diff --git a/DEPS b/DEPS
index 26fdeb04..c2a9faf 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': '11b34d967beff40bb48f013c872fa149ab969d33',
+  'skia_revision': 'b97824d4d1d1b1ae3ab87ec5c122f6da855923ca',
   # 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': 'ca0c97ed52e0f4412cabb6c8199267c3002550c4',
+  'v8_revision': 'e1d02819408cc1a1606b91429482c6b697245cba',
   # 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,11 +150,11 @@
   # 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': '2c49d0b0936aafcfd1a22195698d8158dba5f634',
+  'angle_revision': '08b5629336d0a8a8a97d0482b8df153cbd7a2110',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'bd4cf81fbd5fab203cdd8d70eed20e83a28140e5',
+  'swiftshader_revision': 'ea38f958d07254e3cda97a7347058da130973746',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -201,7 +201,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'ed9fcf3f70a9ea62f2ada913b5289b7cd6a7e74d',
+  'catapult_revision': '9e5dbd8b462b23d989f6ce32ae72fd2a8cb09ee3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -225,11 +225,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_emulator_version
   # and whatever else without interference from each other.
-  'android_sdk_emulator_version': 'ki7EDQRAiZAUYlnTWR1XmI6cJTk65fJ-DNZUU1zrtS8C',
+  'android_sdk_emulator_version': 'xhyuoquVvBTcJelgRjMKZeoBVSQRjB7pLVJPt5C9saIC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_extras_version
   # and whatever else without interference from each other.
-  'android_sdk_extras_version': 'iIwhhDox5E-mHgwUhCz8JACWQCpUjdqt5KTY9VLugKQC',
+  'android_sdk_extras_version': 'ppQ4TnqDvBHQ3lXx5KPq97egzF5X2FFyOrVHkGmiTMQC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_patcher_version
   # and whatever else without interference from each other.
@@ -237,7 +237,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_platform-tools_version
   # and whatever else without interference from each other.
-  'android_sdk_platform-tools_version': '4Y2Cb2LGzoc-qt-oIUIlhySotJaKeE3ELFedSVe6Uk8C',
+  'android_sdk_platform-tools_version': 'MSnxgXN7IurL-MQs1RrTkSFSb8Xd1UtZjLArI8Ty1FgC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_platforms_version
   # and whatever else without interference from each other.
@@ -269,7 +269,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '8fbd7e0b4b044506afd8bab38faae8d7025565cb',
+  'shaderc_revision': '8b2600f715e5f4996718a47925389a0af268c79f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -292,7 +292,7 @@
   # revisions.
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:8c7f49102234f4f4b9349dcb258554675475e596',
+  'gn_version': 'git_revision:81ee1967d3fcbc829bac1c005c3da59739c88df9',
 
   # Also, if you change these, update buildtools/DEPS too. Also update the
   # libc++ svn_revision in //buildtools/deps_revisions.gni.
@@ -807,7 +807,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7fad04d2644250a39ed103221f33c2bc26d2a2ae',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7b8008e2e7e427eed20b92e4711478c0d64749bf',
       'condition': 'checkout_linux',
   },
 
@@ -901,7 +901,7 @@
   },
 
   'src/third_party/glslang/src':
-    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'def9662348b029a6578f7fa9f46fde0e605b3a6c',
+    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '9db72785beb33a89729d801249b23fdda79ae91d',
 
   'src/third_party/google_toolbox_for_mac/src': {
       'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
@@ -1187,7 +1187,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '8ee36813d4ccb4469e215496ade0e4db2e3aa2c0',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'ba0eb777bf5a0b54add3bf54e49cd134130489f3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1383,7 +1383,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/${{platform}}',
-          'version': 'git_revision:5ceacf1dcbfff2a7ed77dbff4400f411e0d7f8b0',
+          'version': 'git_revision:c5ecc324a08216bb365e058acceaf070ce0501c7',
         },
       ],
       'dep_type': 'cipd',
@@ -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@fed21812ada35d6862d53f20ee8b06b8b0f15e1e',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d00e241a16e018aa78317db88f2a236d66bf3653',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 1a3aa9f6..620a6f2 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -950,6 +950,7 @@
   ]
 
   android_manifest_for_lint = system_webview_android_manifest
+  min_sdk_version = 21
 }
 
 android_library("android_webview_variations_utils_java") {
@@ -1088,6 +1089,7 @@
     ":aw_variations_seed_server_aidl",
   ]
   android_manifest_for_lint = system_webview_android_manifest
+  min_sdk_version = 21
 }
 
 android_aidl("crash_receiver_aidl") {
@@ -1110,6 +1112,8 @@
     android_manifest_dep = ":system_webview_manifest"
     deps = upstream_only_webview_deps
     apk_name = "SystemWebView"
+    min_sdk_version = 21
+    target_sdk_version = 28
   }
 
   android_resource_sizes_test("resource_sizes_system_webview_apk") {
diff --git a/android_webview/apk/java/AndroidManifest.xml b/android_webview/apk/java/AndroidManifest.xml
index bca5a6b..e97fd2263 100644
--- a/android_webview/apk/java/AndroidManifest.xml
+++ b/android_webview/apk/java/AndroidManifest.xml
@@ -9,12 +9,6 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="{{manifest_package|default('com.android.webview')}}"
     tools:ignore="MissingLeanbackLauncher">
-    <uses-sdk android:minSdkVersion="{{min_sdk_version|default(21)}}"
-              android:targetSdkVersion="{{target_sdk_version|default(28)}}"
-              {% if max_sdk_version is defined %}
-                android:maxSdkVersion="{{max_sdk_version}}"
-              {% endif %}>
-    </uses-sdk>
 
     <uses-feature android:name="android.hardware.touchscreen"
                   android:required="false" />
diff --git a/android_webview/browser/gfx/aw_vulkan_context_provider.cc b/android_webview/browser/gfx/aw_vulkan_context_provider.cc
index 5057e76..197e31f6 100644
--- a/android_webview/browser/gfx/aw_vulkan_context_provider.cc
+++ b/android_webview/browser/gfx/aw_vulkan_context_provider.cc
@@ -139,7 +139,7 @@
   gfx::ExtensionSet extensions;
   for (uint32_t i = 0; i < params->enabled_device_extension_names_length; ++i)
     extensions.insert(params->enabled_device_extension_names[i]);
-  device_queue_->InitializeForWevbView(
+  device_queue_->InitializeForWebView(
       params->physical_device, params->device, params->queue,
       params->graphics_queue_index, std::move(extensions));
 
diff --git a/android_webview/browser/gfx/parent_output_surface.cc b/android_webview/browser/gfx/parent_output_surface.cc
index 0ebf5df..0291e602 100644
--- a/android_webview/browser/gfx/parent_output_surface.cc
+++ b/android_webview/browser/gfx/parent_output_surface.cc
@@ -92,11 +92,6 @@
   return gl->GetCopyTextureInternalFormat();
 }
 
-std::unique_ptr<viz::OverlayCandidateValidator>
-ParentOutputSurface::TakeOverlayCandidateValidator() {
-  return nullptr;
-}
-
 bool ParentOutputSurface::IsDisplayedAsOverlayPlane() const {
   return false;
 }
diff --git a/android_webview/browser/gfx/parent_output_surface.h b/android_webview/browser/gfx/parent_output_surface.h
index fafa2b3..d496c9df 100644
--- a/android_webview/browser/gfx/parent_output_surface.h
+++ b/android_webview/browser/gfx/parent_output_surface.h
@@ -40,8 +40,6 @@
   bool HasExternalStencilTest() const override;
   void ApplyExternalStencil() override;
   uint32_t GetFramebufferCopyTextureFormat() override;
-  std::unique_ptr<viz::OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() override;
   bool IsDisplayedAsOverlayPlane() const override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
diff --git a/android_webview/glue/BUILD.gn b/android_webview/glue/BUILD.gn
index a1bd319..b57656c8 100644
--- a/android_webview/glue/BUILD.gn
+++ b/android_webview/glue/BUILD.gn
@@ -71,4 +71,5 @@
   ]
 
   android_manifest_for_lint = system_webview_android_manifest
+  min_sdk_version = 21
 }
diff --git a/android_webview/javatests/AndroidManifest.xml b/android_webview/javatests/AndroidManifest.xml
index 5838eae..e15ad16 100644
--- a/android_webview/javatests/AndroidManifest.xml
+++ b/android_webview/javatests/AndroidManifest.xml
@@ -4,7 +4,6 @@
        in the LICENSE file. -->
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.chromium.android_webview.test">
-    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="23" />
     <instrumentation android:name="org.chromium.base.test.BaseChromiumAndroidJUnitRunner"
         android:targetPackage="org.chromium.android_webview.shell"
         android:label="Tests for org.chromium.android_webview"/>
diff --git a/android_webview/proto/aw_variations_seed.proto b/android_webview/proto/aw_variations_seed.proto
index eae71dd..48e053c 100644
--- a/android_webview/proto/aw_variations_seed.proto
+++ b/android_webview/proto/aw_variations_seed.proto
@@ -10,8 +10,9 @@
 option java_package = "org.chromium.android_webview.proto";
 
 // WebView uses AwVariationsSeed to serialize a downloaded seed, along with the
-// required HTTP header metadata, to a file. WebView must save seeds this way
-// because it doesn't persist preferences.
+// required HTTP header metadata, to a file. While Chrome stores the seed in
+// prefs, WebView stores it in a separate file so the WebView service can write
+// new seeds directly to each app's seed file.
 //
 // Next tag: 6
 message AwVariationsSeed {
diff --git a/android_webview/support_library/boundary_interfaces/AndroidManifest.xml b/android_webview/support_library/boundary_interfaces/AndroidManifest.xml
deleted file mode 100644
index abe20e7b..0000000
--- a/android_webview/support_library/boundary_interfaces/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example">
-  <!-- This AndroidManifest file only exists to verify boundary interfaces
-       compile and lint correctly against API 14 (the minSdkVersion of the
-       support library code). As the minSdkVersion of the support library
-       increases, so should this value. See http://crbug.com/828184 for more
-       details. -->
-  <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/android_webview/support_library/boundary_interfaces/BUILD.gn b/android_webview/support_library/boundary_interfaces/BUILD.gn
index 2111854..7cf5f2c 100644
--- a/android_webview/support_library/boundary_interfaces/BUILD.gn
+++ b/android_webview/support_library/boundary_interfaces/BUILD.gn
@@ -40,6 +40,8 @@
   deps = []
 
   # This is to verify the boundary interfaces compile and lint correctly against
-  # the minSdkVersion of the webkit support library module.
-  android_manifest_for_lint = "AndroidManifest.xml"
+  # the minSdkVersion of the webkit support library module. As the minSdkVersion
+  # of the support library increases, so should this value. See
+  # http://crbug.com/828184 for more details.
+  min_sdk_version = 14
 }
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 5a6ea43e..c8205de 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -147,6 +147,7 @@
   apk_name = "WebViewInstrumentationTest"
   apk_under_test = ":webview_instrumentation_apk"
   android_manifest = "../javatests/AndroidManifest.xml"
+  min_sdk_version = 21
   deps = [
     "//android_webview:android_webview_java",
     "//android_webview:android_webview_platform_services_java",
diff --git a/android_webview/test/embedded_test_server/java/AndroidManifest.xml b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
index 81e730775..bf0b2b0f0 100644
--- a/android_webview/test/embedded_test_server/java/AndroidManifest.xml
+++ b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
@@ -8,7 +8,6 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="org.chromium.android_webview.test.support">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
 
diff --git a/android_webview/test/shell/AndroidManifest.xml b/android_webview/test/shell/AndroidManifest.xml
index 5fcaa9b..f15f22d7 100644
--- a/android_webview/test/shell/AndroidManifest.xml
+++ b/android_webview/test/shell/AndroidManifest.xml
@@ -8,7 +8,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.android_webview.shell">
-  <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
diff --git a/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml b/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml
index ea1650d..b2fffba 100644
--- a/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml
+++ b/android_webview/tools/automated_ui_tests/java/AndroidManifest.xml
@@ -10,8 +10,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
-
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/android_webview/tools/automated_ui_tests/javatests/AndroidManifest.xml b/android_webview/tools/automated_ui_tests/javatests/AndroidManifest.xml
index 62426e5..ce89e48 100644
--- a/android_webview/tools/automated_ui_tests/javatests/AndroidManifest.xml
+++ b/android_webview/tools/automated_ui_tests/javatests/AndroidManifest.xml
@@ -8,8 +8,6 @@
       xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.chromium.webview_ui_test.test">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
-
     <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
 
     <!-- We add an application tag here just so that we can indicate that this
diff --git a/android_webview/tools/system_webview_shell/BUILD.gn b/android_webview/tools/system_webview_shell/BUILD.gn
index 593a35e..f02246bd 100644
--- a/android_webview/tools/system_webview_shell/BUILD.gn
+++ b/android_webview/tools/system_webview_shell/BUILD.gn
@@ -32,6 +32,7 @@
     "apk/src/org/chromium/webview_shell/WebViewTracingActivity.java",
   ]
   android_manifest = "apk/AndroidManifest.xml"
+  target_sdk_version = 28
   deps = [
     ":system_webview_shell_apk_resources",
     "//base:base_java",
diff --git a/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml b/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
index 7dc4b34..8d885d98 100644
--- a/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
+++ b/android_webview/tools/system_webview_shell/apk/AndroidManifest.xml
@@ -10,8 +10,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
-
     <!-- "Normal" permissions which do not require user prompt -->
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
diff --git a/android_webview/tools/system_webview_shell/layout_tests/AndroidManifest.xml b/android_webview/tools/system_webview_shell/layout_tests/AndroidManifest.xml
index 1f584e4b5..8147ad1 100644
--- a/android_webview/tools/system_webview_shell/layout_tests/AndroidManifest.xml
+++ b/android_webview/tools/system_webview_shell/layout_tests/AndroidManifest.xml
@@ -11,8 +11,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
-
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/android_webview/tools/system_webview_shell/page_cycler/AndroidManifest.xml b/android_webview/tools/system_webview_shell/page_cycler/AndroidManifest.xml
index 7a79f2e..eb5ca7d 100644
--- a/android_webview/tools/system_webview_shell/page_cycler/AndroidManifest.xml
+++ b/android_webview/tools/system_webview_shell/page_cycler/AndroidManifest.xml
@@ -11,8 +11,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
-
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
diff --git a/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml b/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml
index 63de091..43557a5 100644
--- a/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml
+++ b/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml
@@ -9,8 +9,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
-
     <application
         android:label="WebView Log Verbosifier"
         android:icon="@mipmap/ic_launcher"
diff --git a/android_webview/tools/webview_log_verbosifier/BUILD.gn b/android_webview/tools/webview_log_verbosifier/BUILD.gn
index 772c5b0..aca6466 100644
--- a/android_webview/tools/webview_log_verbosifier/BUILD.gn
+++ b/android_webview/tools/webview_log_verbosifier/BUILD.gn
@@ -10,6 +10,8 @@
   deps = [
     ":webview_log_verbosifier_resources",
   ]
+  min_sdk_version = 21
+  target_sdk_version = 28
 }
 
 android_resources("webview_log_verbosifier_resources") {
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 55864b83..029a1fe 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -1512,9 +1512,7 @@
     return;
 
   if ((action == VOLUME_DOWN || action == VOLUME_UP) &&
-      Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+      Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     if (ShouldSwapSideVolumeButtons(accelerator.source_device_id()))
       action = action == VOLUME_DOWN ? VOLUME_UP : VOLUME_DOWN;
 
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 7598a27..881847d 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1103,7 +1103,7 @@
 
 // Tests the histogram of volume adjustment in tablet mode.
 TEST_F(AcceleratorControllerTest, TabletModeVolumeAdjustHistogram) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::HistogramTester histogram_tester;
   EXPECT_TRUE(
       histogram_tester.GetAllSamples(kTabletCountOfVolumeAdjustType).empty());
@@ -1170,7 +1170,7 @@
 
   void SetUp() override {
     AcceleratorControllerTest::SetUp();
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
     test_api_->SetSideVolumeButtonLocation(region_, side_);
     ui::DeviceDataManagerTestApi().SetUncategorizedDevices({ui::InputDevice(
         kSideVolumeButtonId, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc
index a2d2980c..dd5247d 100644
--- a/ash/accelerators/debug_commands.cc
+++ b/ash/accelerators/debug_commands.cc
@@ -168,8 +168,7 @@
 
 void HandleToggleTabletMode() {
   TabletModeController* controller = Shell::Get()->tablet_mode_controller();
-  controller->EnableTabletModeWindowManager(
-      !controller->IsTabletModeWindowManagerEnabled());
+  controller->SetEnabledForTest(!controller->InTabletMode());
 }
 
 void HandleTriggerCrash() {
diff --git a/ash/accessibility/accessibility_controller.cc b/ash/accessibility/accessibility_controller.cc
index 213c151d..3f2b54407 100644
--- a/ash/accessibility/accessibility_controller.cc
+++ b/ash/accessibility/accessibility_controller.cc
@@ -200,9 +200,7 @@
     text = l10n_util::GetStringUTF16(
         IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED);
   } else {
-    bool is_tablet = Shell::Get()
-                         ->tablet_mode_controller()
-                         ->IsTabletModeWindowManagerEnabled();
+    bool is_tablet = Shell::Get()->tablet_mode_controller()->InTabletMode();
 
     title = l10n_util::GetStringUTF16(
         type == A11yNotificationType::kSpokenFeedbackBrailleEnabled
diff --git a/ash/accessibility/key_accessibility_enabler.cc b/ash/accessibility/key_accessibility_enabler.cc
index 4b8c967..e85f58a 100644
--- a/ash/accessibility/key_accessibility_enabler.cc
+++ b/ash/accessibility/key_accessibility_enabler.cc
@@ -25,9 +25,7 @@
 void KeyAccessibilityEnabler::OnKeyEvent(ui::KeyEvent* event) {
   if ((event->type() != ui::ET_KEY_PRESSED &&
        event->type() != ui::ET_KEY_RELEASED) ||
-      !Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled())
+      !Shell::Get()->tablet_mode_controller()->InTabletMode())
     return;
 
   if (event->key_code() == ui::VKEY_VOLUME_DOWN)
diff --git a/ash/accessibility/key_accessibility_enabler_unittest.cc b/ash/accessibility/key_accessibility_enabler_unittest.cc
index d6f14003..8e7bd27 100644
--- a/ash/accessibility/key_accessibility_enabler_unittest.cc
+++ b/ash/accessibility/key_accessibility_enabler_unittest.cc
@@ -36,7 +36,7 @@
   void SendKeyEvent(ui::KeyEvent* event) {
     // Tablet mode gets exited elsewhere, so we must force it enabled before
     // each key event.
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
     key_accessibility_enabler_->OnKeyEvent(event);
   }
 
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 91cdb9fc..c4ac308 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -67,9 +67,7 @@
 }
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 // Close current Assistant UI.
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc
index 8c9dd74..2d3e93eb 100644
--- a/ash/app_list/app_list_controller_impl_unittest.cc
+++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -41,9 +41,7 @@
 using ::app_list::SearchResultLaunchLocation;
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 app_list::AppListView* GetAppListView() {
@@ -111,7 +109,7 @@
 // (see https://crbug.com/923089).
 TEST_F(AppListControllerImplTest, UpdateExpandArrowViewVisibility) {
   // Turn on the tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(IsTabletMode());
 
   // No activatable windows. So hide the expand arrow view.
@@ -270,7 +268,7 @@
   EXPECT_TRUE(GetVirtualKeyboardWindow()->IsVisible());
 
   // Turn on the tablet mode. The virtual keyboard should still show.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(IsTabletMode());
   EXPECT_TRUE(GetVirtualKeyboardWindow()->IsVisible());
 
@@ -454,7 +452,7 @@
   base::RunLoop().RunUntilIdle();
 
   // Turn on the tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(IsTabletMode());
 
   // Create a window then press the home launcher button. Expect that |w| is
@@ -527,7 +525,7 @@
   base::RunLoop().RunUntilIdle();
 
   // Turn on the tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(IsTabletMode());
 
   // Create a window then press the home launcher button. Expect that |w| is
@@ -554,7 +552,7 @@
   GetAppListView()->OnGestureEvent(&start_event);
 
   // Turn off the tablet mode before scrolling is finished.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(IsTabletMode());
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(AppListViewState::kClosed, GetAppListView()->app_list_state());
diff --git a/ash/app_list/app_list_metrics_unittest.cc b/ash/app_list/app_list_metrics_unittest.cc
index 0d15894a..08ee7b5 100644
--- a/ash/app_list/app_list_metrics_unittest.cc
+++ b/ash/app_list/app_list_metrics_unittest.cc
@@ -394,7 +394,7 @@
 // Test that the histogram records an app launch from the shelf while the
 // homecher all apps state is showing.
 TEST_F(AppListAppLaunchedMetricTest, HomecherAllAppsLaunchFromShelf) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::HistogramTester histogram_tester;
 
   GetAppListTestHelper()->CheckState(ash::AppListViewState::kFullscreenAllApps);
@@ -413,7 +413,7 @@
   base::HistogramTester histogram_tester;
 
   // Enable tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   GetAppListTestHelper()->CheckState(ash::AppListViewState::kFullscreenAllApps);
 
   PopulateAndLaunchAppInGrid();
@@ -431,7 +431,7 @@
 
   GetAppListTestHelper()->WaitUntilIdle();
   // Enable tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   GetAppListTestHelper()->CheckState(ash::AppListViewState::kFullscreenAllApps);
 
   PopulateAndLaunchSuggestionChip();
@@ -449,7 +449,7 @@
 
   // Enable tablet mode.
   GetAppListTestHelper()->WaitUntilIdle();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   // Press a letter key, the AppListView should transition to kFullscreenSearch.
   GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_H, 0);
@@ -471,7 +471,7 @@
 
   // Enable tablet mode.
   GetAppListTestHelper()->WaitUntilIdle();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   // Press a letter key, the AppListView should transition to kFullscreenSearch.
   GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_H, 0);
diff --git a/ash/app_list/app_list_presenter_delegate_impl.cc b/ash/app_list/app_list_presenter_delegate_impl.cc
index 2bb664e8..ec9ae4d 100644
--- a/ash/app_list/app_list_presenter_delegate_impl.cc
+++ b/ash/app_list/app_list_presenter_delegate_impl.cc
@@ -128,9 +128,7 @@
 }
 
 bool AppListPresenterDelegateImpl::IsTabletMode() const {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 app_list::AppListViewDelegate*
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index ede47e9..e3a7acb 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -84,7 +84,7 @@
   // again at the end of |TabletModeController::TabletModeController|.
   base::RunLoop().RunUntilIdle();
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(enable);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
 
   // The app list will be shown automatically when tablet mode is enabled (Home
   // launcher flag is enabled). Wait here for the animation complete.
diff --git a/ash/app_list/views/assistant/assistant_main_stage.cc b/ash/app_list/views/assistant/assistant_main_stage.cc
index 142fb5fe..5254b6a 100644
--- a/ash/app_list/views/assistant/assistant_main_stage.cc
+++ b/ash/app_list/views/assistant/assistant_main_stage.cc
@@ -9,6 +9,7 @@
 #include "ash/assistant/model/assistant_query.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
+#include "ash/assistant/ui/base/stack_layout.h"
 #include "ash/assistant/ui/main_stage/assistant_footer_view.h"
 #include "ash/assistant/ui/main_stage/assistant_progress_indicator.h"
 #include "ash/assistant/ui/main_stage/assistant_query_view.h"
@@ -69,118 +70,6 @@
 constexpr base::TimeDelta kGreetingAnimationFadeOutDuration =
     base::TimeDelta::FromMilliseconds(83);
 
-// StackLayout -----------------------------------------------------------------
-// TODO(wutao): Move an implementation of StackLayout to ash/assistant/ui/base
-// so that it can be reused across standalone and embedded Assistant
-// implementations.
-
-// A layout manager which lays out its views atop each other. This differs from
-// FillLayout in that we respect the preferred size of views during layout. It's
-// possible to explicitly specify which dimension to respect. In contrast,
-// FillLayout will cause its views to match the bounds of the host.
-class StackLayout : public views::LayoutManager {
- public:
-  enum class RespectDimension : uint32_t {
-    // Respect width. If enabled, child's preferred width will be used and will
-    // be horizontally center positioned. Otherwise, the child will be stretched
-    // to match parent width.
-    kWidth = 1,
-    // Respect height. If enabled, child's preferred height will be used.
-    // Otherwise, the child will be stretched to match parent height.
-    // Note that the child is always top-aligned.
-    kHeight = 1 << 1,
-    kAll = kWidth | kHeight,
-  };
-
-  enum class VerticalAlignment {
-    kCenter = 1,
-  };
-
-  StackLayout() = default;
-  ~StackLayout() override = default;
-
-  void Installed(views::View* host) override { host_ = host; }
-
-  void ViewRemoved(views::View* host, views::View* view) override {
-    DCHECK(view);
-    respect_dimension_map_.erase(view);
-    vertical_alignment_map_.erase(view);
-  }
-
-  void SetRespectDimensionForView(views::View* view,
-                                  RespectDimension dimension) {
-    DCHECK(host_ && view->parent() == host_);
-    respect_dimension_map_[view] = dimension;
-  }
-
-  void SetVerticalAlignmentForView(views::View* view,
-                                   VerticalAlignment alignment) {
-    DCHECK(host_ && view->parent() == host_);
-    vertical_alignment_map_[view] = alignment;
-  }
-
-  gfx::Size GetPreferredSize(const views::View* host) const override {
-    return std::accumulate(host->children().cbegin(), host->children().cend(),
-                           gfx::Size(), [](gfx::Size size, const auto* v) {
-                             size.SetToMax(v->GetPreferredSize());
-                             return size;
-                           });
-  }
-
-  int GetPreferredHeightForWidth(const views::View* host,
-                                 int width) const override {
-    const auto& children = host->children();
-    if (children.empty())
-      return 0;
-    std::vector<int> heights(children.size());
-    std::transform(
-        children.cbegin(), children.cend(), heights.begin(),
-        [width](const views::View* v) { return v->GetHeightForWidth(width); });
-    return *std::max_element(heights.cbegin(), heights.cend());
-  }
-
-  void Layout(views::View* host) override {
-    const int host_width = host->GetContentsBounds().width();
-    const int host_height = host->GetContentsBounds().height();
-
-    for (auto* child : host->children()) {
-      int child_width = host_width;
-      int child_height = host_height;
-
-      int child_x = 0;
-      uint32_t dimension = static_cast<uint32_t>(RespectDimension::kAll);
-
-      if (respect_dimension_map_.find(child) != respect_dimension_map_.end())
-        dimension = static_cast<uint32_t>(respect_dimension_map_[child]);
-
-      if (dimension & static_cast<uint32_t>(RespectDimension::kWidth)) {
-        child_width = std::min(child->GetPreferredSize().width(), host_width);
-        child_x = (host_width - child_width) / 2;
-      }
-
-      if (dimension & static_cast<uint32_t>(RespectDimension::kHeight))
-        child_height = child->GetHeightForWidth(child_width);
-
-      int child_y = 0;
-      auto iter = vertical_alignment_map_.find(child);
-      if (iter != vertical_alignment_map_.end()) {
-        VerticalAlignment vertical_alignment = iter->second;
-        if (vertical_alignment == VerticalAlignment::kCenter)
-          child_y = std::max(0, (host_height - child_height) / 2);
-      }
-
-      child->SetBounds(child_x, child_y, child_width, child_height);
-    }
-  }
-
- private:
-  views::View* host_ = nullptr;
-  std::map<views::View*, RespectDimension> respect_dimension_map_;
-  std::map<views::View*, VerticalAlignment> vertical_alignment_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(StackLayout);
-};
-
 // HorizontalSeparator ---------------------------------------------------------
 
 // A horizontal line to separate the dialog plate.
@@ -292,15 +181,15 @@
   InitGreetingLabel();
   content_layout_container->AddChildView(greeting_label_);
   auto* stack_layout = content_layout_container->SetLayoutManager(
-      std::make_unique<StackLayout>());
+      std::make_unique<ash::StackLayout>());
 
   // We need to stretch |greeting_label_| to match its parent so that it
   // won't use heuristics in Label to infer line breaking, which seems to cause
   // text clipping with DPI adjustment. See b/112843496.
   stack_layout->SetRespectDimensionForView(
-      greeting_label_, StackLayout::RespectDimension::kHeight);
+      greeting_label_, ash::StackLayout::RespectDimension::kHeight);
   stack_layout->SetVerticalAlignmentForView(
-      greeting_label_, StackLayout::VerticalAlignment::kCenter);
+      greeting_label_, ash::StackLayout::VerticalAlignment::kCenter);
 
   auto* main_content_layout_container = CreateMainContentLayoutContainer();
   content_layout_container->AddChildView(main_content_layout_container);
@@ -308,7 +197,8 @@
   // Do not respect height, otherwise bounds will not be set correctly for
   // scrolling.
   stack_layout->SetRespectDimensionForView(
-      main_content_layout_container, StackLayout::RespectDimension::kWidth);
+      main_content_layout_container,
+      ash::StackLayout::RespectDimension::kWidth);
 
   return content_layout_container;
 }
@@ -363,7 +253,7 @@
   // Dividers: the progress indicator and the horizontal separator will be the
   // separator when querying and showing the results, respectively.
   views::View* divider_container = new views::View();
-  divider_container->SetLayoutManager(std::make_unique<StackLayout>());
+  divider_container->SetLayoutManager(std::make_unique<ash::StackLayout>());
 
   // Progress indicator, which will be animated on its own layer.
   progress_indicator_ = new ash::AssistantProgressIndicator();
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc
index b42d61d3..9cb18f7 100644
--- a/ash/assistant/assistant_interaction_controller.cc
+++ b/ash/assistant/assistant_interaction_controller.cc
@@ -45,9 +45,7 @@
 
 // Returns true if device is in tablet mode, false otherwise.
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 }  // namespace
diff --git a/ash/assistant/assistant_view_delegate_impl.cc b/ash/assistant/assistant_view_delegate_impl.cc
index a264a4a..7d21ef5 100644
--- a/ash/assistant/assistant_view_delegate_impl.cc
+++ b/ash/assistant/assistant_view_delegate_impl.cc
@@ -134,9 +134,7 @@
 }
 
 bool AssistantViewDelegateImpl::IsTabletMode() const {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 void AssistantViewDelegateImpl::OnDialogPlateButtonPressed(
diff --git a/ash/assistant/ui/BUILD.gn b/ash/assistant/ui/BUILD.gn
index 72483f9..247afa9d 100644
--- a/ash/assistant/ui/BUILD.gn
+++ b/ash/assistant/ui/BUILD.gn
@@ -56,6 +56,8 @@
     "base/assistant_button.h",
     "base/assistant_scroll_view.cc",
     "base/assistant_scroll_view.h",
+    "base/stack_layout.cc",
+    "base/stack_layout.h",
     "caption_bar.cc",
     "caption_bar.h",
     "dialog_plate/dialog_plate.cc",
diff --git a/ash/assistant/ui/base/stack_layout.cc b/ash/assistant/ui/base/stack_layout.cc
new file mode 100644
index 0000000..a366269
--- /dev/null
+++ b/ash/assistant/ui/base/stack_layout.cc
@@ -0,0 +1,93 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/assistant/ui/base/stack_layout.h"
+
+#include <numeric>
+
+#include "ui/views/view.h"
+
+namespace ash {
+
+StackLayout::StackLayout() = default;
+
+StackLayout::~StackLayout() = default;
+
+void StackLayout::Installed(views::View* host) {
+  host_ = host;
+}
+
+void StackLayout::ViewRemoved(views::View* host, views::View* view) {
+  DCHECK(view);
+  respect_dimension_map_.erase(view);
+  vertical_alignment_map_.erase(view);
+}
+
+gfx::Size StackLayout::GetPreferredSize(const views::View* host) const {
+  return std::accumulate(host->children().cbegin(), host->children().cend(),
+                         gfx::Size(), [](gfx::Size size, const auto* v) {
+                           size.SetToMax(v->GetPreferredSize());
+                           return size;
+                         });
+}
+
+int StackLayout::GetPreferredHeightForWidth(const views::View* host,
+                                            int width) const {
+  const auto& children = host->children();
+  if (children.empty())
+    return 0;
+  std::vector<int> heights(children.size());
+  std::transform(
+      children.cbegin(), children.cend(), heights.begin(),
+      [width](const views::View* v) { return v->GetHeightForWidth(width); });
+  return *std::max_element(heights.cbegin(), heights.cend());
+}
+
+void StackLayout::Layout(views::View* host) {
+  const int host_width = host->GetContentsBounds().width();
+  const int host_height = host->GetContentsBounds().height();
+
+  for (auto* child : host->children()) {
+    int child_width = host_width;
+    int child_height = host_height;
+
+    int child_x = 0;
+    uint32_t dimension = static_cast<uint32_t>(RespectDimension::kAll);
+
+    if (respect_dimension_map_.find(child) != respect_dimension_map_.end())
+      dimension = static_cast<uint32_t>(respect_dimension_map_[child]);
+
+    if (dimension & static_cast<uint32_t>(RespectDimension::kWidth)) {
+      child_width = std::min(child->GetPreferredSize().width(), host_width);
+      child_x = (host_width - child_width) / 2;
+    }
+
+    if (dimension & static_cast<uint32_t>(RespectDimension::kHeight))
+      child_height = child->GetHeightForWidth(child_width);
+
+    int child_y = 0;
+    auto iter = vertical_alignment_map_.find(child);
+    if (iter != vertical_alignment_map_.end()) {
+      VerticalAlignment vertical_alignment = iter->second;
+      if (vertical_alignment == VerticalAlignment::kCenter)
+        child_y = std::max(0, (host_height - child_height) / 2);
+    }
+
+    child->SetBounds(child_x, child_y, child_width, child_height);
+  }
+}
+
+void StackLayout::SetRespectDimensionForView(views::View* view,
+                                             RespectDimension dimension) {
+  DCHECK(host_ && view->parent() == host_);
+  respect_dimension_map_[view] = dimension;
+}
+
+void StackLayout::SetVerticalAlignmentForView(views::View* view,
+                                              VerticalAlignment alignment) {
+  DCHECK(host_ && view->parent() == host_);
+  vertical_alignment_map_[view] = alignment;
+}
+
+}  // namespace ash
diff --git a/ash/assistant/ui/base/stack_layout.h b/ash/assistant/ui/base/stack_layout.h
new file mode 100644
index 0000000..13f4ffdd
--- /dev/null
+++ b/ash/assistant/ui/base/stack_layout.h
@@ -0,0 +1,67 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_ASSISTANT_UI_BASE_STACK_LAYOUT_H_
+#define ASH_ASSISTANT_UI_BASE_STACK_LAYOUT_H_
+
+#include <map>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "ui/views/layout/layout_manager.h"
+
+namespace ash {
+
+// A layout manager which lays out its views atop each other. This differs from
+// FillLayout in that we respect the preferred size of views during layout. It's
+// possible to explicitly specify which dimension to respect. In contrast,
+// FillLayout will cause its views to match the bounds of the host.
+class COMPONENT_EXPORT(ASSISTANT_UI) StackLayout : public views::LayoutManager {
+ public:
+  enum class RespectDimension : uint32_t {
+    // Respect width. If enabled, child's preferred width will be used and will
+    // be horizontally center positioned. Otherwise, the child will be stretched
+    // to match parent width.
+    kWidth = 1,
+    // Respect height. If enabled, child's preferred height will be used.
+    // Otherwise, the child will be stretched to match parent height.
+    // Note that the child is always top-aligned.
+    kHeight = 1 << 1,
+    kAll = kWidth | kHeight,
+  };
+
+  enum class VerticalAlignment {
+    kCenter = 1,
+  };
+
+  StackLayout();
+  ~StackLayout() override;
+
+  // views::LayoutManager:
+  void Installed(views::View* host) override;
+  void ViewRemoved(views::View* host, views::View* view) override;
+
+  // views::View:
+  gfx::Size GetPreferredSize(const views::View* host) const override;
+  int GetPreferredHeightForWidth(const views::View* host,
+                                 int width) const override;
+  void Layout(views::View* host) override;
+
+  void SetRespectDimensionForView(views::View* view,
+                                  RespectDimension dimension);
+
+  void SetVerticalAlignmentForView(views::View* view,
+                                   VerticalAlignment alignment);
+
+ private:
+  views::View* host_ = nullptr;
+  std::map<views::View*, RespectDimension> respect_dimension_map_;
+  std::map<views::View*, VerticalAlignment> vertical_alignment_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackLayout);
+};
+
+}  // namespace ash
+
+#endif  // ASH_ASSISTANT_UI_BASE_STACK_LAYOUT_H_
diff --git a/ash/assistant/ui/main_stage/assistant_main_stage.cc b/ash/assistant/ui/main_stage/assistant_main_stage.cc
index d6be1c5..22a1fc8 100644
--- a/ash/assistant/ui/main_stage/assistant_main_stage.cc
+++ b/ash/assistant/ui/main_stage/assistant_main_stage.cc
@@ -11,6 +11,7 @@
 #include "ash/assistant/model/assistant_query.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
+#include "ash/assistant/ui/base/stack_layout.h"
 #include "ash/assistant/ui/main_stage/assistant_footer_view.h"
 #include "ash/assistant/ui/main_stage/assistant_header_view.h"
 #include "ash/assistant/ui/main_stage/assistant_progress_indicator.h"
@@ -101,95 +102,6 @@
 constexpr base::TimeDelta kProgressAnimationFadeOutDuration =
     base::TimeDelta::FromMilliseconds(83);
 
-// StackLayout -----------------------------------------------------------------
-
-// A layout manager which lays out its views atop each other. This differs from
-// FillLayout in that we respect the preferred size of views during layout. It's
-// possible to explicitly specify which dimension to respect. In contrast,
-// FillLayout will cause its views to match the bounds of the host.
-class StackLayout : public views::LayoutManager {
- public:
-  enum class RespectDimension : uint32_t {
-    // Respect width. If enabled, child's preferred width will be used and will
-    // be horizontally center positioned. Otherwise, the child will be stretched
-    // to match parent width.
-    kWidth = 1,
-    // Repect height. If enabled, child's preferred height will be used.
-    // Otherwise, the child will be stretched to match parent height.
-    // Note that the child is always top-aligned.
-    kHeight = 1 << 1,
-    kAll = kWidth | kHeight,
-  };
-
-  StackLayout() = default;
-  ~StackLayout() override = default;
-
-  void Installed(views::View* host) override { host_ = host; }
-
-  void ViewRemoved(views::View* host, views::View* view) override {
-    DCHECK(view);
-    respect_dimension_map_.erase(view);
-  }
-
-  void SetRespectDimensionForView(views::View* view,
-                                  RespectDimension dimension) {
-    DCHECK(host_ && view->parent() == host_);
-    respect_dimension_map_[view] = dimension;
-  }
-
-  gfx::Size GetPreferredSize(const views::View* host) const override {
-    return std::accumulate(host->children().cbegin(), host->children().cend(),
-                           gfx::Size(), [](gfx::Size size, const auto* v) {
-                             size.SetToMax(v->GetPreferredSize());
-                             return size;
-                           });
-  }
-
-  int GetPreferredHeightForWidth(const views::View* host,
-                                 int width) const override {
-    const auto& children = host->children();
-    if (children.empty())
-      return 0;
-    std::vector<int> heights(children.size());
-    std::transform(
-        children.cbegin(), children.cend(), heights.begin(),
-        [width](const views::View* v) { return v->GetHeightForWidth(width); });
-    return *std::max_element(heights.cbegin(), heights.cend());
-  }
-
-  void Layout(views::View* host) override {
-    const int host_width = host->GetContentsBounds().width();
-    const int host_height = host->GetContentsBounds().height();
-
-    for (auto* child : host->children()) {
-      int child_width = host_width;
-      int child_height = host_height;
-
-      int child_x = 0;
-      uint32_t dimension = static_cast<uint32_t>(RespectDimension::kAll);
-
-      if (respect_dimension_map_.find(child) != respect_dimension_map_.end())
-        dimension = static_cast<uint32_t>(respect_dimension_map_[child]);
-
-      if (dimension & static_cast<uint32_t>(RespectDimension::kWidth)) {
-        child_width = std::min(child->GetPreferredSize().width(), host_width);
-        child_x = (host_width - child_width) / 2;
-      }
-
-      if (dimension & static_cast<uint32_t>(RespectDimension::kHeight))
-        child_height = child->GetHeightForWidth(child_width);
-
-      child->SetBounds(child_x, /*y=*/0, child_width, child_height);
-    }
-  }
-
- private:
-  views::View* host_ = nullptr;
-  std::map<views::View*, RespectDimension> respect_dimension_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(StackLayout);
-};
-
 }  // namespace
 
 // AssistantMainStage ----------------------------------------------------------
diff --git a/ash/display/cros_display_config.cc b/ash/display/cros_display_config.cc
index 4217404..98015d5 100644
--- a/ash/display/cros_display_config.cc
+++ b/ash/display/cros_display_config.cc
@@ -259,10 +259,8 @@
   bool has_accelerometer_support =
       display.accelerometer_support() ==
       display::Display::AccelerometerSupport::AVAILABLE;
-  info->is_tablet_mode =
-      has_accelerometer_support && Shell::Get()
-                                       ->tablet_mode_controller()
-                                       ->IsTabletModeWindowManagerEnabled();
+  info->is_tablet_mode = has_accelerometer_support &&
+                         Shell::Get()->tablet_mode_controller()->InTabletMode();
   info->has_touch_support =
       display.touch_support() == display::Display::TouchSupport::AVAILABLE;
   info->has_accelerometer_support = has_accelerometer_support;
@@ -662,9 +660,7 @@
   if (properties->rotation) {
     display::Display::Rotation rotation =
         display::Display::Rotation(properties->rotation->rotation);
-    if (Shell::Get()
-            ->tablet_mode_controller()
-            ->IsTabletModeWindowManagerEnabled() &&
+    if (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
         display.id() == display::Display::InternalDisplayId()) {
       Shell::Get()->screen_orientation_controller()->SetLockToRotation(
           rotation);
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index abce6ed4..aa12170 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -3014,7 +3014,7 @@
 
   // Turn on tablet mode, expect that we switch to mirror mode without any
   // crashes.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
 
@@ -3023,18 +3023,18 @@
   // asynchronously.
   auto* app_list_controller = Shell::Get()->app_list_controller();
   auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
-  EXPECT_TRUE(tablet_mode_controller->IsTabletModeWindowManagerEnabled());
+  EXPECT_TRUE(tablet_mode_controller->InTabletMode());
   EXPECT_TRUE(app_list_controller->IsVisible());
 
   // Exiting tablet mode should exit mirror mode and return back to Unified
   // mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(display_manager()->IsInSoftwareMirrorMode());
   EXPECT_TRUE(display_manager()->IsInUnifiedMode());
 
   // Home Launcher should be dismissed.
-  EXPECT_FALSE(tablet_mode_controller->IsTabletModeWindowManagerEnabled());
+  EXPECT_FALSE(tablet_mode_controller->InTabletMode());
   EXPECT_FALSE(app_list_controller->IsVisible());
 }
 
@@ -3055,7 +3055,7 @@
 
   // Turn on tablet mode, and expect that it's not possible to persist the
   // display prefs while forced mirror mode is active.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
   EXPECT_TRUE(
@@ -3066,7 +3066,7 @@
   EXPECT_TRUE(display_manager()->external_display_mirror_info().empty());
 
   // Exit tablet mode and expect everything is back to normal.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(display_manager()->IsInSoftwareMirrorMode());
   EXPECT_FALSE(
@@ -3616,7 +3616,7 @@
 
   EXPECT_EQ(0, test_observer.countAndReset());
   // Just enabling will not save the lock.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(1, test_observer.countAndReset());
 
   EXPECT_EQ(display::Display::ROTATE_0, screen->GetPrimaryDisplay().rotation());
@@ -3658,13 +3658,13 @@
   EXPECT_EQ(0, test_observer.countAndReset());
 
   // Exit tablet mode reset to clamshell's rotation, which is 90.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(1, test_observer.countAndReset());
   EXPECT_EQ(display::Display::ROTATE_270,
             screen->GetPrimaryDisplay().rotation());
   // Activate Any.
   wm::ActivateWindow(window_a);
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(1, test_observer.countAndReset());
   // Entering with active ANY will lock again to landscape.
   EXPECT_EQ(display::Display::ROTATE_0, screen->GetPrimaryDisplay().rotation());
@@ -3709,7 +3709,7 @@
   display::Screen* screen = display::Screen::GetScreen();
 
   // Just enabling will not save the lock.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   orientation_controller->LockOrientationForWindow(
       window, OrientationLockType::kPortrait);
@@ -3754,7 +3754,7 @@
                                                      OrientationLockType::kAny);
   }
   wm::ActivateWindow(window_a);
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   orientation_controller->OnAccelerometerUpdated(portrait_primary);
 
@@ -3821,7 +3821,7 @@
   test_api.SetFirstDisplayAsInternalDisplay();
   display::Screen* screen = display::Screen::GetScreen();
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   // Emulate that Animator is calling this async when animation is completed.
   display_manager->SetDisplayRotation(
       screen->GetPrimaryDisplay().id(), display::Display::ROTATE_90,
@@ -3829,7 +3829,7 @@
   EXPECT_EQ(display::Display::ROTATE_90,
             screen->GetPrimaryDisplay().rotation());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(display::Display::ROTATE_0, screen->GetPrimaryDisplay().rotation());
 }
 
@@ -4375,7 +4375,7 @@
       .SetFirstDisplayAsInternalDisplay();
 
   // Simulate turning on mirror mode triggered by tablet mode on.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
   EXPECT_EQ(gfx::Rect(0, 0, 400, 300),
diff --git a/ash/display/display_prefs_unittest.cc b/ash/display/display_prefs_unittest.cc
index efe4a05..b20754b 100644
--- a/ash/display/display_prefs_unittest.cc
+++ b/ash/display/display_prefs_unittest.cc
@@ -862,7 +862,7 @@
   ash::TabletModeController* controller =
       ash::Shell::Get()->tablet_mode_controller();
   controller->OnAccelerometerUpdated(update);
-  EXPECT_TRUE(controller->IsTabletModeWindowManagerEnabled());
+  EXPECT_TRUE(controller->InTabletMode());
 
   // Trigger 90 degree rotation
   update->Set(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, false,
@@ -1011,7 +1011,7 @@
   ash::TabletModeController* tablet_mode_controller =
       ash::Shell::Get()->tablet_mode_controller();
   tablet_mode_controller->OnAccelerometerUpdated(update);
-  EXPECT_TRUE(tablet_mode_controller->IsTabletModeWindowManagerEnabled());
+  EXPECT_TRUE(tablet_mode_controller->InTabletMode());
   bool screen_orientation_rotation_lock = IsRotationLocked();
   display::Display::Rotation tablet_mode_rotation =
       GetCurrentInternalDisplayRotation();
diff --git a/ash/display/screen_orientation_controller.cc b/ash/display/screen_orientation_controller.cc
index 0431dd1..be0a3ae 100644
--- a/ash/display/screen_orientation_controller.cc
+++ b/ash/display/screen_orientation_controller.cc
@@ -277,9 +277,7 @@
 }
 
 bool ScreenOrientationController::ScreenOrientationProviderSupported() const {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 bool ScreenOrientationController::IsUserLockedOrientationPortrait() {
diff --git a/ash/display/screen_orientation_controller_unittest.cc b/ash/display/screen_orientation_controller_unittest.cc
index 844ce6f..cebce12 100644
--- a/ash/display/screen_orientation_controller_unittest.cc
+++ b/ash/display/screen_orientation_controller_unittest.cc
@@ -53,7 +53,7 @@
 }
 
 void EnableTabletMode(bool enable) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(enable);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
 }
 
 bool RotationLocked() {
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
index 952bb36..4b90f9d 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -175,7 +175,7 @@
             initial_size_button_bounds.right());
 
   // Button positions should be the same when entering tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   container.UpdateCaptionButtonState(false /*=animate*/);
   test.EndAnimations();
   // Parent needs to layout in response to size change.
@@ -197,7 +197,7 @@
             initial_container_bounds.width());
 
   // Button positions should be the same when leaving tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   container.UpdateCaptionButtonState(false /*=animate*/);
   // Calling code needs to layout in response to size change.
   container.Layout();
diff --git a/ash/frame/non_client_frame_view_ash_unittest.cc b/ash/frame/non_client_frame_view_ash_unittest.cc
index b5c8b9d..6cccde5 100644
--- a/ash/frame/non_client_frame_view_ash_unittest.cc
+++ b/ash/frame/non_client_frame_view_ash_unittest.cc
@@ -284,8 +284,8 @@
   widget->Minimize();
 
   // Enter and exit tablet mode while the window is minimized.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
 
   // When unminimizing in non-tablet mode, size button should match with
   // maximized window state, which is restore icon.
@@ -303,7 +303,7 @@
   std::unique_ptr<views::Widget> widget = CreateTestWidget(delegate);
   widget->Maximize();
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(0, delegate->GetNonClientFrameViewTopBorderHeight());
 }
 
@@ -314,7 +314,7 @@
   auto* delegate = new NonClientFrameViewAshTestWidgetDelegate();
   std::unique_ptr<views::Widget> widget = CreateTestWidget(delegate);
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(views::GetCaptionButtonLayoutSize(
                 views::CaptionButtonLayoutSize::kNonBrowserCaption)
                 .height(),
@@ -331,9 +331,9 @@
 
   widget->SetFullscreen(true);
   EXPECT_EQ(0, delegate->GetNonClientFrameViewTopBorderHeight());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(0, delegate->GetNonClientFrameViewTopBorderHeight());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(0, delegate->GetNonClientFrameViewTopBorderHeight());
 }
 
@@ -342,7 +342,7 @@
   std::unique_ptr<views::Widget> widget = CreateTestWidget(delegate);
   widget->Maximize();
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(0, delegate->GetNonClientFrameViewTopBorderHeight());
 
   // Verify that after minimizing and showing the widget, the height of the
@@ -359,7 +359,7 @@
   wm::GetWindowState(widget->GetNativeWindow())->OnWMEvent(&event);
   EXPECT_EQ(0, delegate->GetNonClientFrameViewTopBorderHeight());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(views::GetCaptionButtonLayoutSize(
                 views::CaptionButtonLayoutSize::kNonBrowserCaption)
                 .height(),
@@ -369,7 +369,7 @@
 // Test if creating a new window in tablet mode uses maximzied state
 // and immersive mode.
 TEST_F(NonClientFrameViewAshTest, GetPreferredOnScreenHeightInTabletMaximzied) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   auto* delegate = new TestWidgetConstraintsDelegate;
   std::unique_ptr<views::Widget> widget = CreateTestWidget(delegate);
@@ -397,7 +397,7 @@
       aura::client::kResizeBehaviorCanMaximize);
   widget->Maximize();
   widget->Minimize();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   widget->Show();
   EXPECT_EQ(widget->non_client_view()->bounds(),
@@ -435,7 +435,7 @@
   auto* delegate2 = new NonClientFrameViewAshTestWidgetDelegate();
   auto widget2 = create_widget(delegate2);
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   // Verify that when one window is snapped, the header is drawn for the snapped
   // window, but not drawn for the window still in overview.
diff --git a/ash/home_screen/home_launcher_gesture_handler.cc b/ash/home_screen/home_launcher_gesture_handler.cc
index 7da5ae7..41bd23ed 100644
--- a/ash/home_screen/home_launcher_gesture_handler.cc
+++ b/ash/home_screen/home_launcher_gesture_handler.cc
@@ -59,9 +59,7 @@
 constexpr float kWidthRatio = 0.8f;
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 // Checks if |window| can be hidden or shown with a gesture.
diff --git a/ash/home_screen/home_launcher_gesture_handler_unittest.cc b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
index f449e06..4644b9b 100644
--- a/ash/home_screen/home_launcher_gesture_handler_unittest.cc
+++ b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
@@ -39,7 +39,7 @@
     // Wait for TabletModeController::Ctor to finish.
     base::RunLoop().RunUntilIdle();
 
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   }
 
   // Create a test window and set the base transform to identity and
@@ -578,7 +578,7 @@
 
   // Tests that on exiting tablet mode, |window| gets minimized and is no longer
   // tracked by the gesture handler.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(GetGestureHandler()->GetActiveWindow());
   EXPECT_TRUE(wm::GetWindowState(window.get())->IsMinimized());
 }
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc
index 20ae1c2..d77b28c3 100644
--- a/ash/home_screen/home_screen_controller.cc
+++ b/ash/home_screen/home_screen_controller.cc
@@ -59,9 +59,7 @@
 }
 
 bool HomeScreenController::IsHomeScreenAvailable() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 void HomeScreenController::Show() {
diff --git a/ash/home_screen/home_screen_controller_unittest.cc b/ash/home_screen/home_screen_controller_unittest.cc
index da989f66..7f84229 100644
--- a/ash/home_screen/home_screen_controller_unittest.cc
+++ b/ash/home_screen/home_screen_controller_unittest.cc
@@ -41,7 +41,7 @@
   std::unique_ptr<aura::Window> w1(CreateTestWindow());
   std::unique_ptr<aura::Window> w2(CreatePopupTestWindow());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   std::unique_ptr<ui::Event> test_event = std::make_unique<ui::KeyEvent>(
       ui::EventType::ET_MOUSE_PRESSED, ui::VKEY_UNKNOWN, ui::EF_NONE);
   home_screen_controller()->GoHome(GetPrimaryDisplay().id());
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index 17de4d12..25deb8c 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -78,7 +78,7 @@
 // cause the Virtual Keyboard Controller to crash. See crbug.com/446204.
 TEST_F(VirtualKeyboardControllerTest, RestoreKeyboardDevices) {
   // Toggle tablet mode on.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   std::unique_ptr<InternalInputDevicesEventBlocker> blocker(
       new MockEventBlocker);
   TabletModeControllerTestApi().set_event_blocker(std::move(blocker));
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 62d5ddf..f5b81f3 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -210,9 +210,7 @@
 }
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 //
diff --git a/ash/login/ui/parent_access_view.cc b/ash/login/ui/parent_access_view.cc
index f767df9..f72c434 100644
--- a/ash/login/ui/parent_access_view.cc
+++ b/ash/login/ui/parent_access_view.cc
@@ -89,9 +89,7 @@
 constexpr SkColor kArrowButtonColor = SkColorSetARGB(0x57, 0xFF, 0xFF, 0xFF);
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 gfx::Size GetPinKeyboardToFooterSpacerSize() {
diff --git a/ash/login/ui/parent_access_view_unittest.cc b/ash/login/ui/parent_access_view_unittest.cc
index 7ced1eab..c1b496f 100644
--- a/ash/login/ui/parent_access_view_unittest.cc
+++ b/ash/login/ui/parent_access_view_unittest.cc
@@ -267,7 +267,7 @@
 // Tests input with virtual pin keyboard.
 TEST_F(ParentAccessViewTest, PinKeyboard) {
   StartView();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   ParentAccessView::TestApi test_api(view_);
   LoginPinView::TestApi test_pin_keyboard(test_api.pin_keyboard_view());
@@ -293,10 +293,10 @@
   LoginPinView::TestApi test_pin_keyboard(test_api.pin_keyboard_view());
   EXPECT_FALSE(test_api.pin_keyboard_view()->GetVisible());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(test_api.pin_keyboard_view()->GetVisible());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(test_api.pin_keyboard_view()->GetVisible());
 }
 
diff --git a/ash/magnifier/docked_magnifier_controller_impl_unittest.cc b/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
index e307e6a0..8f3e63a 100644
--- a/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
+++ b/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
@@ -350,10 +350,8 @@
 // snapped and the other snap region is hosting overview mode.
 TEST_F(DockedMagnifierTest, DisplaysWorkAreasSingleSplitView) {
   // Verify that we're in tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  EXPECT_TRUE(Shell::Get()
-                  ->tablet_mode_controller()
-                  ->IsTabletModeWindowManagerEnabled());
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  EXPECT_TRUE(Shell::Get()->tablet_mode_controller()->InTabletMode());
 
   std::unique_ptr<aura::Window> window(
       CreateTestWindowInShell(SK_ColorWHITE, 100, gfx::Rect(0, 0, 200, 200)));
@@ -394,10 +392,8 @@
 // when we enable the docked magnifier, but rather their bounds are updated.
 TEST_F(DockedMagnifierTest, DisplaysWorkAreasDoubleSplitView) {
   // Verify that we're in tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  EXPECT_TRUE(Shell::Get()
-                  ->tablet_mode_controller()
-                  ->IsTabletModeWindowManagerEnabled());
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  EXPECT_TRUE(Shell::Get()->tablet_mode_controller()->InTabletMode());
 
   std::unique_ptr<aura::Window> window1(
       CreateTestWindowInShell(SK_ColorWHITE, 100, gfx::Rect(0, 0, 200, 200)));
diff --git a/ash/metrics/histogram_macros.cc b/ash/metrics/histogram_macros.cc
index f029b20..1fc303c 100644
--- a/ash/metrics/histogram_macros.cc
+++ b/ash/metrics/histogram_macros.cc
@@ -9,10 +9,10 @@
 
 namespace ash {
 
-bool IsInTabletMode() {
+bool InTabletMode() {
   auto* shell = Shell::Get();
   return shell && shell->tablet_mode_controller() &&
-         shell->tablet_mode_controller()->IsTabletModeWindowManagerEnabled();
+         shell->tablet_mode_controller()->InTabletMode();
 }
 
 bool IsInSplitView() {
diff --git a/ash/metrics/histogram_macros.h b/ash/metrics/histogram_macros.h
index ab6a8ee..c83ab6e 100644
--- a/ash/metrics/histogram_macros.h
+++ b/ash/metrics/histogram_macros.h
@@ -15,7 +15,7 @@
 
 #define UMA_HISTOGRAM_PERCENTAGE_IN_TABLET(name, ...) \
   do {                                                \
-    if (ash::IsInTabletMode())                        \
+    if (ash::InTabletMode())                          \
       UMA_HISTOGRAM_PERCENTAGE(name, __VA_ARGS__);    \
   } while (0)
 
@@ -27,19 +27,19 @@
 
 #define UMA_HISTOGRAM_PERCENTAGE_IN_TABLET_NON_SPLITVIEW(name, ...) \
   do {                                                              \
-    if (ash::IsInTabletMode() && !ash::IsInSplitView())             \
+    if (ash::InTabletMode() && !ash::IsInSplitView())               \
       UMA_HISTOGRAM_PERCENTAGE(name, __VA_ARGS__);                  \
   } while (0)
 
 #define UMA_HISTOGRAM_PERCENTAGE_IN_CLAMSHELL(name, ...) \
   do {                                                   \
-    if (!ash::IsInTabletMode())                          \
+    if (!ash::InTabletMode())                            \
       UMA_HISTOGRAM_PERCENTAGE(name, __VA_ARGS__);       \
   } while (0)
 
 namespace ash {
 
-ASH_EXPORT bool IsInTabletMode();
+ASH_EXPORT bool InTabletMode();
 ASH_EXPORT bool IsInSplitView();
 
 }  // namespace ash
diff --git a/ash/metrics/login_metrics_recorder_unittest.cc b/ash/metrics/login_metrics_recorder_unittest.cc
index 23b6822d..a7c381f9 100644
--- a/ash/metrics/login_metrics_recorder_unittest.cc
+++ b/ash/metrics/login_metrics_recorder_unittest.cc
@@ -48,8 +48,7 @@
 
  protected:
   void EnableTabletMode(bool enable) {
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
-        enable);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
   }
 
   LoginMetricsRecorder* metrics_recorder() {
diff --git a/ash/metrics/pointer_metrics_recorder.cc b/ash/metrics/pointer_metrics_recorder.cc
index e15c008..7630e75e 100644
--- a/ash/metrics/pointer_metrics_recorder.cc
+++ b/ash/metrics/pointer_metrics_recorder.cc
@@ -47,9 +47,7 @@
   views::Widget* target = views::Widget::GetTopLevelWidgetForNativeView(
       static_cast<aura::Window*>(event_target));
   DownEventFormFactor form_factor = DownEventFormFactor::kClamshell;
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     OrientationLockType screen_orientation =
         Shell::Get()->screen_orientation_controller()->GetCurrentOrientation();
     if (screen_orientation == OrientationLockType::kLandscapePrimary ||
diff --git a/ash/metrics/pointer_metrics_recorder_unittest.cc b/ash/metrics/pointer_metrics_recorder_unittest.cc
index 1a31a261..f7c2638 100644
--- a/ash/metrics/pointer_metrics_recorder_unittest.cc
+++ b/ash/metrics/pointer_metrics_recorder_unittest.cc
@@ -77,10 +77,9 @@
   window->SetProperty(aura::client::kAppType, static_cast<int>(destination));
 
   if (form_factor == DownEventFormFactor::kClamshell) {
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
-        false);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   } else {
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
     display::Display::Rotation rotation =
         (form_factor == DownEventFormFactor::kTabletModeLandscape)
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index 596483b3..cc44518 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -15,8 +15,8 @@
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableBackgroundBlur{"EnableBackgroundBlur",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kEnablePlayStoreAppSearch{
-    "EnablePlayStoreAppSearch", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kEnablePlayStoreAppSearch{"EnablePlayStoreAppSearch",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableAppDataSearch{"EnableAppDataSearch",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnableSettingsShortcutSearch{
diff --git a/ash/public/cpp/test/shell_test_api.h b/ash/public/cpp/test/shell_test_api.h
index ae9b724..2bc974d 100644
--- a/ash/public/cpp/test/shell_test_api.h
+++ b/ash/public/cpp/test/shell_test_api.h
@@ -58,8 +58,8 @@
   // password dialog).
   bool IsSystemModalWindowOpen();
 
-  // Enables or disables the tablet mode window manager.
-  void EnableTabletModeWindowManager(bool enable);
+  // Enables or disables the tablet mode.
+  void SetTabletModeEnabledForTest(bool enable);
 
   // Enables the keyboard and associates it with the primary root window
   // controller. In tablet mode, enables the virtual keyboard.
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 19dba800..5b244c5 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -709,9 +709,7 @@
           wallpaper_widget_controller()->GetWidget(), source_type,
           base::BindOnce(&RootWindowController::OnMenuClosed,
                          base::Unretained(this)),
-          Shell::Get()
-              ->tablet_mode_controller()
-              ->IsTabletModeWindowManagerEnabled());
+          Shell::Get()->tablet_mode_controller()->InTabletMode());
 
   root_window_menu_model_adapter_->Run(
       gfx::Rect(location_in_screen, gfx::Size()),
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 62a2d7e..4c474d8 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -699,7 +699,7 @@
   EXPECT_TRUE(controller->root_window_menu_model_adapter_);
 
   // Verify menu closes on entering tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_FALSE(controller->root_window_menu_model_adapter_);
 
   // Open context menu.
@@ -708,7 +708,7 @@
   EXPECT_TRUE(controller->root_window_menu_model_adapter_);
 
   // Verify menu closes on exiting tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(controller->root_window_menu_model_adapter_);
 }
 
diff --git a/ash/rotator/screen_rotation_animator_unittest.cc b/ash/rotator/screen_rotation_animator_unittest.cc
index 2f775a24..6283148 100644
--- a/ash/rotator/screen_rotation_animator_unittest.cc
+++ b/ash/rotator/screen_rotation_animator_unittest.cc
@@ -379,7 +379,7 @@
 // The OverviewButton should be hidden.
 TEST_F(ScreenRotationAnimatorSlowAnimationTest,
        OverviewButtonTrayHideAnimationAlwaysCompletes) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   // Long duration for hide animation, to allow it to be interrupted.
   ui::ScopedAnimationDurationScaleMode hide_duration(
@@ -610,7 +610,7 @@
 // The OverviewButton should be hidden.
 TEST_F(ScreenRotationAnimatorSmoothAnimationTest,
        OverviewButtonTrayHideAnimationAlwaysCompletes) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   // Long duration for hide animation, to allow it to be interrupted.
   ui::ScopedAnimationDurationScaleMode hide_duration(
@@ -680,7 +680,7 @@
   const int64_t internal_display_id =
       display::test::DisplayManagerTestApi(display_manager())
           .SetFirstDisplayAsInternalDisplay();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   aura::Window* root_window =
       Shell::GetRootWindowForDisplayId(internal_display_id);
@@ -704,7 +704,7 @@
 
   EXPECT_TRUE(animator->IsRotating());
   display_manager()->UpdateDisplays();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(animator->IsRotating());
 
   WaitForCopyCallback();
diff --git a/ash/shelf/app_list_button_unittest.cc b/ash/shelf/app_list_button_unittest.cc
index 7f347da3..241059f 100644
--- a/ash/shelf/app_list_button_unittest.cc
+++ b/ash/shelf/app_list_button_unittest.cc
@@ -153,11 +153,11 @@
   base::RunLoop().RunUntilIdle();
 
   ShelfViewTestAPI test_api(GetPrimaryShelf()->GetShelfViewForTesting());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api.RunMessageLoopUntilAnimationsDone();
   EXPECT_GT(app_list_button()->bounds().x(), 0);
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api.RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(ShelfConstants::button_spacing(), app_list_button()->bounds().x());
 }
diff --git a/ash/shelf/assistant_overlay.cc b/ash/shelf/assistant_overlay.cc
index 4181af5..f3a963a 100644
--- a/ash/shelf/assistant_overlay.cc
+++ b/ash/shelf/assistant_overlay.cc
@@ -669,9 +669,8 @@
   transform.Scale(scale_factor, scale_factor);
   icon_layer_->SetTransform(transform);
 
-  const bool is_tablet_mode = Shell::Get()
-                                  ->tablet_mode_controller()
-                                  ->IsTabletModeWindowManagerEnabled();
+  const bool is_tablet_mode =
+      Shell::Get()->tablet_mode_controller()->InTabletMode();
   const int icon_x_offset = is_tablet_mode ? 0 : kIconOffsetDip;
   const int icon_y_offset =
       is_tablet_mode ? -kRippleCircleRadiusDip : -kIconOffsetDip;
@@ -784,9 +783,8 @@
   // We want to animate from the background's current position into a larger
   // size. The animation moves the background's center point while morphing from
   // circle to a rectangle.
-  const bool is_tablet_mode = Shell::Get()
-                                  ->tablet_mode_controller()
-                                  ->IsTabletModeWindowManagerEnabled();
+  const bool is_tablet_mode =
+      Shell::Get()->tablet_mode_controller()->InTabletMode();
   const int icon_x_offset = is_tablet_mode ? 0 : kIconOffsetDip;
   const int icon_y_offset =
       is_tablet_mode ? -kRippleCircleRadiusDip : -kIconOffsetDip;
diff --git a/ash/shelf/back_button_unittest.cc b/ash/shelf/back_button_unittest.cc
index 1322bab..945d20c2 100644
--- a/ash/shelf/back_button_unittest.cc
+++ b/ash/shelf/back_button_unittest.cc
@@ -58,11 +58,11 @@
   ASSERT_TRUE(back_button()->layer());
   EXPECT_EQ(0.f, back_button()->layer()->opacity());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api()->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(1.f, back_button()->layer()->opacity());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api()->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(0.f, back_button()->layer()->opacity());
 }
@@ -74,18 +74,18 @@
   ASSERT_TRUE(back_button()->layer());
   EXPECT_EQ(0.f, back_button()->layer()->opacity());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api()->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(1.f, back_button()->layer()->opacity());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api()->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(0.f, back_button()->layer()->opacity());
 }
 
 TEST_F(BackButtonTest, BackKeySequenceGenerated) {
   // Enter tablet mode; the back button is not visible in non tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api()->RunMessageLoopUntilAnimationsDone();
 
   AcceleratorControllerImpl* controller =
@@ -160,9 +160,7 @@
   SimulateKioskNextSession();
 
   // Tablet mode should be enabled in Kiosk Next.
-  ASSERT_TRUE(Shell::Get()
-                  ->tablet_mode_controller()
-                  ->IsTabletModeWindowManagerEnabled());
+  ASSERT_TRUE(Shell::Get()->tablet_mode_controller()->InTabletMode());
   test_api()->RunMessageLoopUntilAnimationsDone();
 
   // Enter Overview mode, since the shelf view is hidden from the Kiosk Next
diff --git a/ash/shelf/default_shelf_view.cc b/ash/shelf/default_shelf_view.cc
index 206905c6..cc67496 100644
--- a/ash/shelf/default_shelf_view.cc
+++ b/ash/shelf/default_shelf_view.cc
@@ -53,9 +53,7 @@
   // This check is needed, because tablet mode controller is destroyed before
   // shelf widget. See https://crbug.com/967149 for more details.
   return Shell::Get()->tablet_mode_controller() &&
-         Shell::Get()
-             ->tablet_mode_controller()
-             ->IsTabletModeWindowManagerEnabled();
+         Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 // Returns the size occupied by |count| app icons. If |with_overflow| is
diff --git a/ash/shelf/kiosk_next_shelf_view.cc b/ash/shelf/kiosk_next_shelf_view.cc
index 59fadc1b..67251316 100644
--- a/ash/shelf/kiosk_next_shelf_view.cc
+++ b/ash/shelf/kiosk_next_shelf_view.cc
@@ -100,9 +100,7 @@
   // This check is needed, because tablet mode controller is destroyed before
   // shelf widget. See https://crbug.com/967149 for more details.
   return Shell::Get()->tablet_mode_controller() &&
-         Shell::Get()
-             ->tablet_mode_controller()
-             ->IsTabletModeWindowManagerEnabled();
+         Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 }  // namespace
diff --git a/ash/shelf/shelf_context_menu_model.cc b/ash/shelf/shelf_context_menu_model.cc
index 0117a53..a0fc73d 100644
--- a/ash/shelf/shelf_context_menu_model.cc
+++ b/ash/shelf/shelf_context_menu_model.cc
@@ -96,8 +96,7 @@
 
   UserMetricsRecorder* metrics = shell->metrics();
   // Clamshell mode only options should not activate in tablet mode.
-  const bool is_tablet_mode =
-      shell->tablet_mode_controller()->IsTabletModeWindowManagerEnabled();
+  const bool is_tablet_mode = shell->tablet_mode_controller()->InTabletMode();
   switch (command_id) {
     case MENU_AUTO_HIDE:
       SetShelfAutoHideBehaviorPref(
@@ -164,9 +163,7 @@
   // mode, the shelf alignment option is not shown.
   LoginStatus status = Shell::Get()->session_controller()->login_status();
   if ((status == LoginStatus::USER || status == LoginStatus::OWNER) &&
-      !Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled()) {
+      !Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     alignment_submenu_ = std::make_unique<ui::SimpleMenuModel>(this);
 
     constexpr int group = 0;
diff --git a/ash/shelf/shelf_context_menu_model_unittest.cc b/ash/shelf/shelf_context_menu_model_unittest.cc
index 67933831..640bef14 100644
--- a/ash/shelf/shelf_context_menu_model_unittest.cc
+++ b/ash/shelf/shelf_context_menu_model_unittest.cc
@@ -204,7 +204,7 @@
 
   // In tablet mode, the wallpaper picker and auto-hide should be the only two
   // options because other options are disabled.
-  tablet_mode_controller->EnableTabletModeWindowManager(true);
+  tablet_mode_controller->SetEnabledForTest(true);
   ShelfContextMenuModel menu1(nullptr, primary_id);
   EXPECT_EQ(2, menu1.GetItemCount());
   EXPECT_EQ(ShelfContextMenuModel::MENU_AUTO_HIDE, menu1.GetCommandIdAt(0));
@@ -213,7 +213,7 @@
 
   // Test that a menu shown out of tablet mode includes all three options:
   // MENU_AUTO_HIDE, MENU_ALIGNMENT_MENU, and MENU_CHANGE_WALLPAPER.
-  tablet_mode_controller->EnableTabletModeWindowManager(false);
+  tablet_mode_controller->SetEnabledForTest(false);
   ShelfContextMenuModel menu2(nullptr, primary_id);
   EXPECT_EQ(3, menu2.GetItemCount());
 
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index 130828fd..267f2f59 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -91,9 +91,7 @@
 
   // The shelf should always be bottom-aligned in tablet mode; alignment is
   // assigned from prefs when tablet mode is exited.
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     return;
   }
 
diff --git a/ash/shelf/shelf_controller_unittest.cc b/ash/shelf/shelf_controller_unittest.cc
index 7dab2aa6..6c69e6f 100644
--- a/ash/shelf/shelf_controller_unittest.cc
+++ b/ash/shelf/shelf_controller_unittest.cc
@@ -316,7 +316,7 @@
 
   // Verify after entering tablet mode, the shelf alignment is bottom and the
   // auto hide behavior has not changed.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
   EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
 
@@ -329,7 +329,7 @@
 
   // Verify after exiting tablet mode, the shelf alignment and auto hide
   // behavior get their stored pref values.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(SHELF_ALIGNMENT_LEFT, shelf->alignment());
   EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
 }
@@ -343,7 +343,7 @@
   Shelf* shelf = GetPrimaryShelf();
   EXPECT_EQ(SHELF_AUTO_HIDE_ALWAYS_HIDDEN, shelf->auto_hide_behavior());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SHELF_AUTO_HIDE_ALWAYS_HIDDEN, shelf->auto_hide_behavior());
 
   display_manager()->SetDisplayRotation(
@@ -351,7 +351,7 @@
       display::Display::ROTATE_90, display::Display::RotationSource::ACTIVE);
   EXPECT_EQ(SHELF_AUTO_HIDE_ALWAYS_HIDDEN, shelf->auto_hide_behavior());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(SHELF_AUTO_HIDE_ALWAYS_HIDDEN, shelf->auto_hide_behavior());
 }
 
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 860234e..9178e00d 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -105,9 +105,7 @@
   if (!Shell::Get()->tablet_mode_controller())
     return false;
 
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 bool IsHomeScreenAvailable() {
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 5101097a8..4729d6c 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -120,9 +120,7 @@
 // Helper to check if tablet mode is enabled.
 bool IsTabletModeEnabled() {
   return Shell::Get()->tablet_mode_controller() &&
-         Shell::Get()
-             ->tablet_mode_controller()
-             ->IsTabletModeWindowManagerEnabled();
+         Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 // A class to temporarily disable a given bounds animator.
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 2a1b478..a74746f 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -962,7 +962,7 @@
   // is no longer visible on the main shelf but is now visible on the overflow
   // shelf, due to the back button taking up space on the main shelf. The shelf
   // model and corresponding view should be updated to reflect this.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api_->RunMessageLoopUntilAnimationsDone();
   overflow_test_api.RunMessageLoopUntilAnimationsDone();
   ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
@@ -971,7 +971,7 @@
 
   // Verify that the item at |last_visible_index| is once again shown on the
   // main shelf after exiting tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api_->RunMessageLoopUntilAnimationsDone();
   overflow_test_api.RunMessageLoopUntilAnimationsDone();
   ASSERT_TRUE(shelf_view_->IsShowingOverflowBubble());
@@ -2101,12 +2101,12 @@
   shelf_view_->shelf()->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
   SetShelfAlignmentPref(prefs, id, SHELF_ALIGNMENT_BOTTOM);
   observer.Reset();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api_->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(animation_duration, observer.icon_positions_animation_duration());
 
   observer.Reset();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api_->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(animation_duration, observer.icon_positions_animation_duration());
 
@@ -2115,12 +2115,12 @@
   shelf_view_->shelf()->SetAlignment(SHELF_ALIGNMENT_LEFT);
   SetShelfAlignmentPref(prefs, id, SHELF_ALIGNMENT_LEFT);
   observer.Reset();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api_->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(1, observer.icon_positions_animation_duration());
 
   observer.Reset();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   test_api_->RunMessageLoopUntilAnimationsDone();
   EXPECT_EQ(1, observer.icon_positions_animation_duration());
 }
@@ -2165,7 +2165,7 @@
   // Enable tablet mode to show the back button. Wait for tablet mode animations
   // to finish in order for the BackButton to move out from under the
   // AppListButton.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   test_api_->RunMessageLoopUntilAnimationsDone();
 
   views::View* back_button = shelf_view_->GetBackButton();
@@ -2375,12 +2375,12 @@
   EXPECT_EQ(1, shelf_view_->first_visible_index());
   EXPECT_EQ(2, shelf_view_->last_visible_index());
   // By enabling tablet mode, the back button (index 0) should become visible.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(0, shelf_view_->first_visible_index());
   EXPECT_EQ(2, shelf_view_->last_visible_index());
   // And things should return back to the previous state once tablet mode is off
   // again.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(1, shelf_view_->first_visible_index());
   EXPECT_EQ(2, shelf_view_->last_visible_index());
   // Now let's add some apps until the overflow button shows up, each time
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc
index c55d2f94..34c94c1d 100644
--- a/ash/shell_test_api.cc
+++ b/ash/shell_test_api.cc
@@ -180,10 +180,10 @@
   return Shell::IsSystemModalWindowOpen();
 }
 
-void ShellTestApi::EnableTabletModeWindowManager(bool enable) {
+void ShellTestApi::SetTabletModeEnabledForTest(bool enable) {
   AccelerometerReader::GetInstance()->DisableForTest();
   TabletModeController::SetForceNoScreenshotForTest();
-  shell_->tablet_mode_controller()->EnableTabletModeWindowManager(enable);
+  shell_->tablet_mode_controller()->SetEnabledForTest(enable);
 }
 
 void ShellTestApi::EnableVirtualKeyboard() {
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.cc b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
index 6c2c0f6..66d5eb3 100644
--- a/ash/system/accessibility/autoclick_menu_bubble_controller.cc
+++ b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
@@ -145,13 +145,21 @@
                     width, kAutoclickMenuHeight);
       break;
     case mojom::AutoclickMenuPosition::kTopLeft:
-      // Setting the top to 1 instead of 0 so that the view is drawn on screen.
-      new_bounds = gfx::Rect(work_area.x(), 1, width, kAutoclickMenuHeight);
+      // Because there is no inset at the top of the widget, add
+      // 2 * kCollisionWindowWorkAreaInsetsDp to the top of the work area.
+      // to ensure correct padding.
+      new_bounds = gfx::Rect(
+          work_area.x(), work_area.y() + 2 * kCollisionWindowWorkAreaInsetsDp,
+          width, kAutoclickMenuHeight);
       break;
     case mojom::AutoclickMenuPosition::kTopRight:
-      // Setting the top to 1 instead of 0 so that the view is drawn on screen.
+      // Because there is no inset at the top of the widget, add
+      // 2 * kCollisionWindowWorkAreaInsetsDp to the top of the work area.
+      // to ensure correct padding.
       new_bounds =
-          gfx::Rect(work_area.right() - width, 1, width, kAutoclickMenuHeight);
+          gfx::Rect(work_area.right() - width,
+                    work_area.y() + 2 * kCollisionWindowWorkAreaInsetsDp, width,
+                    kAutoclickMenuHeight);
       break;
     case mojom::AutoclickMenuPosition::kSystemDefault:
       return;
@@ -200,7 +208,14 @@
   init_params.parent_window = Shell::GetContainer(
       Shell::GetPrimaryRootWindow(), kShellWindowId_AutoclickContainer);
   init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
-  init_params.insets = gfx::Insets(kCollisionWindowWorkAreaInsetsDp);
+  // The widget's shadow is drawn below and on the sides of the view, with a
+  // width of kCollisionWindowWorkAreaInsetsDp. Set the top inset to 0 to ensure
+  // the scroll view is drawn at kCollisionWindowWorkAreaInsetsDp above the
+  // bubble menu when the position is at the bottom of the screen. The space
+  // between the bubbles belongs to the scroll view bubble's shadow.
+  init_params.insets = gfx::Insets(0, kCollisionWindowWorkAreaInsetsDp,
+                                   kCollisionWindowWorkAreaInsetsDp,
+                                   kCollisionWindowWorkAreaInsetsDp);
   int width = base::CommandLine::ForCurrentProcess()->HasSwitch(
                   switches::kEnableExperimentalAccessibilityAutoclick)
                   ? kAutoclickMenuWidthWithScroll
diff --git a/ash/system/accessibility/autoclick_scroll_bubble_controller.cc b/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
index 37b5aa5..084c393 100644
--- a/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
+++ b/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
@@ -55,8 +55,12 @@
       Shell::GetPrimaryRootWindow(), kShellWindowId_AutoclickContainer);
   init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
   init_params.anchor_rect = anchor_rect;
-  init_params.insets = gfx::Insets(kUnifiedMenuPadding, kUnifiedMenuPadding,
-                                   kUnifiedMenuPadding, kUnifiedMenuPadding);
+  // The widget's shadow is drawn below and on the sides of the scroll view.
+  // Do not inset the top, so that when the scroll bubble is shown below the
+  // menu bubble it lays out directly below the menu bubble's shadow, at a
+  // height of kUnifiedMenuPadding.
+  init_params.insets = gfx::Insets(0, kUnifiedMenuPadding, kUnifiedMenuPadding,
+                                   kUnifiedMenuPadding);
   init_params.min_width = kAutoclickScrollMenuSizeDips;
   init_params.max_width = kAutoclickScrollMenuSizeDips;
   init_params.max_height = kAutoclickScrollMenuSizeDips;
diff --git a/ash/system/power/power_button_controller_unittest.cc b/ash/system/power/power_button_controller_unittest.cc
index eb693deb..c226d41 100644
--- a/ash/system/power/power_button_controller_unittest.cc
+++ b/ash/system/power/power_button_controller_unittest.cc
@@ -131,9 +131,7 @@
   // Press the power button to show the menu.
   void OpenPowerButtonMenu() {
     PressPowerButton();
-    if (Shell::Get()
-            ->tablet_mode_controller()
-            ->IsTabletModeWindowManagerEnabled()) {
+    if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
       EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
       ASSERT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout());
     }
@@ -1133,9 +1131,7 @@
 
   // Returns true if it is in tablet mode.
   bool IsTabletMode() const {
-    return Shell::Get()
-        ->tablet_mode_controller()
-        ->IsTabletModeWindowManagerEnabled();
+    return Shell::Get()->tablet_mode_controller()->InTabletMode();
   }
 
   // Returns true if the menu is at the center of the display.
diff --git a/ash/system/power/power_button_display_controller.cc b/ash/system/power/power_button_display_controller.cc
index 594de01..79f5a99e 100644
--- a/ash/system/power/power_button_display_controller.cc
+++ b/ash/system/power/power_button_display_controller.cc
@@ -23,8 +23,7 @@
 bool IsTabletModeActive() {
   TabletModeController* tablet_mode_controller =
       Shell::Get()->tablet_mode_controller();
-  return tablet_mode_controller &&
-         tablet_mode_controller->IsTabletModeWindowManagerEnabled();
+  return tablet_mode_controller && tablet_mode_controller->InTabletMode();
 }
 
 }  // namespace
diff --git a/ash/system/power/power_button_menu_screen_view.cc b/ash/system/power/power_button_menu_screen_view.cc
index 0d7cd8c..828c0af 100644
--- a/ash/system/power/power_button_menu_screen_view.cc
+++ b/ash/system/power/power_button_menu_screen_view.cc
@@ -311,9 +311,7 @@
   gfx::Rect menu_bounds;
 
   if (power_button_position_ == PowerButtonPosition::NONE ||
-      !Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled()) {
+      !Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     menu_bounds = GetContentsBounds();
     menu_bounds.ClampToCenteredSize(
         power_button_menu_view_->GetPreferredSize());
diff --git a/ash/system/power/power_button_menu_view.cc b/ash/system/power/power_button_menu_view.cc
index fbebf58..d774f330 100644
--- a/ash/system/power/power_button_menu_view.cc
+++ b/ash/system/power/power_button_menu_view.cc
@@ -96,9 +96,7 @@
 PowerButtonMenuView::GetTransformDisplacement() const {
   TransformDisplacement transform_displacement;
   if (power_button_position_ == PowerButtonPosition::NONE ||
-      !Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled()) {
+      !Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     transform_displacement.direction = TransformDirection::Y;
     transform_displacement.distance = kMenuViewTransformDistanceDp;
     return transform_displacement;
diff --git a/ash/system/power/power_button_screenshot_controller.cc b/ash/system/power/power_button_screenshot_controller.cc
index 34e0660..81080b65 100644
--- a/ash/system/power/power_button_screenshot_controller.cc
+++ b/ash/system/power/power_button_screenshot_controller.cc
@@ -18,9 +18,7 @@
 namespace {
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 }  // namespace
diff --git a/ash/system/power/power_button_test_base.cc b/ash/system/power/power_button_test_base.cc
index 2c0f5ea..60c0c99c 100644
--- a/ash/system/power/power_button_test_base.cc
+++ b/ash/system/power/power_button_test_base.cc
@@ -117,7 +117,7 @@
 }
 
 void PowerButtonTestBase::EnableTabletMode(bool enable) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(enable);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
 }
 
 void PowerButtonTestBase::AdvanceClockToAvoidIgnoring() {
diff --git a/ash/system/rotation/rotation_lock_feature_pod_controller.cc b/ash/system/rotation/rotation_lock_feature_pod_controller.cc
index 205e2f67..efb4ad3 100644
--- a/ash/system/rotation/rotation_lock_feature_pod_controller.cc
+++ b/ash/system/rotation/rotation_lock_feature_pod_controller.cc
@@ -55,9 +55,7 @@
 }
 
 void RotationLockFeaturePodController::UpdateButton() {
-  bool tablet_enabled = Shell::Get()
-                            ->tablet_mode_controller()
-                            ->IsTabletModeWindowManagerEnabled();
+  bool tablet_enabled = Shell::Get()->tablet_mode_controller()->InTabletMode();
 
   button_->SetVisible(tablet_enabled);
 
diff --git a/ash/system/rotation/rotation_lock_feature_pod_controller_unittest.cc b/ash/system/rotation/rotation_lock_feature_pod_controller_unittest.cc
index 06e14074b6..6e264de 100644
--- a/ash/system/rotation/rotation_lock_feature_pod_controller_unittest.cc
+++ b/ash/system/rotation/rotation_lock_feature_pod_controller_unittest.cc
@@ -67,10 +67,10 @@
 // Tests that when the button is created, while TabletMode is active,
 // that it is visible.
 TEST_F(RotationLockFeaturePodControllerTest, CreateButtonDuringTabletMode) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   SetUpController();
   EXPECT_TRUE(button_view()->GetVisible());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(button_view()->GetVisible());
 }
 
@@ -79,9 +79,9 @@
 TEST_F(RotationLockFeaturePodControllerTest,
        ButtonVisibilityChangesDuringTabletMode) {
   SetUpController();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(button_view()->GetVisible());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(button_view()->GetVisible());
 }
 
@@ -92,7 +92,7 @@
   ScreenOrientationController* screen_orientation_controller =
       Shell::Get()->screen_orientation_controller();
   ASSERT_FALSE(screen_orientation_controller->rotation_locked());
-  tablet_mode_controller->EnableTabletModeWindowManager(true);
+  tablet_mode_controller->SetEnabledForTest(true);
   ASSERT_TRUE(button_view()->GetVisible());
   EXPECT_FALSE(button_view()->IsToggled());
 
@@ -106,7 +106,7 @@
   EXPECT_TRUE(button_view()->GetVisible());
   EXPECT_FALSE(button_view()->IsToggled());
 
-  tablet_mode_controller->EnableTabletModeWindowManager(false);
+  tablet_mode_controller->SetEnabledForTest(false);
 }
 
 }  // namespace ash
diff --git a/ash/system/screen_layout_observer.cc b/ash/system/screen_layout_observer.cc
index 808141e2..52085c2 100644
--- a/ash/system/screen_layout_observer.cc
+++ b/ash/system/screen_layout_observer.cc
@@ -335,9 +335,7 @@
       continue;
     }
     // c) if the device is in tablet mode, and source is not user.
-    if (Shell::Get()
-            ->tablet_mode_controller()
-            ->IsTabletModeWindowManagerEnabled() &&
+    if (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
         iter.second.active_rotation_source() !=
             display::Display::RotationSource::USER) {
       continue;
diff --git a/ash/system/screen_layout_observer_unittest.cc b/ash/system/screen_layout_observer_unittest.cc
index ef50732..5cb37e3 100644
--- a/ash/system/screen_layout_observer_unittest.cc
+++ b/ash/system/screen_layout_observer_unittest.cc
@@ -195,7 +195,7 @@
   CloseNotification();
 
   // Start tablet mode and wait until display mode is updated.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::RunLoop().RunUntilIdle();
 
   // Exit mirror mode manually. Now display mode should be extending mode.
@@ -221,7 +221,7 @@
   // updated.
   display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
       .ResetMaximumDisplay();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   base::RunLoop().RunUntilIdle();
 
   // Turn on mirror mode.
@@ -556,7 +556,7 @@
             GetDisplayNotificationAdditionalText());
 
   // Switch to Tablet
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   // The accelerometer source.
   display_manager()->SetDisplayRotation(
diff --git a/ash/system/tray/tray_event_filter.cc b/ash/system/tray/tray_event_filter.cc
index 385f26f0..ea8827a 100644
--- a/ash/system/tray/tray_event_filter.cc
+++ b/ash/system/tray/tray_event_filter.cc
@@ -91,9 +91,7 @@
     // treated as outside of the bubble.
     int bubble_container_id =
         wm::GetContainerForWindow(bubble_widget->GetNativeWindow())->id();
-    if (Shell::Get()
-            ->tablet_mode_controller()
-            ->IsTabletModeWindowManagerEnabled() &&
+    if (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
         bubble_container_id == kShellWindowId_SettingBubbleContainer) {
       bounds.Intersect(bubble_widget->GetWorkAreaBoundsInScreen());
     }
diff --git a/ash/system/unified/ime_mode_view.cc b/ash/system/unified/ime_mode_view.cc
index 4ec4ef191..2fb9949 100644
--- a/ash/system/unified/ime_mode_view.cc
+++ b/ash/system/unified/ime_mode_view.cc
@@ -78,9 +78,7 @@
 
   // Do not show IME mode icon in tablet mode as it's less useful and screen
   // space is limited.
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     SetVisible(false);
     return;
   }
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index 5136282..34f757c 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -334,9 +334,7 @@
 
   // If you want to add a new feature pod item, add here.
 
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     UMA_HISTOGRAM_COUNTS_100("ChromeOS.SystemTray.Tablet.FeaturePodCountOnOpen",
                              unified_view_->GetVisibleFeaturePodCount());
   } else {
diff --git a/ash/wallpaper/wallpaper_base_view.cc b/ash/wallpaper/wallpaper_base_view.cc
index a792f97..122bc9c 100644
--- a/ash/wallpaper/wallpaper_base_view.cc
+++ b/ash/wallpaper/wallpaper_base_view.cc
@@ -38,9 +38,7 @@
       SkColorSetA(darken_color, 0xFF));
 
   int alpha = login_constants::kTranslucentAlpha;
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     alpha = kTabletModeWallpaperAlpha;
   } else if (Shell::Get()->overview_controller()->InOverviewSession()) {
     // Overview mode will apply its own brightness filter on a downscaled image,
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index 8f05d04e..2962742 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -714,9 +714,7 @@
   // wallpaper preview.
   const bool should_dim =
       Shell::Get()->session_controller()->IsUserSessionBlocked() ||
-      (Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled() &&
+      (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
        !confirm_preview_wallpaper_callback_);
   return should_dim && !IsOneShotWallpaper();
 }
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 0f7238a..c02e2db 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -1151,7 +1151,7 @@
   // since it's the one that has a window in it.
   // Avoid TabletModeController::OnGetSwitchStates() from disabling tablet mode.
   base::RunLoop().RunUntilIdle();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   auto* desk_1_backdrop_controller =
       GetDeskBackdropController(desk_1, Shell::GetPrimaryRootWindow());
   auto* desk_2_backdrop_controller =
@@ -1208,7 +1208,7 @@
   EXPECT_TRUE(desk_2_backdrop_controller->backdrop_window()->IsVisible());
 
   // No backdrops after exiting tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
   EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
 }
@@ -1221,7 +1221,7 @@
   // Enter tablet mode. Avoid TabletModeController::OnGetSwitchStates() from
   // disabling tablet mode.
   base::RunLoop().RunUntilIdle();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   auto* overview_controller = Shell::Get()->overview_controller();
   overview_controller->ToggleOverview();
diff --git a/ash/wm/drag_details.cc b/ash/wm/drag_details.cc
index d31e223..611c78e 100644
--- a/ash/wm/drag_details.cc
+++ b/ash/wm/drag_details.cc
@@ -45,9 +45,8 @@
 }
 
 gfx::Rect GetWindowInitialBoundsInParent(aura::Window* window) {
-  const bool is_tablet_mode = Shell::Get()
-                                  ->tablet_mode_controller()
-                                  ->IsTabletModeWindowManagerEnabled();
+  const bool is_tablet_mode =
+      Shell::Get()->tablet_mode_controller()->InTabletMode();
   if (is_tablet_mode) {
     gfx::Rect* override_bounds = window->GetProperty(kRestoreBoundsOverrideKey);
     if (override_bounds && !override_bounds->IsEmpty()) {
@@ -86,9 +85,8 @@
     return;
 
   wm::WindowState* window_state = wm::GetWindowState(window);
-  const bool is_tablet_mode = Shell::Get()
-                                  ->tablet_mode_controller()
-                                  ->IsTabletModeWindowManagerEnabled();
+  const bool is_tablet_mode =
+      Shell::Get()->tablet_mode_controller()->InTabletMode();
   // TODO(xdai): Move these logic to WindowState::GetRestoreBoundsInScreen()
   // and let it return the right value.
   if (!is_tablet_mode && window_state->IsNormalOrSnapped() &&
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc
index b5dd235a..86fb2b1 100644
--- a/ash/wm/immersive_fullscreen_controller_unittest.cc
+++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -237,8 +237,7 @@
 
   // Enable or disable tablet mode based on |enable|.
   void EnableTabletMode(bool enable) {
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
-        enable);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
   }
 
  private:
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index 0f58602..9b7c71e 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -70,9 +70,7 @@
 // the screen.
 bool ShouldSlideInOutOverview(const std::vector<aura::Window*>& windows) {
   // No sliding if home launcher is not available.
-  if (!Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled()) {
+  if (!Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     return false;
   }
 
diff --git a/ash/wm/overview/overview_controller_unittest.cc b/ash/wm/overview/overview_controller_unittest.cc
index f636c68..4930571 100644
--- a/ash/wm/overview/overview_controller_unittest.cc
+++ b/ash/wm/overview/overview_controller_unittest.cc
@@ -261,9 +261,9 @@
 TEST_F(OverviewControllerTest, OverviewEnterExitAnimationTablet) {
   TestOverviewObserver observer(/*should_monitor_animation_state = */ false);
 
-  // Ensure calls to EnableTabletModeWindowManager complete.
+  // Ensure calls to SetEnabledForTest complete.
   base::RunLoop().RunUntilIdle();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   base::RunLoop().RunUntilIdle();
 
   const gfx::Rect bounds(200, 200);
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index c04713f..e8826daf 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -392,9 +392,7 @@
   }
   bool single_animation_in_clamshell =
       (animate_count == 1 && !has_non_cover_animating) &&
-      !Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled();
+      !Shell::Get()->tablet_mode_controller()->InTabletMode();
 
   // OverviewGrid in splitscreen does not include the window to be activated.
   if (!window_list_.empty() ||
@@ -417,9 +415,7 @@
   for (const auto& window : window_list_)
     window->PrepareForOverview();
   prepared_for_overview_ = true;
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     ScreenRotationAnimator::GetForRootWindow(root_window_)->AddObserver(this);
   }
 }
@@ -484,9 +480,7 @@
       !window_list_.empty()) {
     bool single_animation_in_clamshell =
         animate_count == 1 && !has_non_cover_animating &&
-        !Shell::Get()
-             ->tablet_mode_controller()
-             ->IsTabletModeWindowManagerEnabled();
+        !Shell::Get()->tablet_mode_controller()->InTabletMode();
     fps_counter_ = std::make_unique<OverviewEnterFpsCounter>(
         window_list_[0]->GetWindow()->layer()->GetCompositor(),
         single_animation_in_clamshell);
@@ -1079,9 +1073,7 @@
                   : items[i]->GetWindow()->GetBoundsInRootWindow();
     if (!src_bounds_temp.IsEmpty()) {
       if (transition == OverviewTransition::kEnter &&
-          Shell::Get()
-              ->tablet_mode_controller()
-              ->IsTabletModeWindowManagerEnabled()) {
+          Shell::Get()->tablet_mode_controller()->InTabletMode()) {
         BackdropController* backdrop_controller =
             GetActiveWorkspaceController(root_window_)
                 ->layout_manager()
diff --git a/ash/wm/overview/overview_grid_unittest.cc b/ash/wm/overview/overview_grid_unittest.cc
index 014959b..c6ea4e1c 100644
--- a/ash/wm/overview/overview_grid_unittest.cc
+++ b/ash/wm/overview/overview_grid_unittest.cc
@@ -200,7 +200,7 @@
                        aura::client::kResizeBehaviorNone);
   ::wm::ActivateWindow(window1.get());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   BackdropController* backdrop_controller =
       GetWorkspaceControllerForContext(window1.get())
           ->layout_manager()
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index a89df4a3..b4963c1 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -99,9 +99,7 @@
   // Fade out the minimized window without animation if switch from tablet mode
   // to clamshell mode.
   if (type == OverviewSession::EnterExitOverviewType::kWindowsMinimized) {
-    return Shell::Get()
-                   ->tablet_mode_controller()
-                   ->IsTabletModeWindowManagerEnabled()
+    return Shell::Get()->tablet_mode_controller()->InTabletMode()
                ? OVERVIEW_ANIMATION_EXIT_TO_HOME_LAUNCHER
                : OVERVIEW_ANIMATION_NONE;
   }
@@ -271,9 +269,7 @@
   // TODO(oshima): SplitViewController has its own logic to adjust the
   // target state in |SplitViewController::OnOverviewModeEnding|.
   // Unify the mechanism to control it and remove ifs.
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled() &&
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode() &&
       !Shell::Get()->split_view_controller()->InSplitViewMode() &&
       reset_transform) {
     MaximizeIfSnapped(GetWindow());
@@ -904,9 +900,7 @@
 
   base::RecordAction(
       base::UserMetricsAction("WindowSelector_OverviewCloseButton"));
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     base::RecordAction(
         base::UserMetricsAction("Tablet_WindowCloseFromOverviewButton"));
   }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 12c53c8..3b7de06 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -167,9 +167,9 @@
   // Enters tablet mode. Needed by tests that test dragging and or splitview,
   // which are tablet mode only.
   void EnterTabletMode() {
-    // Ensure calls to EnableTabletModeWindowManager complete.
+    // Ensure calls to SetEnabledForTest complete.
     base::RunLoop().RunUntilIdle();
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -3718,7 +3718,7 @@
   DragWindowTo(overview_item1, gfx::PointF());
   EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(overview_controller()->InOverviewSession());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
 
@@ -4512,8 +4512,7 @@
     scoped_feature_list_.InitAndEnableFeature(
         ash::features::kDragToSnapInClamshellMode);
     OverviewSessionTest::SetUp();
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
-        false);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
     DCHECK(ShouldAllowSplitView());
   }
 
@@ -4545,9 +4544,7 @@
 // Test some basic functionalities in clamshell splitview mode.
 TEST_F(SplitViewOverviewSessionInClamshellTest, BasicFunctionalitiesTest) {
   UpdateDisplay("600x400");
-  EXPECT_FALSE(Shell::Get()
-                   ->tablet_mode_controller()
-                   ->IsTabletModeWindowManagerEnabled());
+  EXPECT_FALSE(Shell::Get()->tablet_mode_controller()->InTabletMode());
 
   // 1. Test the 1 window scenario.
   const gfx::Rect bounds(400, 400);
diff --git a/ash/wm/pip/pip_window_resizer_unittest.cc b/ash/wm/pip/pip_window_resizer_unittest.cc
index e084aff..e02e411 100644
--- a/ash/wm/pip/pip_window_resizer_unittest.cc
+++ b/ash/wm/pip/pip_window_resizer_unittest.cc
@@ -236,7 +236,7 @@
 }
 
 TEST_P(PipWindowResizerTest, PipWindowCanBeDraggedInTabletMode) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   PreparePipWindow(gfx::Rect(200, 200, 100, 100));
   std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
@@ -247,7 +247,7 @@
 }
 
 TEST_P(PipWindowResizerTest, PipWindowCanBeResizedInTabletMode) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   PreparePipWindow(gfx::Rect(200, 200, 100, 100));
   std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTBOTTOM));
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 6a7d8ea..9c10cbc 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -276,9 +276,7 @@
   display::Screen::GetScreen()->AddObserver(this);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
   if (IsClamshellSplitViewModeEnabled()) {
-    split_view_type_ = Shell::Get()
-                               ->tablet_mode_controller()
-                               ->IsTabletModeWindowManagerEnabled()
+    split_view_type_ = Shell::Get()->tablet_mode_controller()->InTabletMode()
                            ? SplitViewType::kTabletType
                            : SplitViewType::kClamshellType;
   }
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 02e89b8..44a79e70 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -116,9 +116,7 @@
 };
 
 bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 }  // namespace
@@ -134,7 +132,7 @@
     // Avoid TabletModeController::OnGetSwitchStates() from disabling tablet
     // mode.
     base::RunLoop().RunUntilIdle();
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
     FpsCounter::SetForceReportZeroAnimationForTest(true);
     ash::PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest(
         true);
@@ -1403,7 +1401,7 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
 }
 
@@ -1791,7 +1789,7 @@
   EXPECT_NE(nullptr, w2_state->drag_details());
 
   // End tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
 
   // Drag is ended for both windows.
   EXPECT_EQ(nullptr, w1_state->drag_details());
diff --git a/ash/wm/splitview/split_view_drag_indicators_unittest.cc b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
index ae60b8cd..d5b4d8d3 100644
--- a/ash/wm/splitview/split_view_drag_indicators_unittest.cc
+++ b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
@@ -31,9 +31,9 @@
   void SetUp() override {
     AshTestBase::SetUp();
 
-    // Ensure calls to EnableTabletModeWindowManager complete.
+    // Ensure calls to SetEnabledForTest complete.
     base::RunLoop().RunUntilIdle();
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
     base::RunLoop().RunUntilIdle();
     ash::PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest(
         true);
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index 84fcfc0..9f826c1 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -234,9 +234,7 @@
 }
 
 bool ShouldAllowSplitView() {
-  if (!Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled() &&
+  if (!Shell::Get()->tablet_mode_controller()->InTabletMode() &&
       !IsClamshellSplitViewModeEnabled()) {
     return false;
   }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 5c9ef9c8..bbdca66 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -211,7 +211,7 @@
 
   // TODO(jonross): Do not create TabletModeController if the flag is
   // unavailable. This will require refactoring
-  // IsTabletModeWindowManagerEnabled to check for the existence of the
+  // InTabletMode to check for the existence of the
   // controller.
   if (ShouldInitTabletModeController()) {
     Shell::Get()->window_tree_host_manager()->AddObserver(this);
@@ -265,69 +265,12 @@
   force_no_screenshot = true;
 }
 
-// TODO(jcliang): Hide or remove EnableTabletModeWindowManager
-// (http://crbug.com/620241).
-void TabletModeController::EnableTabletModeWindowManager(bool should_enable) {
-  bool is_enabled = IsTabletModeWindowManagerEnabled();
-  if (should_enable == is_enabled)
-    return;
-
-  // Hide the context menu on entering tablet mode to prevent users from
-  // accessing forbidden options. Hide the context menu on exiting tablet mode
-  // to match behaviors.
-  for (auto* root_window : Shell::Get()->GetAllRootWindows())
-    RootWindowController::ForWindow(root_window)->HideContextMenu();
-
-  // Suspend occlusion tracker when entering or exiting tablet mode.
-  SuspendOcclusionTracker();
-  DeleteScreenshot();
-
-  if (should_enable) {
-    state_ = State::kEnteringTabletMode;
-
-    // Take a screenshot if there is a top window that will get animated.
-    // TODO(sammiequon): Handle the case where the top window is not on the
-    // primary display.
-    aura::Window* top_window = TabletModeWindowManager::GetTopWindow();
-    bool top_window_on_primary_display =
-        top_window &&
-        top_window->GetRootWindow() == Shell::GetPrimaryRootWindow();
-    if (!force_no_screenshot && top_window_on_primary_display) {
-      screenshot_set_callback_.Reset(
-          base::BindOnce(&TabletModeController::FinishInitTabletMode,
-                         weak_factory_.GetWeakPtr()));
-      TakeScreenshot(top_window, screenshot_set_callback_.callback());
-    } else {
-      FinishInitTabletMode();
-    }
-  } else {
-    state_ = State::kExitingTabletMode;
-
-    tablet_mode_window_manager_->SetIgnoreWmEventsForExit();
-    for (auto& observer : tablet_mode_observers_)
-      observer.OnTabletModeEnding();
-    tablet_mode_window_manager_->Shutdown();
-    tablet_mode_window_manager_.reset();
-    base::RecordAction(base::UserMetricsAction("Touchview_Disabled"));
-    RecordTabletModeUsageInterval(TABLET_MODE_INTERVAL_ACTIVE);
-    for (auto& observer : tablet_mode_observers_)
-      observer.OnTabletModeEnded();
-
-    state_ = State::kInClamshellMode;
-    if (toggle_observer_)  // Null at startup and in tests.
-      toggle_observer_->OnTabletModeToggled(false);
-    VLOG(1) << "Exit tablet mode.";
-  }
-
-  UpdateInternalInputDevicesEventBlocker();
-}
-
-bool TabletModeController::IsTabletModeWindowManagerEnabled() const {
+bool TabletModeController::InTabletMode() const {
   return !!tablet_mode_window_manager_;
 }
 
 void TabletModeController::AddWindow(aura::Window* window) {
-  if (IsTabletModeWindowManagerEnabled())
+  if (InTabletMode())
     tablet_mode_window_manager_->AddWindow(window);
 }
 
@@ -341,7 +284,7 @@
 
 bool TabletModeController::ShouldAutoHideTitlebars(views::Widget* widget) {
   DCHECK(widget);
-  const bool tablet_mode = IsTabletModeWindowManagerEnabled();
+  const bool tablet_mode = InTabletMode();
   if (!tablet_mode)
     return false;
 
@@ -401,7 +344,7 @@
 }
 
 bool TabletModeController::IsEnabled() const {
-  return IsTabletModeWindowManagerEnabled();
+  return InTabletMode();
 }
 
 void TabletModeController::SetEnabledForTest(bool enabled) {
@@ -412,7 +355,7 @@
   // ARC++ Tast tests.
   AccelerometerReader::GetInstance()->RemoveObserver(this);
   chromeos::PowerManagerClient::Get()->RemoveObserver(this);
-  EnableTabletModeWindowManager(enabled);
+  SetTabletModeEnabledInternal(enabled);
 }
 
 void TabletModeController::OnShellInitialized() {
@@ -427,7 +370,7 @@
 
   if (!HasActiveInternalDisplay()) {
     AttemptLeaveTabletMode();
-  } else if (tablet_mode_switch_is_on_ && !IsTabletModeWindowManagerEnabled()) {
+  } else if (tablet_mode_switch_is_on_ && !InTabletMode()) {
     // The internal display has returned, as we are exiting docked mode.
     // The device is still in tablet mode, so trigger tablet mode, as this
     // switch leads to the ignoring of accelerometer events. When the switch is
@@ -532,10 +475,9 @@
   // always reliable when |on|. However we wish to exit tablet mode at a
   // smaller angle, so when |on| is false we ignore if it is possible to
   // calculate the lid angle.
-  if (on && !IsTabletModeWindowManagerEnabled()) {
+  if (on && !InTabletMode()) {
     AttemptEnterTabletMode();
-  } else if (!on && IsTabletModeWindowManagerEnabled() &&
-             !can_detect_lid_angle_) {
+  } else if (!on && InTabletMode() && !can_detect_lid_angle_) {
     AttemptLeaveTabletMode();
   }
 
@@ -596,7 +538,7 @@
 }
 
 void TabletModeController::OnKioskNextEnabled() {
-  kiosk_next_enabled_ = true;
+  force_ui_mode_ = UiMode::kTabletMode;
   AttemptEnterTabletMode();
 }
 
@@ -641,6 +583,63 @@
   StopObservingAnimation(/*record_stats=*/false, /*delete_screenshot=*/true);
 }
 
+// TODO(jcliang): Remove SetTabletModeEnabledInternal
+// (http://crbug.com/620241).
+void TabletModeController::SetTabletModeEnabledInternal(bool should_enable) {
+  bool is_enabled = InTabletMode();
+  if (should_enable == is_enabled)
+    return;
+
+  // Hide the context menu on entering tablet mode to prevent users from
+  // accessing forbidden options. Hide the context menu on exiting tablet mode
+  // to match behaviors.
+  for (auto* root_window : Shell::Get()->GetAllRootWindows())
+    RootWindowController::ForWindow(root_window)->HideContextMenu();
+
+  // Suspend occlusion tracker when entering or exiting tablet mode.
+  SuspendOcclusionTracker();
+  DeleteScreenshot();
+
+  if (should_enable) {
+    state_ = State::kEnteringTabletMode;
+
+    // Take a screenshot if there is a top window that will get animated.
+    // TODO(sammiequon): Handle the case where the top window is not on the
+    // primary display.
+    aura::Window* top_window = TabletModeWindowManager::GetTopWindow();
+    bool top_window_on_primary_display =
+        top_window &&
+        top_window->GetRootWindow() == Shell::GetPrimaryRootWindow();
+    if (!force_no_screenshot && top_window_on_primary_display) {
+      screenshot_set_callback_.Reset(
+          base::BindOnce(&TabletModeController::FinishInitTabletMode,
+                         weak_factory_.GetWeakPtr()));
+      TakeScreenshot(top_window, screenshot_set_callback_.callback());
+    } else {
+      FinishInitTabletMode();
+    }
+  } else {
+    state_ = State::kExitingTabletMode;
+
+    tablet_mode_window_manager_->SetIgnoreWmEventsForExit();
+    for (auto& observer : tablet_mode_observers_)
+      observer.OnTabletModeEnding();
+    tablet_mode_window_manager_->Shutdown();
+    tablet_mode_window_manager_.reset();
+    base::RecordAction(base::UserMetricsAction("Touchview_Disabled"));
+    RecordTabletModeUsageInterval(TABLET_MODE_INTERVAL_ACTIVE);
+    for (auto& observer : tablet_mode_observers_)
+      observer.OnTabletModeEnded();
+
+    state_ = State::kInClamshellMode;
+    if (toggle_observer_)  // Null at startup and in tests.
+      toggle_observer_->OnTabletModeToggled(false);
+    VLOG(1) << "Exit tablet mode.";
+  }
+
+  UpdateInternalInputDevicesEventBlocker();
+}
+
 void TabletModeController::HandleHingeRotation(
     scoped_refptr<const AccelerometerUpdate> update) {
   static const gfx::Vector3dF hinge_vector(1.0f, 0.0f, 0.0f);
@@ -745,21 +744,21 @@
 }
 
 void TabletModeController::AttemptEnterTabletMode() {
-  if (IsTabletModeWindowManagerEnabled() || has_external_pointing_device_) {
+  if (InTabletMode() || has_external_pointing_device_) {
     UpdateInternalInputDevicesEventBlocker();
     return;
   }
 
-  EnableTabletModeWindowManager(true);
+  SetTabletModeEnabledInternal(true);
 }
 
 void TabletModeController::AttemptLeaveTabletMode() {
-  if (!IsTabletModeWindowManagerEnabled()) {
+  if (!InTabletMode()) {
     UpdateInternalInputDevicesEventBlocker();
     return;
   }
 
-  EnableTabletModeWindowManager(false);
+  SetTabletModeEnabledInternal(false);
 }
 
 void TabletModeController::RecordTabletModeUsageInterval(
@@ -793,13 +792,13 @@
 
 TabletModeController::TabletModeIntervalType
 TabletModeController::CurrentTabletModeIntervalType() {
-  if (IsTabletModeWindowManagerEnabled())
+  if (InTabletMode())
     return TABLET_MODE_INTERVAL_ACTIVE;
   return TABLET_MODE_INTERVAL_INACTIVE;
 }
 
 bool TabletModeController::AllowUiModeChange() const {
-  return force_ui_mode_ == UiMode::kNone && !kiosk_next_enabled_;
+  return force_ui_mode_ == UiMode::kNone;
 }
 
 void TabletModeController::HandlePointingDeviceAddedOrRemoved() {
@@ -840,7 +839,7 @@
   if (has_external_pointing_device) {
     AttemptLeaveTabletMode();
   } else if (HasActiveInternalDisplay() &&
-             (LidAngleIsInTabletModeRange() || tablet_mode_switch_is_on_)) {
+             (LidAngleInTabletModeRange() || tablet_mode_switch_is_on_)) {
     // If there is no external pointing device, only enter tablet mode if docked
     // mode is inactive and 1) the lid angle can be detected and is in tablet
     // mode angle range. or 2) if the lid angle can't be detected (e.g., tablet
@@ -869,12 +868,12 @@
 
 void TabletModeController::UpdateInternalInputDevicesEventBlocker() {
   bool should_block_internal_events = false;
-  if (IsTabletModeWindowManagerEnabled()) {
+  if (InTabletMode()) {
     // If we are currently in tablet mode, the internal input events should
     // always be blocked.
     should_block_internal_events = (force_ui_mode_ == UiMode::kNone);
   } else if (HasActiveInternalDisplay() &&
-             (LidAngleIsInTabletModeRange() || tablet_mode_switch_is_on_)) {
+             (LidAngleInTabletModeRange() || tablet_mode_switch_is_on_)) {
     // If we are currently in clamshell mode, the intenral input events should
     // only be blocked if the current lid angle belongs to tablet mode angle
     // or |tablet_mode_switch_is_on_| is true.
@@ -892,7 +891,7 @@
     observer.OnTabletModeEventsBlockingChanged();
 }
 
-bool TabletModeController::LidAngleIsInTabletModeRange() {
+bool TabletModeController::LidAngleInTabletModeRange() {
   return can_detect_lid_angle_ && !lid_is_closed_ &&
          lid_angle_ >= kEnterTabletModeAngle;
 }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.h b/ash/wm/tablet_mode/tablet_mode_controller.h
index a2d1425..48cea7c 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.h
+++ b/ash/wm/tablet_mode/tablet_mode_controller.h
@@ -95,17 +95,8 @@
   // async.
   static void SetForceNoScreenshotForTest();
 
-  // TODO(jonross): Merge this with AttemptEnterTabletMode. Currently these are
-  // separate for several reasons: there is no internal display when running
-  // unittests; the event blocker prevents keyboard input when running ChromeOS
-  // on linux. http://crbug.com/362881
-  // Turn the always tablet mode window manager on or off.
-  // TODO(xdai): Make it a private function. This function is not supposed to be
-  // called by an external caller except for tests.
-  void EnableTabletModeWindowManager(bool should_enable);
-
   // Test if the TabletModeWindowManager is enabled or not.
-  bool IsTabletModeWindowManagerEnabled() const;
+  bool InTabletMode() const;
 
   // Add a special window to the TabletModeWindowManager for tracking. This is
   // only required for special windows which are handled by other window
@@ -204,6 +195,13 @@
     kExitingTabletMode,
   };
 
+  // TODO(jonross): Merge this with AttemptEnterTabletMode. Currently these are
+  // separate for several reasons: there is no internal display when running
+  // unittests; the event blocker prevents keyboard input when running ChromeOS
+  // on linux. http://crbug.com/362881
+  // Turn the always tablet mode window manager on or off.
+  void SetTabletModeEnabledInternal(bool should_enable);
+
   // If EC cannot handle lid angle calc, browser detects hinge rotation from
   // base and lid accelerometers and automatically start / stop tablet mode.
   void HandleHingeRotation(scoped_refptr<const AccelerometerUpdate> update);
@@ -270,7 +268,7 @@
   // Returns true if the current lid angle can be detected and is in tablet mode
   // angle range. If EC can handle lid angle calc, lid angle is unavailable to
   // browser.
-  bool LidAngleIsInTabletModeRange();
+  bool LidAngleInTabletModeRange();
 
   // Suspends |occlusion_tracker_pauser_| for the duration of
   // kOcclusionTrackTimeout.
@@ -359,9 +357,6 @@
   // Counts of the tab drag from top when splitview is active.
   int tab_drag_in_splitview_count_ = 0;
 
-  // Tracks KioskNext state separately to simplify testing.
-  bool kiosk_next_enabled_ = false;
-
   // Tracks smoothed accelerometer data over time. This is done when the hinge
   // is approaching vertical to remove abrupt acceleration that can lead to
   // incorrect calculations of hinge angles.
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.h b/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
index 583bf3441..583357e 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
+++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
@@ -80,7 +80,7 @@
   }
 
   bool IsTabletModeStarted() const {
-    return tablet_mode_controller_->IsTabletModeWindowManagerEnabled();
+    return tablet_mode_controller_->InTabletMode();
   }
 
   bool AreEventsBlocked() const {
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index d0100eb..26725c3 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -199,18 +199,18 @@
   ASSERT_EQ(0, user_action_tester()->GetActionCount(kTabletModeDisabled));
 
   user_action_tester()->ResetCounts();
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(1, user_action_tester()->GetActionCount(kTabletModeEnabled));
   EXPECT_EQ(0, user_action_tester()->GetActionCount(kTabletModeDisabled));
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(1, user_action_tester()->GetActionCount(kTabletModeEnabled));
   EXPECT_EQ(0, user_action_tester()->GetActionCount(kTabletModeDisabled));
 
   user_action_tester()->ResetCounts();
-  tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(0, user_action_tester()->GetActionCount(kTabletModeEnabled));
   EXPECT_EQ(1, user_action_tester()->GetActionCount(kTabletModeDisabled));
-  tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(0, user_action_tester()->GetActionCount(kTabletModeEnabled));
   EXPECT_EQ(1, user_action_tester()->GetActionCount(kTabletModeDisabled));
 }
@@ -553,7 +553,7 @@
   ASSERT_NE(w1->GetRootWindow(), w2->GetRootWindow());
   ASSERT_FALSE(IsTabletModeStarted());
 
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(Shell::Get()->overview_controller()->ToggleOverview());
 
   UpdateDisplay("800x600");
@@ -681,23 +681,23 @@
 
 TEST_F(TabletModeControllerInitedFromPowerManagerClientTest,
        InitializedWhileTabletModeSwitchOn) {
-  EXPECT_FALSE(tablet_mode_controller()->IsTabletModeWindowManagerEnabled());
+  EXPECT_FALSE(tablet_mode_controller()->InTabletMode());
   // PowerManagerClient callback is a posted task.
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(tablet_mode_controller()->IsTabletModeWindowManagerEnabled());
+  EXPECT_TRUE(tablet_mode_controller()->InTabletMode());
 }
 
 TEST_F(TabletModeControllerTest, RestoreAfterExit) {
   UpdateDisplay("1000x600");
   std::unique_ptr<aura::Window> w1(
       CreateTestWindowInShellWithBounds(gfx::Rect(10, 10, 900, 300)));
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   Shell::Get()->screen_orientation_controller()->SetLockToRotation(
       display::Display::ROTATE_90);
   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
   EXPECT_EQ(display::Display::ROTATE_90, display.rotation());
   EXPECT_LT(display.size().width(), display.size().height());
-  tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  tablet_mode_controller()->SetEnabledForTest(false);
   display = display::Screen::GetScreen()->GetPrimaryDisplay();
   // Sanity checks.
   EXPECT_EQ(display::Display::ROTATE_0, display.rotation());
@@ -1136,7 +1136,7 @@
       Shell::Get()->split_view_controller();
   std::unique_ptr<aura::Window> window = CreateTestWindow();
   ::wm::ActivateWindow(window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
@@ -1148,7 +1148,7 @@
       Shell::Get()->split_view_controller();
   std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedLeft();
   ::wm::ActivateWindow(window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1161,7 +1161,7 @@
       Shell::Get()->split_view_controller();
   std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1177,7 +1177,7 @@
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(left_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
@@ -1194,7 +1194,7 @@
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(left_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
@@ -1214,7 +1214,7 @@
   std::unique_ptr<aura::Window> right_window =
       CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(left_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
@@ -1236,7 +1236,7 @@
       CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(right_window.get());
   ::wm::ActivateWindow(left_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1254,7 +1254,7 @@
   ::wm::AddTransientChild(parent.get(), child.get());
   ::wm::ActivateWindow(parent.get());
   ::wm::ActivateWindow(child.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(parent.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1271,7 +1271,7 @@
   Shell::Get()->app_list_controller()->ShowAppList();
   ASSERT_TRUE(::wm::IsActiveWindow(
       GetAppListTestHelper()->GetAppListView()->GetWidget()->GetNativeView()));
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1295,7 +1295,7 @@
       CreateDesktopWindowSnappedLeft();
   ::wm::ActivateWindow(snapped_window.get());
   ::wm::ActivateWindow(dragged_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1315,7 +1315,7 @@
       CreateDesktopWindowSnappedLeft();
   ::wm::ActivateWindow(snapped_window.get());
   ::wm::ActivateWindow(window_hidden_from_overview.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1345,7 +1345,7 @@
       CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(right_window.get());
   ::wm::ActivateWindow(left_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
@@ -1375,7 +1375,7 @@
   right_window_state->OnWMEvent(&snap_to_right);
   ::wm::ActivateWindow(left_window.get());
   ::wm::ActivateWindow(right_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
@@ -1406,7 +1406,7 @@
   right_window_state->OnWMEvent(&snap_to_right);
   ::wm::ActivateWindow(right_window.get());
   ::wm::ActivateWindow(left_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1437,7 +1437,7 @@
       CreateDesktopWindowSnappedRight();
   ::wm::ActivateWindow(left_window.get());
   ::wm::ActivateWindow(right_window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1450,7 +1450,7 @@
       Shell::Get()->app_list_controller();
   std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedLeft();
   ::wm::ActivateWindow(window.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   app_list_controller->ShowAppList();
   EXPECT_TRUE(app_list_controller->IsVisible());
 }
@@ -1465,7 +1465,7 @@
   std::unique_ptr<aura::Window> window1 = CreateDesktopWindowSnappedLeft();
   std::unique_ptr<aura::Window> window2 = CreateDesktopWindowSnappedLeft();
   ::wm::ActivateWindow(window1.get());
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
   EXPECT_EQ(window1.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1477,7 +1477,7 @@
        ProgrammaticallyStartSplitViewAndThenOverview) {
   SplitViewController* split_view_controller =
       Shell::Get()->split_view_controller();
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   std::unique_ptr<aura::Window> window = CreateTestWindow();
   ::wm::ActivateWindow(window.get());
   split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT);
@@ -1554,8 +1554,8 @@
     SCOPED_TRACE("No window");
     histogram_tester.ExpectTotalCount(kEnterHistogram, 0);
     histogram_tester.ExpectTotalCount(kExitHistogram, 0);
-    tablet_mode_controller()->EnableTabletModeWindowManager(true);
-    tablet_mode_controller()->EnableTabletModeWindowManager(false);
+    tablet_mode_controller()->SetEnabledForTest(true);
+    tablet_mode_controller()->SetEnabledForTest(false);
     histogram_tester.ExpectTotalCount(kEnterHistogram, 0);
     histogram_tester.ExpectTotalCount(kExitHistogram, 0);
   }
@@ -1568,11 +1568,11 @@
     SCOPED_TRACE("Window is maximized");
     wm::GetWindowState(window.get())->Maximize();
     window->layer()->GetAnimator()->StopAnimating();
-    tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    tablet_mode_controller()->SetEnabledForTest(true);
     EXPECT_FALSE(window->layer()->GetAnimator()->is_animating());
     histogram_tester.ExpectTotalCount(kEnterHistogram, 0);
     histogram_tester.ExpectTotalCount(kExitHistogram, 0);
-    tablet_mode_controller()->EnableTabletModeWindowManager(false);
+    tablet_mode_controller()->SetEnabledForTest(false);
     EXPECT_FALSE(window->layer()->GetAnimator()->is_animating());
     histogram_tester.ExpectTotalCount(kEnterHistogram, 0);
     histogram_tester.ExpectTotalCount(kExitHistogram, 0);
@@ -1592,7 +1592,7 @@
   // entering and exiting tablet mode with a normal window.
   ui::Layer* layer = window->layer();
   ui::Layer* layer2 = window2->layer();
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(window->layer()->GetAnimator()->is_animating());
   EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
   layer->GetAnimator()->StopAnimating();
@@ -1602,7 +1602,7 @@
 
   layer = window->layer();
   layer2 = window2->layer();
-  tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_TRUE(layer->GetAnimator()->is_animating());
   EXPECT_TRUE(layer2->GetAnimator()->is_animating());
   layer->GetAnimator()->StopAnimating();
@@ -1623,13 +1623,13 @@
   window2->layer()->GetAnimator()->StopAnimating();
 
   // Tests that we have no logged metrics since nothing animates.
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_FALSE(window->layer()->GetAnimator()->is_animating());
   EXPECT_FALSE(window2->layer()->GetAnimator()->is_animating());
   histogram_tester.ExpectTotalCount(kEnterHistogram, 0);
   histogram_tester.ExpectTotalCount(kExitHistogram, 0);
 
-  tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(window->layer()->GetAnimator()->is_animating());
   EXPECT_FALSE(window2->layer()->GetAnimator()->is_animating());
   window2->layer()->GetAnimator()->StopAnimating();
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index 8d4f61a..22455829 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -126,14 +126,13 @@
   // Create the tablet mode window manager.
   TabletModeWindowManager* CreateTabletModeWindowManager() {
     EXPECT_FALSE(TabletModeControllerTestApi().tablet_mode_window_manager());
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
     return TabletModeControllerTestApi().tablet_mode_window_manager();
   }
 
   // Destroy the tablet mode window manager.
   void DestroyTabletModeWindowManager() {
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
-        false);
+    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
     EXPECT_FALSE(TabletModeControllerTestApi().tablet_mode_window_manager());
   }
 
@@ -831,7 +830,7 @@
       CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
   wm::WindowState* window_state = wm::GetWindowState(window.get());
   EXPECT_EQ(rect.ToString(), window->bounds().ToString());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(window_state->IsMaximized());
   EXPECT_FALSE(window_state->IsMinimized());
   EXPECT_TRUE(window->IsVisible());
@@ -846,7 +845,7 @@
   EXPECT_FALSE(window_state->IsMinimized());
   EXPECT_TRUE(window->IsVisible());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(window_state->IsMaximized());
   EXPECT_FALSE(window_state->IsMinimized());
   EXPECT_TRUE(window->IsVisible());
@@ -861,9 +860,9 @@
   wm::WindowState* window_state = wm::GetWindowState(window.get());
   window_state->Minimize();
   EXPECT_TRUE(window_state->IsMinimized());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_TRUE(window_state->IsMinimized());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_TRUE(window_state->IsMinimized());
 
   window_state->Unminimize();
@@ -884,7 +883,7 @@
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
             window->GetProperty(aura::client::kPreMinimizedShowStateKey));
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   window_state->Unminimize();
   // Check that pre-minimized window show state is not cleared due to
   // unminimizing in tablet mode.
@@ -894,7 +893,7 @@
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
             window->GetProperty(aura::client::kPreMinimizedShowStateKey));
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   window_state->Unminimize();
   EXPECT_TRUE(window_state->IsMaximized());
 }
@@ -909,18 +908,18 @@
   wm::WindowState* window_state = wm::GetWindowState(window.get());
   window_state->Maximize();
   window_state->Minimize();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   window_state->Unminimize();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_TRUE(window_state->IsMaximized());
 
   // Tests restoring to normal show state.
   window_state->Restore();
   EXPECT_EQ(gfx::Rect(10, 10, 100, 100), window->GetBoundsInScreen());
   window_state->Minimize();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   window_state->Unminimize();
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_EQ(gfx::Rect(10, 10, 100, 100), window->GetBoundsInScreen());
 }
 
@@ -1278,7 +1277,7 @@
 
   // 2. Check that turning on the manager will stop allowing the window from
   // dragging.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   gfx::Rect center_bounds(window->bounds());
   EXPECT_NE(rect.origin().ToString(), center_bounds.origin().ToString());
   generator.MoveMouseTo(
@@ -1289,7 +1288,7 @@
   generator.ReleaseLeftButton();
   EXPECT_EQ(center_bounds.x(), window->bounds().x());
   EXPECT_EQ(center_bounds.y(), window->bounds().y());
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
 
   // 3. Releasing the mazimize manager again will restore the window to its
   // previous bounds and
@@ -1744,7 +1743,7 @@
 // Test that the restore state will be kept at its original value for
 // session restoration purposes.
 TEST_F(TabletModeWindowManagerTest, SetPropertyOnUnmanagedWindow) {
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   InitParams params(aura::client::WINDOW_TYPE_NORMAL);
   params.bounds = gfx::Rect(10, 10, 100, 100);
   params.show_on_creation = false;
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index 491dd17..4d5d9c7 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -68,9 +68,7 @@
 
 void ShowResizeShadow(aura::Window* window, int component) {
   // Window resize in tablet mode is disabled (except in splitscreen).
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     return;
   }
 
@@ -511,9 +509,7 @@
 
   aura::Window* toplevel = widget->GetNativeWindow();
 
-  if (!Shell::Get()
-           ->tablet_mode_controller()
-           ->IsTabletModeWindowManagerEnabled()) {
+  if (!Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     return nullptr;
   }
   wm::WindowState* window_state = wm::GetWindowState(toplevel);
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc
index da58ae2c..12db160 100644
--- a/ash/wm/window_animations.cc
+++ b/ash/wm/window_animations.cc
@@ -256,7 +256,7 @@
       Shell::Get()->tablet_mode_controller();
 
   if (home_screen_controller && tablet_mode_controller &&
-      tablet_mode_controller->IsTabletModeWindowManagerEnabled()) {
+      tablet_mode_controller->InTabletMode()) {
     // Slide down the window from above screen to show and, meanwhile, slide
     // down the home launcher off screen.
     HomeLauncherGestureHandler* handler =
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 972cd503..3d96729 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -51,9 +51,7 @@
 namespace {
 
 bool IsTabletModeEnabled() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+  return Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 bool IsToplevelContainer(aura::Window* window) {
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index 6cf7c08..4a17127 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -436,7 +436,7 @@
 
   // When entering tablet mode, the windows will be maximized, thus the resizer
   // widget should be dismissed.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   EXPECT_FALSE(IsShowing());
 }
 
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 232cfd1..a5c9746 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1806,7 +1806,7 @@
 // Test that backdrop works in split view mode.
 TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropForSplitScreenTest) {
   ShowTopWindowBackdropForContainer(default_container(), true);
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   class SplitViewTestWindowDelegate : public aura::test::TestWindowDelegate {
    public:
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index c45d7f9..25c072d5 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -148,9 +148,7 @@
     return std::make_unique<PipWindowResizer>(window_state);
   }
 
-  if (Shell::Get()
-          ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+  if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
     return CreateWindowResizerForTabletMode(window, point_in_parent,
                                             window_component, source);
   }
diff --git a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
index ab9437b3..3b0ffd2 100644
--- a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
+++ b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
@@ -45,7 +45,8 @@
     private static final String TRACE_CONFIG_FILENAME = "/data/local/chrome-trace-config.json";
 
     /** Single trace event. */
-    public static final class Event {
+    @VisibleForTesting
+    static final class Event {
         final String mName;
         final int mThreadId;
         final long mBeginTimeNanos;
@@ -53,14 +54,14 @@
         long mEndTimeNanos;
         long mEndThreadTimeMillis;
 
-        public Event(String name) {
+        Event(String name) {
             mName = name;
             mThreadId = Process.myTid();
             mBeginTimeNanos = elapsedRealtimeNanos();
             mBeginThreadTimeMillis = SystemClock.currentThreadTimeMillis();
         }
 
-        public void end() {
+        void end() {
             assert mEndTimeNanos == 0;
             assert mEndThreadTimeMillis == 0;
             mEndTimeNanos = elapsedRealtimeNanos();
@@ -252,15 +253,6 @@
         }
     }
 
-    /** Add events that were captured before {@link TraceEvent#maybeEnableEarlyTracing()}. */
-    public static void addEvent(Event e) {
-        if (!enabled()) return;
-        synchronized (sLock) {
-            if (!enabled()) return;
-            sCompletedEvents.add(e);
-        }
-    }
-
     /** @see {@link TraceEvent#startAsync()}. */
     public static void startAsync(String name, long id) {
         if (!enabled()) return;
diff --git a/base/android/jni_generator/AndroidManifest.xml b/base/android/jni_generator/AndroidManifest.xml
index 59a72d6..86fb52e 100644
--- a/base/android/jni_generator/AndroidManifest.xml
+++ b/base/android/jni_generator/AndroidManifest.xml
@@ -7,7 +7,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jni.generator">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />
     <application></application>
 
 </manifest>
diff --git a/base/android/jni_generator/BUILD.gn b/base/android/jni_generator/BUILD.gn
index 0f058501..1818271 100644
--- a/base/android/jni_generator/BUILD.gn
+++ b/base/android/jni_generator/BUILD.gn
@@ -65,6 +65,7 @@
 android_apk("sample_jni_apk") {
   apk_name = "SampleJni"
   android_manifest = "AndroidManifest.xml"
+  target_sdk_version = 24
   deps = [
     ":jni_sample_java",
     "//base:base_java",
diff --git a/base/fuchsia/startup_context.cc b/base/fuchsia/startup_context.cc
index 080a6c7..bf9f5cb 100644
--- a/base/fuchsia/startup_context.cc
+++ b/base/fuchsia/startup_context.cc
@@ -66,7 +66,11 @@
   }
 }
 
-StartupContext::~StartupContext() = default;
+StartupContext::~StartupContext() {
+  // |additional_services_directory_| needs to be empty for clean teardown.
+  if (additional_services_directory_)
+    additional_services_directory_->RemoveAllServices();
+}
 
 ServiceDirectory* StartupContext::public_services() {
   if (!public_services_ && startup_info_.launch_info.directory_request) {
diff --git a/base/run_loop_unittest.cc b/base/run_loop_unittest.cc
index d9832e4..03c20d46 100644
--- a/base/run_loop_unittest.cc
+++ b/base/run_loop_unittest.cc
@@ -309,7 +309,8 @@
   EXPECT_FALSE(task3_run);
 }
 
-TEST_P(RunLoopTest, NestedRunWithTimeout) {
+// TODO(https://crbug.com/970187): This test is inherently flaky.
+TEST_P(RunLoopTest, DISABLED_NestedRunWithTimeout) {
   // SimpleSingleThreadTaskRunner doesn't support delayed tasks.
   if (GetParam() == RunLoopTestType::kTestDelegate)
     return;
diff --git a/build/android/AndroidManifest.xml b/build/android/AndroidManifest.xml
index fe21b80b..d48afd8 100644
--- a/build/android/AndroidManifest.xml
+++ b/build/android/AndroidManifest.xml
@@ -9,12 +9,8 @@
   This is a dummy manifest which is required by:
   1. aapt when generating R.java in java.gypi:
      Nothing in the manifest is used, but it is still required by aapt.
-  2. lint: [min|target]SdkVersion are required by lint and should
-     be kept up to date.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.dummy">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24" />
-
 </manifest>
diff --git a/build/android/gradle/root.jinja b/build/android/gradle/root.jinja
index 513db63..3895fc43 100644
--- a/build/android/gradle/root.jinja
+++ b/build/android/gradle/root.jinja
@@ -10,7 +10,7 @@
     }
     dependencies {
 {% if channel == 'canary' %}
-        classpath "com.android.tools.build:gradle:3.6.0-alpha02"
+        classpath "com.android.tools.build:gradle:3.6.0-alpha03"
 {% elif channel == 'beta' %}
         classpath "com.android.tools.build:gradle:3.1.0-beta4"
 {% else %}
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index 5ab30e6e..df42af9 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -27,6 +27,8 @@
 from xml.etree import ElementTree
 
 from util import build_utils
+from util import diff_utils
+from util import manifest_utils
 from util import resource_utils
 
 # Name of environment variable that can be used to force this script to
@@ -67,6 +69,17 @@
       '--aapt2-path', required=True, help='Path to the Android aapt2 tool.')
   input_opts.add_argument(
       '--android-manifest', required=True, help='AndroidManifest.xml path.')
+  input_opts.add_argument(
+      '--android-manifest-expected',
+      help='Expected contents for the final manifest.')
+  input_opts.add_argument(
+      '--android-manifest-normalized', help='Normalized manifest.')
+  input_opts.add_argument(
+      '--fail-if-unexpected-android-manifest',
+      action='store_true',
+      help=
+      'Fail if expected manifest contents do not match final manifest contents.'
+  )
   group = input_opts.add_mutually_exclusive_group()
   group.add_argument(
       '--shared-resources',
@@ -132,6 +145,14 @@
 
   input_opts.add_argument('--version-code', help='Version code for apk.')
   input_opts.add_argument('--version-name', help='Version name for apk.')
+  input_opts.add_argument(
+      '--min-sdk-version', required=True, help='android:minSdkVersion for APK.')
+  input_opts.add_argument(
+      '--target-sdk-version',
+      required=True,
+      help="android:targetSdkVersion for APK.")
+  input_opts.add_argument(
+      '--max-sdk-version', help="android:maxSdkVersion for APK.")
 
   input_opts.add_argument(
       '--locale-whitelist',
@@ -435,9 +456,20 @@
   version_code, version_name = successful_extractions.pop()[:2]
 
   debug_manifest_path = os.path.join(temp_dir, 'AndroidManifest.xml')
-  doc, manifest_node, app_node = resource_utils.ParseAndroidManifest(
+  doc, manifest_node, app_node = manifest_utils.ParseManifest(
       options.android_manifest)
 
+  manifest_utils.AssertNoUsesSdk(manifest_node)
+
+  uses_sdk_attributes = [
+      ('android:minSdkVersion', options.min_sdk_version),
+      ('android:targetSdkVersion', options.target_sdk_version),
+  ]
+  if options.max_sdk_version:
+    uses_sdk_attributes += [('android:maxSdkVersion', options.max_sdk_version)]
+  uses_sdk_node = manifest_utils.MakeElement('uses-sdk', uses_sdk_attributes)
+  manifest_node.insert(0, uses_sdk_node)
+
   manifest_node.set('platformBuildVersionCode', version_code)
   manifest_node.set('platformBuildVersionName', version_name)
 
@@ -446,15 +478,28 @@
     manifest_node.set('package', options.arsc_package_name)
 
   if options.debuggable:
-    app_node.set('{%s}%s' % (resource_utils.ANDROID_NAMESPACE, 'debuggable'),
+    app_node.set('{%s}%s' % (manifest_utils.ANDROID_NAMESPACE, 'debuggable'),
                  'true')
 
-  with open(debug_manifest_path, 'w') as debug_manifest:
-    debug_manifest.write(ElementTree.tostring(doc.getroot(), encoding='UTF-8'))
-
+  manifest_utils.SaveManifest(doc, debug_manifest_path)
   return debug_manifest_path, orig_package
 
 
+def _VerifyManifest(actual_manifest, expected_manifest, normalized_manifest,
+                    fail_if_unexpected_manifest):
+  with build_utils.AtomicOutput(normalized_manifest) as normalized_output:
+    normalized_output.write(manifest_utils.NormalizeManifest(actual_manifest))
+  msg = diff_utils.DiffFileContents(expected_manifest, normalized_manifest)
+  if msg:
+    sys.stderr.write("""\
+AndroidManifest.xml expectations file needs updating. For details see:
+https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/java/README.md
+""")
+    sys.stderr.write(msg)
+    if fail_if_unexpected_manifest:
+      sys.exit(1)
+
+
 def _ResourceNameFromPath(path):
   return os.path.splitext(os.path.basename(path))[0]
 
@@ -682,6 +727,10 @@
       'link',
       '--auto-add-overlay',
       '--no-version-vectors',
+      '--min-sdk-version',
+      options.min_sdk_version,
+      '--target-sdk-version',
+      options.target_sdk_version,
   ]
 
   for j in options.include_resources:
@@ -717,6 +766,11 @@
       options, build.temp_dir)
   if options.rename_manifest_package:
     desired_manifest_package_name = options.rename_manifest_package
+  if options.android_manifest_expected:
+    _VerifyManifest(fixed_manifest, options.android_manifest_expected,
+                    options.android_manifest_normalized,
+                    options.fail_if_unexpected_android_manifest)
+
   link_command += [
       '--manifest', fixed_manifest, '--rename-manifest-package',
       desired_manifest_package_name
diff --git a/build/android/gyp/compile_resources.pydeps b/build/android/gyp/compile_resources.pydeps
index 2ffcb52..a6edc94 100644
--- a/build/android/gyp/compile_resources.pydeps
+++ b/build/android/gyp/compile_resources.pydeps
@@ -25,5 +25,7 @@
 compile_resources.py
 util/__init__.py
 util/build_utils.py
+util/diff_utils.py
+util/manifest_utils.py
 util/md5_check.py
 util/resource_utils.py
diff --git a/build/android/gyp/lint.py b/build/android/gyp/lint.py
index 77caf296..10c644b7 100755
--- a/build/android/gyp/lint.py
+++ b/build/android/gyp/lint.py
@@ -11,20 +11,36 @@
 import argparse
 import os
 import re
+import shutil
 import sys
 import traceback
 from xml.dom import minidom
 
 from util import build_utils
+from util import manifest_utils
 
 _LINT_MD_URL = 'https://chromium.googlesource.com/chromium/src/+/master/build/android/docs/lint.md' # pylint: disable=line-too-long
 
 
-def _OnStaleMd5(lint_path, config_path, processed_config_path,
-                manifest_path, result_path, product_dir, sources, jar_path,
-                cache_dir, android_sdk_version, srcjars, resource_sources,
-                disable=None, classpath=None, can_fail_build=False,
-                include_unexpected=False, silent=False):
+def _OnStaleMd5(lint_path,
+                config_path,
+                processed_config_path,
+                manifest_path,
+                result_path,
+                product_dir,
+                sources,
+                jar_path,
+                cache_dir,
+                android_sdk_version,
+                srcjars,
+                min_sdk_version,
+                resource_sources,
+                disable=None,
+                classpath=None,
+                can_fail_build=False,
+                include_unexpected=False,
+                silent=False):
+
   def _RebasePath(path):
     """Returns relative path to top-level src dir.
 
@@ -176,8 +192,24 @@
       manifest_path = os.path.join(
           build_utils.DIR_SOURCE_ROOT, 'build', 'android',
           'AndroidManifest.xml')
-    os.symlink(os.path.abspath(manifest_path),
-               os.path.join(project_dir, 'AndroidManifest.xml'))
+    lint_manifest_path = os.path.join(project_dir, 'AndroidManifest.xml')
+    shutil.copyfile(os.path.abspath(manifest_path), lint_manifest_path)
+
+    # Add the minSdkVersion to the manifest.
+    doc, manifest, _ = manifest_utils.ParseManifest(lint_manifest_path)
+    # TODO(crbug.com/891996): Only activate once downstream has been updated.
+    # manifest_utils.AssertNoUsesSdk(manifest)
+    if min_sdk_version:
+      # TODO(crbug.com/891996): Don't remove uses-sdk once downstream has been
+      # updated.
+      uses_sdk = manifest.find('./uses-sdk')
+      if uses_sdk is not None:
+        manifest.remove(uses_sdk)
+      uses_sdk = manifest_utils.MakeElement(
+          'uses-sdk', [('android:minSdkVersion', min_sdk_version)])
+      manifest.insert(0, uses_sdk)
+      manifest_utils.SaveManifest(doc, lint_manifest_path)
+
     cmd.append(project_dir)
 
     if os.path.exists(result_path):
@@ -309,6 +341,8 @@
                       help='Directories containing java files.')
   parser.add_argument('--srcjars',
                       help='GN list of included srcjars.')
+  parser.add_argument(
+      '--min-sdk-version', help='Minimal SDK version to lint against.')
 
   args = parser.parse_args(build_utils.ExpandFileArgs(sys.argv[1:]))
 
@@ -382,6 +416,7 @@
                           args.cache_dir,
                           args.android_sdk_version,
                           args.srcjars,
+                          args.min_sdk_version,
                           resource_sources,
                           disable=disable,
                           classpath=classpath,
diff --git a/build/android/gyp/lint.pydeps b/build/android/gyp/lint.pydeps
index a8616e4..49fbf17c 100644
--- a/build/android/gyp/lint.pydeps
+++ b/build/android/gyp/lint.pydeps
@@ -4,4 +4,5 @@
 lint.py
 util/__init__.py
 util/build_utils.py
+util/manifest_utils.py
 util/md5_check.py
diff --git a/build/android/gyp/merge_manifest.py b/build/android/gyp/merge_manifest.py
index 0637d43..4804148 100755
--- a/build/android/gyp/merge_manifest.py
+++ b/build/android/gyp/merge_manifest.py
@@ -9,14 +9,12 @@
 import argparse
 import contextlib
 import os
-import shlex
 import sys
 import tempfile
-import xml.dom.minidom as minidom
 import xml.etree.ElementTree as ElementTree
 
 from util import build_utils
-from util import diff_utils
+from util import manifest_utils
 
 # Tools library directory - relative to Android SDK root
 _SDK_TOOLS_LIB_DIR = os.path.join('tools', 'lib')
@@ -29,34 +27,21 @@
     'sdklib{suffix}.jar',
 ]
 
-_TOOLS_NAMESPACE_PREFIX = 'tools'
-_TOOLS_NAMESPACE = 'http://schemas.android.com/tools'
-_ANDROID_NAMESPACE = 'http://schemas.android.com/apk/res/android'
-
-# Without registering namespaces ElementTree converts them to "ns0" and "ns1"
-ElementTree.register_namespace('tools', _TOOLS_NAMESPACE)
-ElementTree.register_namespace('android', _ANDROID_NAMESPACE)
-
 
 @contextlib.contextmanager
-def _ProcessManifest(manifest_path):
+def _ProcessManifest(manifest_path, allow_uses_sdk):
   """Patches an Android manifest to always include the 'tools' namespace
   declaration, as it is not propagated by the manifest merger from the SDK.
 
   See https://issuetracker.google.com/issues/63411481
   """
-  doc = minidom.parse(manifest_path)
-  manifests = doc.getElementsByTagName('manifest')
-  assert len(manifests) == 1
-  manifest = manifests[0]
-  package = manifest.getAttribute('package')
-
-  manifest.setAttribute('xmlns:%s' % _TOOLS_NAMESPACE_PREFIX, _TOOLS_NAMESPACE)
-
+  doc, manifest, _ = manifest_utils.ParseManifest(manifest_path)
+  package = manifest_utils.GetPackage(manifest)
+  if not allow_uses_sdk:
+    manifest_utils.AssertNoUsesSdk(manifest)
   tmp_prefix = os.path.basename(manifest_path)
   with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest:
-    doc.writexml(patched_manifest)
-    patched_manifest.flush()
+    manifest_utils.SaveManifest(doc, patched_manifest.name)
     yield patched_manifest.name, package
 
 
@@ -69,39 +54,6 @@
   ])
 
 
-def _SortAndStripElementTree(tree, reverse_toplevel=False):
-  for node in tree:
-    if node.text and node.text.isspace():
-      node.text = None
-    _SortAndStripElementTree(node)
-  tree[:] = sorted(tree, key=ElementTree.tostring, reverse=reverse_toplevel)
-
-
-def _NormalizeManifest(path):
-  with open(path) as f:
-    # This also strips comments and sorts node attributes alphabetically.
-    root = ElementTree.fromstring(f.read())
-
-  # Sort nodes alphabetically, recursively.
-  _SortAndStripElementTree(root, reverse_toplevel=True)
-
-  # Fix up whitespace/indentation.
-  dom = minidom.parseString(ElementTree.tostring(root))
-  lines = []
-  for l in dom.toprettyxml(indent='  ').splitlines():
-    if l.strip():
-      if len(l) > 100:
-        indent = ' ' * l.find('<')
-        attributes = shlex.split(l, posix=False)
-        lines.append('{}{}'.format(indent, attributes[0]))
-        for attribute in attributes[1:]:
-          lines.append('{}    {}'.format(indent, attribute))
-      else:
-        lines.append(l)
-
-  return '\n'.join(lines)
-
-
 def main(argv):
   argv = build_utils.ExpandFileArgs(argv)
   parser = argparse.ArgumentParser(description=__doc__)
@@ -112,16 +64,22 @@
   parser.add_argument('--root-manifest',
                       help='Root manifest which to merge into',
                       required=True)
-  parser.add_argument(
-      '--expected-manifest', help='Expected contents for the merged manifest.')
-  parser.add_argument('--normalized-output', help='Normalized merged manifest.')
-  parser.add_argument(
-      '--verify-expected-manifest',
-      action='store_true',
-      help='Fail if expected contents do not match merged manifest contents.')
   parser.add_argument('--output', help='Output manifest path', required=True)
   parser.add_argument('--extras',
                       help='GN list of additional manifest to merge')
+  parser.add_argument(
+      '--min-sdk-version',
+      required=True,
+      help='android:minSdkVersion for merging.')
+  parser.add_argument(
+      '--target-sdk-version',
+      required=True,
+      help='android:targetSdkVersion for merging.')
+  parser.add_argument(
+      '--allow-uses-sdk',
+      action='store_true',
+      help='Use only for third party code. '
+      'Don\'t fail if input manifest contains a <uses-sdk> element.')
   args = parser.parse_args(argv)
 
   classpath = _BuildManifestMergerClasspath(
@@ -141,28 +99,36 @@
     if extras:
       cmd += ['--libs', ':'.join(extras)]
 
-    with _ProcessManifest(args.root_manifest) as tup:
+    with _ProcessManifest(args.root_manifest, args.allow_uses_sdk) as tup:
       root_manifest, package = tup
-      cmd += ['--main', root_manifest, '--property', 'PACKAGE=' + package]
+      cmd += [
+          '--main',
+          root_manifest,
+          '--property',
+          'PACKAGE=' + package,
+          '--property',
+          'MIN_SDK_VERSION=' + args.min_sdk_version,
+          '--property',
+          'TARGET_SDK_VERSION=' + args.target_sdk_version,
+      ]
       build_utils.CheckOutput(cmd,
         # https://issuetracker.google.com/issues/63514300:
         # The merger doesn't set a nonzero exit code for failures.
         fail_func=lambda returncode, stderr: returncode != 0 or
           build_utils.IsTimeStale(output.name, [root_manifest] + extras))
 
-  if args.expected_manifest:
-    with build_utils.AtomicOutput(args.normalized_output) as normalized_output:
-      normalized_output.write(_NormalizeManifest(args.output))
-    msg = diff_utils.DiffFileContents(args.expected_manifest,
-                                      args.normalized_output)
-    if msg:
-      sys.stderr.write("""\
-AndroidManifest.xml expectations file needs updating. For details see:
-https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/java/README.md
-""")
-      sys.stderr.write(msg)
-      if args.verify_expected_manifest:
-        sys.exit(1)
+    # Subsequent build system steps expect uses-sdk tag does not exist.
+    # Therefore, check it has the expected attribute values and remove it.
+    doc, manifest, _ = manifest_utils.ParseManifest(output.name)
+    uses_sdk = manifest.find('./uses-sdk')
+    assert uses_sdk.get(
+        '{%s}minSdkVersion' %
+        manifest_utils.ANDROID_NAMESPACE) == args.min_sdk_version
+    assert uses_sdk.get(
+        '{%s}targetSdkVersion' %
+        manifest_utils.ANDROID_NAMESPACE) == args.target_sdk_version
+    manifest.remove(uses_sdk)
+    manifest_utils.SaveManifest(doc, output.name)
 
   if args.depfile:
     inputs = extras + classpath.split(':')
diff --git a/build/android/gyp/merge_manifest.pydeps b/build/android/gyp/merge_manifest.pydeps
index 797cd5fb..772d2ce 100644
--- a/build/android/gyp/merge_manifest.pydeps
+++ b/build/android/gyp/merge_manifest.pydeps
@@ -4,5 +4,5 @@
 merge_manifest.py
 util/__init__.py
 util/build_utils.py
-util/diff_utils.py
+util/manifest_utils.py
 util/md5_check.py
diff --git a/build/android/gyp/prepare_resources.py b/build/android/gyp/prepare_resources.py
index 4f5ab17..6147f1a0 100755
--- a/build/android/gyp/prepare_resources.py
+++ b/build/android/gyp/prepare_resources.py
@@ -15,6 +15,7 @@
 import sys
 
 from util import build_utils
+from util import manifest_utils
 from util import resource_utils
 
 _AAPT_IGNORE_PATTERN = ':'.join([
@@ -131,14 +132,16 @@
   """
   # NOTE: This uses aapt rather than aapt2 because 'aapt2 compile' does not
   # support the --output-text-symbols option yet (https://crbug.com/820460).
-  package_command = [options.aapt_path,
-                     'package',
-                     '-m',
-                     '-M', resource_utils.EMPTY_ANDROID_MANIFEST_PATH,
-                     '--no-crunch',
-                     '--auto-add-overlay',
-                     '--no-version-vectors',
-                    ]
+  package_command = [
+      options.aapt_path,
+      'package',
+      '-m',
+      '-M',
+      manifest_utils.EMPTY_ANDROID_MANIFEST_PATH,
+      '--no-crunch',
+      '--auto-add-overlay',
+      '--no-version-vectors',
+  ]
   for j in options.include_resources:
     package_command += ['-I', j]
 
@@ -209,8 +212,9 @@
     if options.srcjar_out:
       package = options.custom_package
       if not package and options.android_manifest:
-        package = resource_utils.ExtractPackageFromManifest(
+        _, manifest_node, _ = manifest_utils.ParseManifest(
             options.android_manifest)
+        package = manifest_utils.GetPackage(manifest_node)
 
       # Don't create a .java file for the current resource target when no
       # package name was provided (either by manifest or build rules).
diff --git a/build/android/gyp/prepare_resources.pydeps b/build/android/gyp/prepare_resources.pydeps
index 8fce876d..8c65cf9 100644
--- a/build/android/gyp/prepare_resources.pydeps
+++ b/build/android/gyp/prepare_resources.pydeps
@@ -25,5 +25,6 @@
 prepare_resources.py
 util/__init__.py
 util/build_utils.py
+util/manifest_utils.py
 util/md5_check.py
 util/resource_utils.py
diff --git a/build/android/gyp/util/manifest_utils.py b/build/android/gyp/util/manifest_utils.py
new file mode 100644
index 0000000..4171d3d
--- /dev/null
+++ b/build/android/gyp/util/manifest_utils.py
@@ -0,0 +1,115 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Contains common helpers for working with Android manifests."""
+
+import os
+import shlex
+import xml.dom.minidom as minidom
+
+from util import build_utils
+from xml.etree import ElementTree
+
+ANDROID_NAMESPACE = 'http://schemas.android.com/apk/res/android'
+TOOLS_NAMESPACE = 'http://schemas.android.com/tools'
+DIST_NAMESPACE = 'http://schemas.android.com/apk/distribution'
+EMPTY_ANDROID_MANIFEST_PATH = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..', '..', 'AndroidManifest.xml'))
+
+_xml_namespace_initialized = False
+
+
+def _RegisterElementTreeNamespaces():
+  global _xml_namespace_initialized
+  if _xml_namespace_initialized:
+    return
+  _xml_namespace_initialized = True
+  ElementTree.register_namespace('android', ANDROID_NAMESPACE)
+  ElementTree.register_namespace('tools', TOOLS_NAMESPACE)
+  ElementTree.register_namespace('dist', DIST_NAMESPACE)
+
+
+def ParseManifest(path):
+  """Parses an AndroidManifest.xml using ElementTree.
+
+  Registers required namespaces, creates application node if missing, adds any
+  missing namespaces for 'android', 'tools' and 'dist'.
+
+  Returns tuple of:
+    doc: Root xml document.
+    manifest_node: the <manifest> node.
+    app_node: the <application> node.
+  """
+  _RegisterElementTreeNamespaces()
+  doc = ElementTree.parse(path)
+  # ElementTree.find does not work if the required tag is the root.
+  if doc.getroot().tag == 'manifest':
+    manifest_node = doc.getroot()
+  else:
+    manifest_node = doc.find('manifest')
+
+  app_node = doc.find('application')
+  if app_node is None:
+    app_node = ElementTree.SubElement(manifest_node, 'application')
+
+  return doc, manifest_node, app_node
+
+
+def MakeElement(name, attributes=None):
+  _RegisterElementTreeNamespaces()
+  element = ElementTree.Element(name)
+  if attributes:
+    for attribute_name, attribute_val in attributes:
+      if attribute_name.startswith('android:'):
+        attribute_name = '{%s}%s' % (
+            ANDROID_NAMESPACE, attribute_name[attribute_name.find(':') + 1:])
+      element.set(attribute_name, attribute_val)
+  return element
+
+
+def SaveManifest(doc, path):
+  with build_utils.AtomicOutput(path) as f:
+    f.write(ElementTree.tostring(doc.getroot(), encoding='UTF-8'))
+
+
+def GetPackage(manifest_node):
+  return manifest_node.get('package')
+
+
+def AssertNoUsesSdk(manifest_node):
+  """Asserts that manifest has no <uses-sdk> element."""
+  assert manifest_node.find('./uses-sdk') is None, 'Must define uses-sdk in GN'
+
+
+def _SortAndStripElementTree(tree, reverse_toplevel=False):
+  for node in tree:
+    if node.text and node.text.isspace():
+      node.text = None
+    _SortAndStripElementTree(node)
+  tree[:] = sorted(tree, key=ElementTree.tostring, reverse=reverse_toplevel)
+
+
+def NormalizeManifest(path):
+  with open(path) as f:
+    # This also strips comments and sorts node attributes alphabetically.
+    root = ElementTree.fromstring(f.read())
+
+  # Sort nodes alphabetically, recursively.
+  _SortAndStripElementTree(root, reverse_toplevel=True)
+
+  # Fix up whitespace/indentation.
+  dom = minidom.parseString(ElementTree.tostring(root))
+  lines = []
+  for l in dom.toprettyxml(indent='  ').splitlines():
+    if l.strip():
+      if len(l) > 100:
+        indent = ' ' * l.find('<')
+        attributes = shlex.split(l, posix=False)
+        lines.append('{}{}'.format(indent, attributes[0]))
+        for attribute in attributes[1:]:
+          lines.append('{}    {}'.format(indent, attribute))
+      else:
+        lines.append(l)
+
+  return '\n'.join(lines)
diff --git a/build/android/gyp/util/resource_utils.py b/build/android/gyp/util/resource_utils.py
index c356994..002f582a 100644
--- a/build/android/gyp/util/resource_utils.py
+++ b/build/android/gyp/util/resource_utils.py
@@ -21,11 +21,6 @@
 sys.path.insert(1, os.path.join(_SOURCE_ROOT, 'third_party'))
 from jinja2 import Template # pylint: disable=F0401
 
-EMPTY_ANDROID_MANIFEST_PATH = os.path.join(
-    _SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml')
-
-ANDROID_NAMESPACE = 'http://schemas.android.com/apk/res/android'
-TOOLS_NAMESPACE = 'http://schemas.android.com/tools'
 
 # A variation of these maps also exists in:
 # //base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -46,9 +41,6 @@
 }
 
 
-_xml_namespace_initialized = False
-
-
 def ToAndroidLocaleName(chromium_locale):
   """Convert an Chromium locale name into a corresponding Android one."""
   # First handle the special cases, these are needed to deal with Android
@@ -596,11 +588,6 @@
       parent_path=dep_path)
 
 
-def ExtractPackageFromManifest(manifest_path):
-  """Extract package name from Android manifest file."""
-  return ParseAndroidManifest(manifest_path)[1].get('package')
-
-
 def ExtractBinaryManifestValues(aapt2_path, apk_path):
   """Returns (version_code, version_name, package_name) for the given apk."""
   output = subprocess.check_output([
@@ -890,36 +877,3 @@
     new_xml_data = GenerateAndroidResourceStringsXml(strings_map, namespaces)
     with open(xml_file_path, 'wb') as f:
       f.write(new_xml_data)
-
-
-def _RegisterElementTreeNamespaces():
-  global _xml_namespace_initialized
-  if not _xml_namespace_initialized:
-    _xml_namespace_initialized = True
-    ElementTree.register_namespace('android', ANDROID_NAMESPACE)
-    ElementTree.register_namespace('tools', TOOLS_NAMESPACE)
-
-
-def ParseAndroidManifest(path):
-  """Parses an AndroidManifest.xml using ElementTree.
-
-  Registers required namespaces & creates application node if missing.
-
-  Returns tuple of:
-    doc: Root xml document.
-    manifest_node: the <manifest> node.
-    app_node: the <application> node.
-  """
-  _RegisterElementTreeNamespaces()
-  doc = ElementTree.parse(path)
-  # ElementTree.find does not work if the required tag is the root.
-  if doc.getroot().tag == 'manifest':
-    manifest_node = doc.getroot()
-  else:
-    manifest_node = doc.find('manifest')
-
-  app_node = doc.find('application')
-  if app_node is None:
-    app_node = ElementTree.SubElement(manifest_node, 'application')
-
-  return doc, manifest_node, app_node
diff --git a/build/android/incremental_install/generate_android_manifest.py b/build/android/incremental_install/generate_android_manifest.py
index bf38f4e..48dcc997 100755
--- a/build/android/incremental_install/generate_android_manifest.py
+++ b/build/android/incremental_install/generate_android_manifest.py
@@ -19,6 +19,7 @@
 
 sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir, 'gyp'))
 from util import build_utils
+from util import manifest_utils
 from util import resource_utils
 
 _INCREMENTAL_APP_NAME = 'org.chromium.incrementalinstall.BootstrapApplication'
@@ -36,7 +37,7 @@
 
 def _AddNamespace(name):
   """Adds the android namespace prefix to the given identifier."""
-  return '{%s}%s' % (resource_utils.ANDROID_NAMESPACE, name)
+  return '{%s}%s' % (manifest_utils.ANDROID_NAMESPACE, name)
 
 
 def _ParseArgs(args):
@@ -68,7 +69,7 @@
 
 
 def _ProcessManifest(path, arsc_package_name, disable_isolated_processes):
-  doc, manifest_node, app_node = resource_utils.ParseAndroidManifest(path)
+  doc, manifest_node, app_node = manifest_utils.ParseManifest(path)
 
   # Ensure the manifest package matches that of the apk's arsc package
   # So that resource references resolve correctly. The actual manifest
diff --git a/build/android/incremental_install/generate_android_manifest.pydeps b/build/android/incremental_install/generate_android_manifest.pydeps
index 21b49c6f..6b487b9 100644
--- a/build/android/incremental_install/generate_android_manifest.pydeps
+++ b/build/android/incremental_install/generate_android_manifest.pydeps
@@ -24,6 +24,7 @@
 ../../gn_helpers.py
 ../gyp/util/__init__.py
 ../gyp/util/build_utils.py
+../gyp/util/manifest_utils.py
 ../gyp/util/md5_check.py
 ../gyp/util/resource_utils.py
 generate_android_manifest.py
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 233e8b0e..ba473c7 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -36,6 +36,13 @@
     ]
   }
 
+  if (current_cpu == "x86") {
+    cflags += [
+      # Forces same alignment between x86 and x64. https://crbug.com/781095
+      "-malign-double",
+    ]
+  }
+
   ldflags = [
     # Don't allow visible symbols from libgcc or libc++ to be
     # re-exported.
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index d3f311c..254e2e8 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -924,6 +924,10 @@
           ]
         }
       }
+
+      if (defined(invoker.min_sdk_version)) {
+        args += [ "--min-sdk-version=${invoker.min_sdk_version}" ]
+      }
     }
   }
 
@@ -1768,21 +1772,14 @@
         rebase_path(invoker.output_manifest, root_build_dir),
         "--extras",
         "@FileArg($_rebased_build_config:extra_android_manifests)",
+        "--min-sdk-version=${invoker.min_sdk_version}",
+        "--target-sdk-version=${invoker.target_sdk_version}",
       ]
 
-      if (defined(invoker.expected_manifest)) {
-        inputs += [ invoker.expected_manifest ]
-        _normalized_output = "${invoker.output_manifest}.normalized"
-        outputs += [ _normalized_output ]
-        args += [
-          "--expected-manifest",
-          rebase_path(invoker.expected_manifest, root_build_dir),
-          "--normalized-output",
-          rebase_path(_normalized_output, root_build_dir),
-        ]
-        if (check_android_configuration) {
-          args += [ "--verify-expected-manifest" ]
-        }
+      # TODO(crbug.com/891996): Only activate for non-Chromium code once
+      # downstream has been updated.
+      if ((defined(invoker.chromium_code) && !invoker.chromium_code) || true) {
+        args += [ "--allow-uses-sdk" ]
       }
     }
   }
@@ -2136,6 +2133,8 @@
         "--dependencies-res-zips=@FileArg($_rebased_build_config:resources:dependency_zips)",
         "--extra-res-packages=@FileArg($_rebased_build_config:resources:extra_package_names)",
         "--extra-r-text-files=@FileArg($_rebased_build_config:resources:extra_r_text_files)",
+        "--min-sdk-version=${invoker.min_sdk_version}",
+        "--target-sdk-version=${invoker.target_sdk_version}",
       ]
 
       inputs += [ invoker.android_manifest ]
@@ -2352,6 +2351,24 @@
         args += [ "--use-resource-ids-path=$_rebased_ids_path" ]
         deps += [ _compile_res_dep ]
       }
+      if (defined(invoker.max_sdk_version)) {
+        _max_sdk_version = invoker.max_sdk_version
+        args += [ "--max-sdk-version=$_max_sdk_version" ]
+      }
+      if (defined(invoker.expected_manifest)) {
+        inputs += [ invoker.expected_manifest ]
+        _normalized_output = "${invoker.android_manifest}.normalized"
+        outputs += [ _normalized_output ]
+        args += [
+          "--android-manifest-expected",
+          rebase_path(invoker.expected_manifest, root_build_dir),
+          "--android-manifest-normalized",
+          rebase_path(_normalized_output, root_build_dir),
+        ]
+        if (check_android_configuration) {
+          args += [ "--fail-if-unexpected-android-manifest" ]
+        }
+      }
     }
 
     if (defined(invoker.post_process_script)) {
@@ -3090,6 +3107,8 @@
   #    from the final .jar file.
   #  jar_included_patterns: Optional list of .class file patterns to include
   #    in the final .jar file. jar_excluded_patterns take precedence over this.
+  #  min_sdk_version: Optional. The minimum Android SDK version this target
+  #    supports.
   #
   # For 'android_apk' and 'android_app_bundle_module' targets only:
   #
@@ -3432,6 +3451,9 @@
     # TODO(agrieve): Enable lint for _has_sources rather than just _java_files.
     _lint_enabled = _java_files != [] && _supports_android && _chromium_code &&
                     !disable_android_lint
+    if (!_lint_enabled && defined(invoker.min_sdk_version)) {
+      not_needed(invoker, [ "min_sdk_version" ])
+    }
     if (defined(invoker.enable_errorprone)) {
       _enable_errorprone = invoker.enable_errorprone
     } else {
@@ -3502,6 +3524,7 @@
       if (_lint_enabled) {
         _android_lint_target = "${_main_target_name}__lint"
         android_lint(_android_lint_target) {
+          forward_variables_from(invoker, [ "min_sdk_version" ])
           if (invoker.type == "android_apk" ||
               invoker.type == "android_app_bundle_module") {
             forward_variables_from(invoker, [ "android_manifest" ])
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 1c22933..83c0326 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1352,6 +1352,8 @@
         android_manifest = "//build/android/AndroidManifest.xml"
       }
       arsc_output = _resource_arsc_output
+      min_sdk_version = 19
+      target_sdk_version = 23
     }
 
     _jni_srcjar_target = "${target_name}__final_jni"
@@ -1830,6 +1832,9 @@
 
       supports_android = true
       requires_android = true
+      if (!defined(invoker.min_sdk_version)) {
+        min_sdk_version = 19
+      }
 
       if (!defined(jar_excluded_patterns)) {
         jar_excluded_patterns = []
@@ -1948,7 +1953,9 @@
   # Android APK or an Android app bundle module.
   #
   # Supports all variables of android_library(), plus:
-  #   android_manifest: Path to AndroidManifest.xml.
+  #   android_manifest: Path to AndroidManifest.xml. NOTE: This manifest must
+  #     not contain a <uses-sdk> element. Use [min|target|max]_sdk_version
+  #     instead.
   #   android_manifest_dep: Target that generates AndroidManifest (if applicable)
   #   png_to_webp: If true, pngs (with the exception of 9-patch) are
   #     converted to webp during resource packaging.
@@ -2030,6 +2037,12 @@
   #     use as a static library APK. When proguard is enabled, the
   #     static_library_provider target will provide the dex file(s) for this
   #     target.
+  #   min_sdk_version: The minimum Android SDK version this target supports.
+  #     Optional, default 19.
+  #   target_sdk_version: The target Android SDK version for this target.
+  #     Optional, default 23.
+  #   max_sdk_version: The maximum Android SDK version this target supports.
+  #     Optional, default not set.
   template("android_apk_or_module") {
     forward_variables_from(invoker, [ "testonly" ])
     assert(defined(invoker.final_apk_path) || defined(invoker.name))
@@ -2039,8 +2052,14 @@
     _build_config = "$target_gen_dir/$target_name.build_config"
     _build_config_target = "$target_name$build_config_target_suffix"
 
-    # Mark as used
-    assert(!defined(invoker.min_sdk_version) || invoker.min_sdk_version != 0)
+    _min_sdk_version = 19
+    _target_sdk_version = 23
+    if (defined(invoker.min_sdk_version)) {
+      _min_sdk_version = invoker.min_sdk_version
+    }
+    if (defined(invoker.target_sdk_version)) {
+      _target_sdk_version = invoker.target_sdk_version
+    }
 
     # JUnit tests use resource zip files. These must not be put in gen/
     # directory or they will not be available to tester bots.
@@ -2294,15 +2313,12 @@
         "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml"
     _merge_manifest_target = "${_template_name}__merge_manifests"
     merge_manifests(_merge_manifest_target) {
+      forward_variables_from(invoker, [ "chromium_code" ])
       input_manifest = _android_root_manifest
       output_manifest = _android_manifest
       build_config = _build_config
-      if (defined(invoker.verify_manifest) && invoker.verify_manifest &&
-          !is_java_debug) {
-        _target_src_dir = get_label_info(":$target_name", "dir")
-        expected_manifest =
-            "$_target_src_dir/java/$_template_name.AndroidManifest.expected"
-      }
+      min_sdk_version = _min_sdk_version
+      target_sdk_version = _target_sdk_version
       deps = _android_root_manifest_deps + [ ":$_build_config_target" ]
     }
 
@@ -2356,6 +2372,7 @@
                              [
                                "aapt_locale_whitelist",
                                "app_as_shared_lib",
+                               "max_sdk_version",
                                "no_xml_namespaces",
                                "package_name",
                                "package_name_to_id_mapping",
@@ -2364,14 +2381,22 @@
                                "resource_blacklist_regex",
                                "resources_config_path",
                                "shared_resources",
+                               "shared_resources_whitelist_locales",
                                "short_resource_paths",
                                "strip_resource_names",
-                               "shared_resources_whitelist_locales",
                                "support_zh_hk",
                              ])
       android_manifest = _android_manifest
       version_code = _version_code
       version_name = _version_name
+      min_sdk_version = _min_sdk_version
+      target_sdk_version = _target_sdk_version
+      if (defined(invoker.verify_manifest) && invoker.verify_manifest &&
+          !is_java_debug) {
+        _target_src_dir = get_label_info(":$target_name", "dir")
+        expected_manifest =
+            "$_target_src_dir/java/$_template_name.AndroidManifest.expected"
+      }
 
       if (defined(_resource_ids_provider_dep)) {
         resource_ids_provider_dep = _resource_ids_provider_dep
@@ -2688,6 +2713,7 @@
       main_target_name = _template_name
       supports_android = true
       requires_android = true
+      min_sdk_version = _min_sdk_version
       deps = _deps
 
       srcjar_deps = _srcjar_deps
@@ -3253,13 +3279,13 @@
                                "dexlayout_profile",
                                "dist_ijar_path",
                                "dont_load_shared_libraries",
-                               "jacoco_never_instrument",
                                "enable_chromium_linker_tests",
                                "enable_multidex",
                                "final_apk_path",
                                "generate_buildconfig_java",
                                "generate_final_jni",
                                "input_jars_paths",
+                               "jacoco_never_instrument",
                                "java_files",
                                "javac_args",
                                "jni_registration_header",
@@ -3269,6 +3295,7 @@
                                "keystore_path",
                                "load_library_from_apk",
                                "loadable_modules",
+                               "max_sdk_version",
                                "min_sdk_version",
                                "native_lib_placeholders",
                                "native_lib_version_arg",
@@ -3277,15 +3304,14 @@
                                "never_incremental",
                                "no_build_hooks",
                                "no_xml_namespaces",
-                               "strip_resource_names",
                                "png_to_webp",
                                "post_process_package_resources_script",
                                "product_version_resources_dep",
                                "proguard_configs",
                                "proguard_enabled",
                                "proguard_jar_path",
-                               "resource_blacklist_regex",
                                "resource_blacklist_exceptions",
+                               "resource_blacklist_regex",
                                "resource_ids_provider_dep",
                                "resources_config_path",
                                "secondary_abi_loadable_modules",
@@ -3299,10 +3325,12 @@
                                "srcjar_deps",
                                "static_library_dependent_targets",
                                "static_library_provider",
+                               "strip_resource_names",
                                "support_zh_hk",
+                               "target_sdk_version",
                                "testonly",
-                               "uncompress_shared_libraries",
                                "uncompress_dex",
+                               "uncompress_shared_libraries",
                                "use_chromium_linker",
                                "version_code",
                                "version_name",
@@ -3372,19 +3400,20 @@
                                "data",
                                "data_deps",
                                "deps",
-                               "jacoco_never_instrument",
                                "enable_chromium_linker_tests",
+                               "enable_class_deps_output",
                                "enable_multidex",
                                "generate_buildconfig_java",
                                "generate_final_jni",
-                               "enable_class_deps_output",
                                "input_jars_paths",
                                "is_base_module",
+                               "jacoco_never_instrument",
                                "java_files",
                                "javac_args",
                                "jni_registration_header",
                                "jni_sources_blacklist",
                                "load_library_from_apk",
+                               "max_sdk_version",
                                "min_sdk_version",
                                "native_lib_version_arg",
                                "native_lib_version_rule",
@@ -3406,11 +3435,12 @@
                                "shared_resources",
                                "shared_resources_whitelist_locales",
                                "shared_resources_whitelist_target",
-                               "strip_resource_names",
                                "short_resource_paths",
                                "srcjar_deps",
                                "static_library_provider",
+                               "strip_resource_names",
                                "support_zh_hk",
+                               "target_sdk_version",
                                "testonly",
                                "uncompress_shared_libraries",
                                "use_chromium_linker",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 72cea8e..e50ac81 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -658,9 +658,9 @@
   if (compiler_timing) {
     if (is_clang) {
       if (is_win) {
-        cflags += [ "/clang:-ftime-report" ]
+        cflags += [ "/clang:-ftime-trace" ]
       } else {
-        cflags += [ "-ftime-report" ]
+        cflags += [ "-ftime-trace" ]
       }
     } else if (is_win) {
       cflags += [
@@ -1092,7 +1092,8 @@
   }
 
   # Makes builds independent of absolute file path.
-  if (symbol_level != 0 && is_clang && strip_absolute_paths_from_debug_symbols) {
+  if (symbol_level != 0 && is_clang &&
+      strip_absolute_paths_from_debug_symbols) {
     # If debug option is given, clang includes $cwd in debug info by default.
     # For such build, this flag generates reproducible obj files even we use
     # different build directory like "out/feature_a" and "out/feature_b" if
diff --git a/build/config/fuchsia/package.gni b/build/config/fuchsia/package.gni
index 55b43c0..dcea6cda 100644
--- a/build/config/fuchsia/package.gni
+++ b/build/config/fuchsia/package.gni
@@ -40,14 +40,12 @@
   _archive_manifest = "$_pkg_out_dir/${pkg.package_name}.archive_manifest"
   _build_ids_file = "$_pkg_out_dir/ids.txt"
   _component_manifest = "$_pkg_out_dir/${pkg.package_name}.cmx"
-  _key_file = "$_pkg_out_dir/signing-key"
   _meta_far_file = "$_pkg_out_dir/meta.far"
   _combined_far_file = "$_pkg_out_dir/${pkg.package_name}-0.far"
   _final_far_file = "$_pkg_out_dir/${pkg.package_name}.far"
   _package_info_path = "$_pkg_out_dir/package"
 
   _write_manifest_target = "${pkg.package_name}__write_manifest"
-  _generate_key_target = "${pkg.package_name}__genkey"
   _package_target = "${pkg.package_name}__pkg"
   _bundle_target = "${pkg.package_name}__bundle"
 
@@ -118,29 +116,6 @@
     write_runtime_deps = _runtime_deps_file
   }
 
-  # Generates a signing key to use for building the package.
-  action(_generate_key_target) {
-    forward_variables_from(invoker, [ "testonly" ])
-
-    script = "//build/gn_run_binary.py"
-
-    inputs = [
-      # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
-      "${fuchsia_sdk}/.hash",
-    ]
-
-    outputs = [
-      _key_file,
-    ]
-
-    args = [
-      rebase_path(_pm_tool_path, root_build_dir),
-      "-k",
-      rebase_path(_key_file, root_build_dir),
-      "genkey",
-    ]
-  }
-
   # Creates a signed Fuchsia metadata package.
   action(_package_target) {
     forward_variables_from(invoker, [ "testonly" ])
@@ -148,14 +123,12 @@
     script = "//build/gn_run_binary.py"
 
     deps = [
-      ":$_generate_key_target",
       ":$_write_manifest_target",
     ]
 
     inputs = [
       # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
       "${fuchsia_sdk}/.hash",
-      _key_file,
     ]
 
     outputs = [
@@ -166,8 +139,6 @@
       rebase_path(_pm_tool_path, root_build_dir),
       "-o",
       rebase_path(_pkg_out_dir, root_build_dir),
-      "-k",
-      rebase_path(_key_file, root_build_dir),
       "-m",
       rebase_path(_archive_manifest, root_build_dir),
       "build",
diff --git a/build/sanitizers/lsan_suppressions.cc b/build/sanitizers/lsan_suppressions.cc
index 9653180..fbd9b40 100644
--- a/build/sanitizers/lsan_suppressions.cc
+++ b/build/sanitizers/lsan_suppressions.cc
@@ -21,7 +21,6 @@
 
     // False positives in libfontconfig. http://crbug.com/39050
     "leak:libfontconfig\n"
-    "leak:third_party/fontconfig/*\n"
     // eglibc-2.19/string/strdup.c creates false positive leak errors because of
     // the same reason as crbug.com/39050. The leak error stack trace, when
     // unwind on malloc, includes a call to libfontconfig. But the default stack
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 3dd5442..6f0dec36 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -34,11 +34,6 @@
     // [test-only]. http://crbug.com/927330.
     "race:content/browser/net_info_browsertest.cc\n"
 
-    // http://crbug.com/84094.
-    "race:sqlite3StatusSet\n"
-    "race:pcache1EnforceMaxPage\n"
-    "race:pcache1AllocPage\n"
-
     // http://crbug.com/120808
     "race:base/threading/watchdog.cc\n"
 
diff --git a/buildtools/DEPS b/buildtools/DEPS
index d7a54d4..4b944b9 100644
--- a/buildtools/DEPS
+++ b/buildtools/DEPS
@@ -14,7 +14,7 @@
   #
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:8c7f49102234f4f4b9349dcb258554675475e596',
+  'gn_version': 'git_revision:81ee1967d3fcbc829bac1c005c3da59739c88df9',
 
   # When changing these, also update the svn revisions in deps_revisions.gni
   'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
diff --git a/cc/test/pixel_test_output_surface.cc b/cc/test/pixel_test_output_surface.cc
index f961843..1c16562a 100644
--- a/cc/test/pixel_test_output_surface.cc
+++ b/cc/test/pixel_test_output_surface.cc
@@ -82,11 +82,6 @@
       gfx::PresentationFeedback(base::TimeTicks::Now(), base::TimeDelta(), 0));
 }
 
-std::unique_ptr<viz::OverlayCandidateValidator>
-PixelTestOutputSurface::TakeOverlayCandidateValidator() {
-  return nullptr;
-}
-
 bool PixelTestOutputSurface::IsDisplayedAsOverlayPlane() const {
   return false;
 }
diff --git a/cc/test/pixel_test_output_surface.h b/cc/test/pixel_test_output_surface.h
index a14412a..76778c5 100644
--- a/cc/test/pixel_test_output_surface.h
+++ b/cc/test/pixel_test_output_surface.h
@@ -33,8 +33,6 @@
   bool HasExternalStencilTest() const override;
   void ApplyExternalStencil() override;
   void SwapBuffers(viz::OutputSurfaceFrame frame) override;
-  std::unique_ptr<viz::OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() override;
   bool IsDisplayedAsOverlayPlane() const override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 9a8c60c8..329983c 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -40,6 +40,7 @@
   import("//build/mac/tweak_info_plist.gni")
   import("//build/util/branding.gni")
   import("//build/util/version.gni")
+  import("//content/public/app/mac_helpers.gni")
   import("//media/cdm/library_cdm/cdm_paths.gni")
   import("//third_party/icu/config.gni")
 }
@@ -879,53 +880,68 @@
     visibility = [ "//chrome/installer/mac:copies" ]
   }
 
-  mac_app_bundle("chrome_helper_app") {
-    output_name = chrome_helper_name
+  template("chrome_helper_app") {
+    mac_app_bundle(target_name) {
+      assert(defined(invoker.helper_name_suffix))
+      assert(defined(invoker.helper_bundle_id_suffix))
 
-    info_plist_target = ":chrome_helper_plist"
-    extra_substitutions = [
-      "CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
-      "CHROMIUM_SHORT_NAME=$chrome_product_short_name",
-    ]
+      output_name = chrome_helper_name + invoker.helper_name_suffix
 
-    sources = [
-      "app/chrome_exe_main_mac.cc",
-    ]
-
-    extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
-
-    defines = [ "HELPER_EXECUTABLE" ]
-
-    deps = [
-      "//chrome/common:buildflags",
-      "//chrome/common:version_header",
-      "//sandbox/mac:seatbelt",
-    ]
-
-    ldflags = []
-
-    if (is_component_build) {
-      ldflags += [
-        # The helper is in Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/X/Helpers/Chromium Helper.app/Contents/MacOS
-        # so set rpath up to the base.
-        "-rpath",
-        "@loader_path/../../../../../../../../../..",
+      info_plist_target = ":chrome_helper_plist"
+      extra_substitutions = [
+        "CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id",
+        "CHROMIUM_SHORT_NAME=$chrome_product_short_name",
+        "CHROMIUM_HELPER_SUFFIX=${invoker.helper_name_suffix}",
+        "CHROMIUM_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
       ]
-    }
 
-    if (enable_stripping) {
-      # At link time, preserve the global symbols specified in the .exports
-      # file. All other global symbols will be marked as private. The default
-      # //build/config/mac:strip_all config will then remove the remaining
-      # local and debug symbols.
-      ldflags += [ "-Wl,-exported_symbols_list," +
-                   rebase_path("app/app.exports", root_build_dir) ]
+      sources = [
+        "app/chrome_exe_main_mac.cc",
+      ]
+
+      extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
+
+      defines = [ "HELPER_EXECUTABLE" ]
+
+      deps = [
+        "//chrome/common:version_header",
+        "//sandbox/mac:seatbelt",
+      ]
+
+      ldflags = []
+
+      if (is_component_build) {
+        ldflags += [
+          # The helper is in Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/X/Helpers/Chromium Helper.app/Contents/MacOS
+          # so set rpath up to the base.
+          "-rpath",
+          "@loader_path/../../../../../../../../../..",
+        ]
+      }
+
+      if (enable_stripping) {
+        # At link time, preserve the global symbols specified in the .exports
+        # file. All other global symbols will be marked as private. The default
+        # //build/config/mac:strip_all config will then remove the remaining
+        # local and debug symbols.
+        ldflags += [ "-Wl,-exported_symbols_list," +
+                     rebase_path("app/app.exports", root_build_dir) ]
+      }
+    }
+  }
+
+  foreach(helper_params, content_mac_helpers) {
+    _helper_target = helper_params[0]
+    _helper_bundle_id = helper_params[1]
+    _helper_suffix = helper_params[2]
+    chrome_helper_app("chrome_helper_app_${_helper_target}") {
+      helper_name_suffix = _helper_suffix
+      helper_bundle_id_suffix = _helper_bundle_id
     }
   }
 
   bundle_data("chrome_framework_helpers") {
     sources = [
-      "$root_out_dir/$chrome_helper_name.app",
       "$root_out_dir/app_mode_loader",
       "$root_out_dir/chrome_crashpad_handler",
     ]
@@ -935,11 +951,16 @@
     ]
 
     public_deps = [
-      ":chrome_helper_app",
       "//chrome/app_shim:app_mode_loader",
       "//components/crash/content/app:chrome_crashpad_handler",
     ]
 
+    foreach(helper_params, content_mac_helpers) {
+      sources +=
+          [ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app" ]
+      public_deps += [ ":chrome_helper_app_${helper_params[0]}" ]
+    }
+
     if (is_asan) {
       # crashpad_handler requires the ASan runtime at its @executable_path.
       sources += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ]
@@ -1359,13 +1380,16 @@
     _chrome_symbols_sources = [
       _framework_binary_path,
       "$root_out_dir/AlertNotificationService.xpc/Contents/MacOS/AlertNotificationService",
-      "$root_out_dir/$chrome_helper_name.app/Contents/MacOS/$chrome_helper_name",
       "$root_out_dir/$chrome_product_full_name.app/Contents/MacOS/$chrome_product_full_name",
       "$root_out_dir/chrome_crashpad_handler",
       "$root_out_dir/libswiftshader_libEGL.dylib",
       "$root_out_dir/libswiftshader_libGLESv2.dylib",
     ]
 
+    foreach(helper_params, content_mac_helpers) {
+      _chrome_symbols_sources += [ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.app/Contents/MacOS/${chrome_helper_name}${helper_params[2]}" ]
+    }
+
     # It is possible to run dump_syms on unstripped products without dSYMs,
     # but doing so isn't logical and won't happen in practice.
     action_foreach("chrome_dump_syms") {
@@ -1390,13 +1414,16 @@
       deps = [
         ":chrome_app",
         ":chrome_framework",
-        ":chrome_helper_app",
         "//chrome/browser/ui/cocoa/notifications:alert_notification_xpc_service",
         "//components/crash/content/app:chrome_crashpad_handler",
         "//third_party/breakpad:dump_syms",
         "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
         "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
       ]
+
+      foreach(helper_params, content_mac_helpers) {
+        deps += [ ":chrome_helper_app_${helper_params[0]}" ]
+      }
     }
 
     action("chrome_dsym_archive") {
@@ -1409,13 +1436,27 @@
       _dsyms = [
         "$root_out_dir/AlertNotificationService.dSYM",
         "$root_out_dir/$chrome_framework_name.dSYM",
-        "$root_out_dir/$chrome_helper_name.dSYM",
         "$root_out_dir/$chrome_product_full_name.dSYM",
         "$root_out_dir/chrome_crashpad_handler.dSYM",
         "$root_out_dir/libswiftshader_libEGL.dylib.dSYM",
         "$root_out_dir/libswiftshader_libGLESv2.dylib.dSYM",
       ]
 
+      deps = [
+        ":chrome_app",
+        ":chrome_framework",
+        "//chrome/browser/ui/cocoa/notifications:alert_notification_xpc_service",
+        "//components/crash/content/app:chrome_crashpad_handler",
+        "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
+        "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
+      ]
+
+      foreach(helper_params, content_mac_helpers) {
+        _dsyms +=
+            [ "$root_out_dir/${chrome_helper_name}${helper_params[2]}.dSYM" ]
+        deps += [ ":chrome_helper_app_${helper_params[0]}" ]
+      }
+
       sources = _chrome_symbols_sources
 
       _output = "$root_out_dir/$chrome_product_full_name.dSYM.tar.bz2"
@@ -1426,16 +1467,6 @@
 
       args = [ rebase_path(_output, root_out_dir) ] +
              rebase_path(_dsyms, root_out_dir)
-
-      deps = [
-        ":chrome_app",
-        ":chrome_framework",
-        ":chrome_helper_app",
-        "//chrome/browser/ui/cocoa/notifications:alert_notification_xpc_service",
-        "//components/crash/content/app:chrome_crashpad_handler",
-        "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
-        "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
-      ]
     }
   } else {
     group("chrome_dump_syms") {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 766aa5b..77adc407 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1175,6 +1175,8 @@
       deps += [ "//chrome/browser/android/vr:ui_module_dummy_factory" ]
     }
   }
+
+  allow_partitions = true
 }
 
 chrome_common_shared_library("libchromefortest") {
@@ -1435,6 +1437,7 @@
     }
 
     is_monochrome = true
+    allow_partitions = true
   }
 }
 
@@ -1659,6 +1662,7 @@
   ]
   java_files =
       [ "java/src/org/chromium/chrome/browser/MonochromeApplication.java" ]
+  min_sdk_version = 24
 }
 
 # Defines a target that derives from the monochrome public application. This
@@ -1774,6 +1778,10 @@
     apk_name = "TrichromeLibrary"
     android_manifest = trichrome_library_android_manifest
     android_manifest_dep = ":trichrome_library_android_manifest"
+
+    # TODO(torne): make minsdk=Q once we no longer build hacky P version
+    min_sdk_version = android_sdk_version
+    target_sdk_version = android_sdk_version
     if (trichrome_synchronized_proguard) {
       static_library_dependent_targets = [
         {
@@ -1798,6 +1806,10 @@
     apk_name = "TrichromeLibraryForBundle"
     android_manifest = trichrome_library_android_manifest
     android_manifest_dep = ":trichrome_library_android_manifest"
+
+    # TODO(torne): make minsdk=Q once we no longer build hacky P version
+    min_sdk_version = android_sdk_version
+    target_sdk_version = android_sdk_version
     if (trichrome_synchronized_proguard) {
       static_library_dependent_targets = [
         {
@@ -1941,13 +1953,15 @@
   monochrome_public_common_apk_or_module_tmpl(target_name) {
     forward_variables_from(invoker,
                            [
-                             "apk_name",
                              "android_manifest",
                              "android_manifest_dep",
+                             "apk_name",
                              "data_deps",
                              "loadable_modules",
+                             "min_sdk_version",
                              "secondary_abi_loadable_modules",
                              "shared_libraries",
+                             "target_sdk_version",
                            ])
 
     testonly = true
@@ -2020,6 +2034,8 @@
     apk_name = "VrNfcSimulator"
     android_manifest = vr_nfc_simulator_apk_manifest
     android_manifest_dep = ":vr_nfc_simulator_apk_manifest"
+    min_sdk_version = 24
+    target_sdk_version = 24
 
     deps = [
       ":chrome_test_vr_java",
@@ -2033,6 +2049,8 @@
     apk_name = "MonochromePublicTestAr"
     android_manifest = monochrome_public_test_ar_apk_manifest
     android_manifest_dep = ":monochrome_public_test_ar_apk_manifest"
+    min_sdk_version = 24
+    target_sdk_version = android_sdk_version
 
     # This is where we would add the shared_libraries entry for
     # :libchromefortest in the non-Monochrome version. However, doing so in the
diff --git a/chrome/android/chrome_common_shared_library.gni b/chrome/android/chrome_common_shared_library.gni
index e37213e..843ed5c1 100644
--- a/chrome/android/chrome_common_shared_library.gni
+++ b/chrome/android/chrome_common_shared_library.gni
@@ -32,6 +32,10 @@
 #    is_monochrome: Optional. If set, the library is for use in monochrome.
 #    is_webview: If true, the library is for webview, and browser-specific
 #      config is skipped.
+#    allow_partitions: If true, and the build config supports it, the library
+#      is linked as a partitioned library, and separate feature libs are
+#      generated if specified. Those libraries may later be packaged into
+#      dynamic feature modules or APKs.
 template("chrome_common_shared_library") {
   _is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
   _is_webview = defined(invoker.is_webview) && invoker.is_webview
@@ -40,16 +44,21 @@
   _linker_script = "$target_gen_dir/${target_name}_linker_script.txt"
   _linker_script_target = "${target_name}_linker_script"
 
+  # Create a partitioned libraries if the build config supports it, and the
+  # invoker wants partitions.
+  _generate_partitions = defined(invoker.allow_partitions) &&
+                         invoker.allow_partitions && use_native_modules
+
   # Create a custom linker script based on JNI and feature module requirements.
   generate_linker_version_script(_linker_script_target) {
     linker_script = _linker_script
     export_java_symbols = _export_java_symbols
-    if (use_native_modules) {
+    if (_generate_partitions) {
       export_symbol_whitelist_files = native_feature_module_entrypoint_files
     }
   }
 
-  if (use_native_modules) {
+  if (_generate_partitions) {
     _target_type = "partitioned_shared_library"
   } else {
     _target_type = "shared_library"
@@ -92,7 +101,7 @@
       }
     }
 
-    if (use_native_modules) {
+    if (_generate_partitions) {
       partitions = native_feature_modules
       deps += feature_module_base_lib_deps
     }
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index e9140c3a..9cc31d00 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -124,6 +124,7 @@
     } else {
       min_sdk_version = 19
     }
+    target_sdk_version = android_sdk_version
 
     resource_blacklist_regex = "[/-]xxxhdpi[/-]"
 
diff --git a/chrome/android/features/ar/AndroidManifest.xml b/chrome/android/features/ar/AndroidManifest.xml
index 6b11734..f6a69ed6 100644
--- a/chrome/android/features/ar/AndroidManifest.xml
+++ b/chrome/android/features/ar/AndroidManifest.xml
@@ -8,11 +8,6 @@
     featureSplit="ar"
     package="{{manifest_package}}">
 
-    <!-- Chrome AR is only supported on Android N+. -->
-    <uses-sdk
-        android:minSdkVersion="24"
-        android:targetSdkVersion="{{target_sdk_version}}" />
-
     <dist:module
         dist:onDemand="true"
         dist:title="@string/ar_module_title">
diff --git a/chrome/android/features/ar/ar_module_tmpl.gni b/chrome/android/features/ar/ar_module_tmpl.gni
index 8c4570d..b666740 100644
--- a/chrome/android/features/ar/ar_module_tmpl.gni
+++ b/chrome/android/features/ar/ar_module_tmpl.gni
@@ -21,10 +21,7 @@
   jinja_template(_manifest_target) {
     input = "//chrome/android/features/ar/AndroidManifest.xml"
     output = _manifest
-    variables = [
-      "target_sdk_version=$android_sdk_version",
-      "manifest_package=${invoker.manifest_package}",
-    ]
+    variables = [ "manifest_package=${invoker.manifest_package}" ]
   }
 
   android_app_bundle_module(target_name) {
@@ -38,6 +35,8 @@
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":$_manifest_target"
+    min_sdk_version = 24
+    target_sdk_version = android_sdk_version
     deps = [
       "//chrome/browser/android/vr:ar_java",
       "//third_party/android_deps:com_google_ar_core_java",
diff --git a/chrome/android/features/autofill_assistant/autofill_assistant_module_tmpl.gni b/chrome/android/features/autofill_assistant/autofill_assistant_module_tmpl.gni
index d43b17f5..2f68f5c 100644
--- a/chrome/android/features/autofill_assistant/autofill_assistant_module_tmpl.gni
+++ b/chrome/android/features/autofill_assistant/autofill_assistant_module_tmpl.gni
@@ -18,10 +18,7 @@
     input =
         "//chrome/android/features/autofill_assistant/java/AndroidManifest.xml"
     output = _manifest
-    variables = [
-      "target_sdk_version=$android_sdk_version",
-      "manifest_package=${invoker.manifest_package}",
-    ]
+    variables = [ "manifest_package=${invoker.manifest_package}" ]
   }
 
   android_app_bundle_module(target_name) {
@@ -35,6 +32,8 @@
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":${_manifest_target}"
+    min_sdk_version = 21
+    target_sdk_version = android_sdk_version
     proguard_enabled = !is_java_debug
     aapt_locale_whitelist = locales
     package_name = "autofill_assistant"
diff --git a/chrome/android/features/autofill_assistant/java/AndroidManifest.xml b/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
index 1d3890a..c226c4c 100644
--- a/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
+++ b/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
@@ -3,11 +3,6 @@
     featureSplit="autofill_assistant"
     package="{{manifest_package}}">
 
-    <!-- For Chrome Modern we use android:minSdkVersion="21". -->
-    <uses-sdk
-        android:minSdkVersion="21"
-        android:targetSdkVersion="{{target_sdk_version}}" />
-
     <dist:module
         dist:onDemand="true"
         dist:title="@string/autofill_assistant_module_title">
diff --git a/chrome/android/features/devtools/devtools_module_tmpl.gni b/chrome/android/features/devtools/devtools_module_tmpl.gni
index 6ef1f78..f39946b 100644
--- a/chrome/android/features/devtools/devtools_module_tmpl.gni
+++ b/chrome/android/features/devtools/devtools_module_tmpl.gni
@@ -12,10 +12,7 @@
   jinja_template(_manifest_target) {
     input = "//chrome/android/features/devtools/java/AndroidManifest.xml"
     output = _manifest
-    variables = [
-      "target_sdk_version=$android_sdk_version",
-      "manifest_package=${invoker.manifest_package}",
-    ]
+    variables = [ "manifest_package=${invoker.manifest_package}" ]
   }
 
   android_app_bundle_module(target_name) {
@@ -29,6 +26,8 @@
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":${_manifest_target}"
+    min_sdk_version = 21
+    target_sdk_version = android_sdk_version
     deps = [
       "//chrome/android/features/devtools:java",
     ]
diff --git a/chrome/android/features/devtools/java/AndroidManifest.xml b/chrome/android/features/devtools/java/AndroidManifest.xml
index eb573a9..7e0f92f 100644
--- a/chrome/android/features/devtools/java/AndroidManifest.xml
+++ b/chrome/android/features/devtools/java/AndroidManifest.xml
@@ -8,9 +8,6 @@
     featureSplit="devtools"
     package="{{manifest_package}}">
 
-    <uses-sdk
-        android:minSdkVersion="21"
-        android:targetSdkVersion="{{target_sdk_version}}" />
     <dist:module
         dist:onDemand="true"
         dist:title="@string/devtools_module_title">
diff --git a/chrome/android/features/tab_ui/AndroidManifest.xml b/chrome/android/features/tab_ui/AndroidManifest.xml
index 577915e8..50f982d 100644
--- a/chrome/android/features/tab_ui/AndroidManifest.xml
+++ b/chrome/android/features/tab_ui/AndroidManifest.xml
@@ -8,9 +8,6 @@
     featureSplit="tab_ui"
     package="{{manifest_package}}">
 
-    <uses-sdk
-        android:minSdkVersion="21"
-        android:targetSdkVersion="{{target_sdk_version}}" />
     <application></application>
     <dist:module
         dist:onDemand="true"
diff --git a/chrome/android/features/tab_ui/tab_ui_module_tmpl.gni b/chrome/android/features/tab_ui/tab_ui_module_tmpl.gni
index 614aed0..6b3fd1b 100644
--- a/chrome/android/features/tab_ui/tab_ui_module_tmpl.gni
+++ b/chrome/android/features/tab_ui/tab_ui_module_tmpl.gni
@@ -16,10 +16,7 @@
   jinja_template(_manifest_target) {
     input = "//chrome/android/features/tab_ui/AndroidManifest.xml"
     output = _manifest
-    variables = [
-      "target_sdk_version=$android_sdk_version",
-      "manifest_package=${invoker.manifest_package}",
-    ]
+    variables = [ "manifest_package=${invoker.manifest_package}" ]
   }
 
   android_app_bundle_module(target_name) {
@@ -33,6 +30,8 @@
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":${_manifest_target}"
+    min_sdk_version = 21
+    target_sdk_version = android_sdk_version
     proguard_enabled = !is_java_debug
     aapt_locale_whitelist = locales
     package_name = "tab_ui"
diff --git a/chrome/android/features/vr/java/AndroidManifest.xml b/chrome/android/features/vr/java/AndroidManifest.xml
index 99f71ad..e892602 100644
--- a/chrome/android/features/vr/java/AndroidManifest.xml
+++ b/chrome/android/features/vr/java/AndroidManifest.xml
@@ -8,11 +8,6 @@
     featureSplit="vr"
     package="{{manifest_package}}">
 
-    <!-- The VR module is only supported on Android L+. -->
-    <uses-sdk
-        android:minSdkVersion="21"
-        android:targetSdkVersion="{{target_sdk_version}}" />
-
     <dist:module
         dist:onDemand="true"
         dist:title="@string/vr_module_title">
diff --git a/chrome/android/features/vr/vr_module_tmpl.gni b/chrome/android/features/vr/vr_module_tmpl.gni
index c54c53d1..422f9b7 100644
--- a/chrome/android/features/vr/vr_module_tmpl.gni
+++ b/chrome/android/features/vr/vr_module_tmpl.gni
@@ -22,10 +22,7 @@
   jinja_template(_manifest_target) {
     input = "//chrome/android/features/vr/java/AndroidManifest.xml"
     output = _manifest
-    variables = [
-      "target_sdk_version=$android_sdk_version",
-      "manifest_package=${invoker.manifest_package}",
-    ]
+    variables = [ "manifest_package=${invoker.manifest_package}" ]
   }
 
   android_app_bundle_module(target_name) {
@@ -40,6 +37,8 @@
                            ])
     android_manifest = _manifest
     android_manifest_dep = ":${_manifest_target}"
+    min_sdk_version = 21
+    target_sdk_version = android_sdk_version
     deps = [
       "//chrome/android/features/vr:java",
       "//chrome/browser/android/vr:vr_ui_dummy_lib",
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java
index 86c75e6..a447de0 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedDebuggingBridge.java
@@ -5,7 +5,7 @@
 package org.chromium.chrome.browser.feed;
 
 import com.google.android.libraries.feed.api.client.requestmanager.RequestManager;
-import com.google.android.libraries.feed.api.internal.scope.FeedProcessScope;
+import com.google.android.libraries.feed.api.client.scope.ProcessScope;
 import com.google.android.libraries.feed.common.logging.Dumper;
 
 import org.chromium.base.annotations.CalledByNative;
@@ -26,28 +26,28 @@
     }
 
     @CalledByNative
-    static String getFeedProcessScopeDump() {
-        FeedProcessScope feedProcessScope = FeedProcessScopeFactory.getFeedProcessScope();
+    static String getProcessScopeDump() {
+        ProcessScope processScope = FeedProcessScopeFactory.getFeedProcessScope();
         Dumper dumper = Dumper.newDefaultDumper();
-        dumper.dump(feedProcessScope);
+        dumper.dump(processScope);
 
         try {
             StringWriter writer = new StringWriter();
             dumper.write(writer);
             return writer.toString();
         } catch (IOException e) {
-            return "Unable to dump FeedProcessScope";
+            return "Unable to dump ProcessScope";
         }
     }
 
     @CalledByNative
     static void triggerRefresh() {
-        FeedProcessScope feedProcessScope = FeedProcessScopeFactory.getFeedProcessScope();
+        ProcessScope processScope = FeedProcessScopeFactory.getFeedProcessScope();
 
         // Do nothing if Feed is disabled.
-        if (feedProcessScope == null) return;
+        if (processScope == null) return;
 
-        RequestManager requestManager = feedProcessScope.getRequestManager();
+        RequestManager requestManager = processScope.getRequestManager();
 
         // The only notification of this completing is through the SchedulerApi interface, like all
         // other refreshes.
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 3ac5139..a866df1b 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
@@ -17,6 +17,7 @@
 import android.view.View;
 import android.widget.ScrollView;
 
+import com.google.android.libraries.feed.api.client.scope.ProcessScope;
 import com.google.android.libraries.feed.api.client.scope.StreamScope;
 import com.google.android.libraries.feed.api.client.stream.Header;
 import com.google.android.libraries.feed.api.client.stream.NonDismissibleHeader;
@@ -27,7 +28,6 @@
 import com.google.android.libraries.feed.api.host.stream.SnackbarCallbackApi;
 import com.google.android.libraries.feed.api.host.stream.StreamConfiguration;
 import com.google.android.libraries.feed.api.host.stream.TooltipApi;
-import com.google.android.libraries.feed.api.internal.scope.FeedProcessScope;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
@@ -352,7 +352,7 @@
             mScrollViewResizer = null;
         }
 
-        FeedProcessScope feedProcessScope = FeedProcessScopeFactory.getFeedProcessScope();
+        ProcessScope feedProcessScope = FeedProcessScopeFactory.getFeedProcessScope();
         assert feedProcessScope != null;
 
         FeedAppLifecycle appLifecycle = FeedProcessScopeFactory.getFeedAppLifecycle();
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
index 0c94490..6ec286be 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
@@ -6,12 +6,12 @@
 
 import android.support.annotation.Nullable;
 
+import com.google.android.libraries.feed.api.client.scope.ProcessScope;
 import com.google.android.libraries.feed.api.client.scope.ProcessScopeBuilder;
 import com.google.android.libraries.feed.api.host.config.ApplicationInfo;
 import com.google.android.libraries.feed.api.host.config.Configuration;
 import com.google.android.libraries.feed.api.host.config.DebugBehavior;
 import com.google.android.libraries.feed.api.host.network.NetworkClient;
-import com.google.android.libraries.feed.api.internal.scope.FeedProcessScope;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
@@ -24,7 +24,7 @@
 
 import java.util.concurrent.Executors;
 
-/** Holds singleton {@link FeedProcessScope} and some of the scope's host implementations. */
+/** Holds singleton {@link ProcessScope} and some of the scope's host implementations. */
 public class FeedProcessScopeFactory {
     private static final String TAG = "FeedProcessScopeFtry";
 
@@ -44,22 +44,24 @@
 
     private static PrefChangeRegistrar sPrefChangeRegistrar;
     private static FeedAppLifecycle sFeedAppLifecycle;
-    private static FeedProcessScope sFeedProcessScope;
+    private static ProcessScope sProcessScope;
     private static FeedScheduler sFeedScheduler;
     private static FeedOfflineIndicator sFeedOfflineIndicator;
     private static NetworkClient sTestNetworkClient;
     private static FeedLoggingBridge sFeedLoggingBridge;
 
-    /** @return The shared {@link FeedProcessScope} instance. Null if the Feed is disabled. */
-    public static @Nullable FeedProcessScope getFeedProcessScope() {
-        if (sFeedProcessScope == null) {
+    /** @return The shared {@link ProcessScope} instance. Null if the Feed is disabled. */
+    public static @Nullable ProcessScope getFeedProcessScope() {
+        if (sProcessScope == null) {
             initialize();
         }
-        return sFeedProcessScope;
+        return sProcessScope;
     }
 
-    /** @return The {@link FeedScheduler} that was given to the {@link FeedProcessScope}. Null if
-     * the Feed is disabled. */
+    /**
+     * @return The {@link FeedScheduler} that was given to the {@link ProcessScope}. Null if
+     * the Feed is disabled.
+     */
     public static @Nullable FeedScheduler getFeedScheduler() {
         if (sFeedScheduler == null) {
             initialize();
@@ -67,8 +69,10 @@
         return sFeedScheduler;
     }
 
-    /** @return The {@link FeedOfflineIndicator} that was given to the {@link FeedProcessScope}.
-     * Null if the Feed is disabled. */
+    /**
+     * @return The {@link FeedOfflineIndicator} that was given to the {@link ProcessScope}.
+     * Null if the Feed is disabled.
+     */
     public static @Nullable FeedOfflineIndicator getFeedOfflineIndicator() {
         if (sFeedOfflineIndicator == null) {
             initialize();
@@ -115,7 +119,7 @@
     }
 
     private static void initialize() {
-        assert sFeedProcessScope == null && sFeedScheduler == null && sFeedOfflineIndicator == null
+        assert sProcessScope == null && sFeedScheduler == null && sFeedOfflineIndicator == null
                 && sFeedAppLifecycle == null && sFeedLoggingBridge == null;
         if (!isFeedProcessEnabled()) return;
 
@@ -136,24 +140,24 @@
         NetworkClient networkClient = sTestNetworkClient == null ?
             new FeedNetworkBridge(profile) : sTestNetworkClient;
         sFeedLoggingBridge = new FeedLoggingBridge(profile);
-        sFeedProcessScope = (FeedProcessScope) new ProcessScopeBuilder(configHostApi,
-                Executors.newSingleThreadExecutor(), sFeedLoggingBridge, networkClient,
-                schedulerBridge, DebugBehavior.SILENT, ContextUtils.getApplicationContext(),
-                applicationInfo, new BasicTooltipSupportedApi())
-                                    .setContentStorage(contentStorage)
-                                    .setJournalStorage(journalStorage)
-                                    .build();
-        schedulerBridge.initializeFeedDependencies(sFeedProcessScope.getRequestManager());
+        sProcessScope = new ProcessScopeBuilder(configHostApi, Executors.newSingleThreadExecutor(),
+                sFeedLoggingBridge, networkClient, schedulerBridge, DebugBehavior.SILENT,
+                ContextUtils.getApplicationContext(), applicationInfo,
+                new BasicTooltipSupportedApi())
+                                .setContentStorage(contentStorage)
+                                .setJournalStorage(journalStorage)
+                                .build();
+        schedulerBridge.initializeFeedDependencies(sProcessScope.getRequestManager());
 
-        sFeedOfflineIndicator = new FeedOfflineBridge(profile, sFeedProcessScope.getKnownContent());
+        sFeedOfflineIndicator = new FeedOfflineBridge(profile, sProcessScope.getKnownContent());
 
-        sFeedAppLifecycle = new FeedAppLifecycle(sFeedProcessScope.getAppLifecycleListener(),
+        sFeedAppLifecycle = new FeedAppLifecycle(sProcessScope.getAppLifecycleListener(),
                 new FeedLifecycleBridge(profile), sFeedScheduler);
     }
 
     /**
-     * Creates a {@link FeedProcessScope} using the provided host implementations. Call {@link
-     * #clearFeedProcessScopeForTesting()} to reset the FeedProcessScope after testing is complete.
+     * Creates a {@link ProcessScope} using the provided host implementations. Call {@link
+     * #clearFeedProcessScopeForTesting()} to reset the ProcessScope after testing is complete.
      *
      * @param feedScheduler A {@link FeedScheduler} to use for testing.
      * @param networkClient A {@link NetworkClient} to use for testing.
@@ -174,11 +178,11 @@
         ApplicationInfo applicationInfo =
                 new ApplicationInfo.Builder(ContextUtils.getApplicationContext()).build();
 
-        sFeedProcessScope = (FeedProcessScope) new ProcessScopeBuilder(configHostApi,
-                Executors.newSingleThreadExecutor(), sFeedLoggingBridge, networkClient,
-                sFeedScheduler, DebugBehavior.SILENT, ContextUtils.getApplicationContext(),
-                applicationInfo, new BasicTooltipSupportedApi())
-                                    .build();
+        sProcessScope = new ProcessScopeBuilder(configHostApi, Executors.newSingleThreadExecutor(),
+                sFeedLoggingBridge, networkClient, sFeedScheduler, DebugBehavior.SILENT,
+                ContextUtils.getApplicationContext(), applicationInfo,
+                new BasicTooltipSupportedApi())
+                                .build();
     }
 
     /** Use supplied NetworkClient instead of real one, for tests. */
@@ -186,15 +190,15 @@
     public static void setTestNetworkClient(NetworkClient client) {
         if (client == null) {
             sTestNetworkClient = null;
-        } else if (sFeedProcessScope == null) {
+        } else if (sProcessScope == null) {
             sTestNetworkClient = client;
         } else {
             throw(new IllegalStateException(
-                    "TestNetworkClient can not be set after FeedProcessScope has initialized."));
+                    "TestNetworkClient can not be set after ProcessScope has initialized."));
         }
     }
 
-    /** Resets the FeedProcessScope after testing is complete. */
+    /** Resets the ProcessScope after testing is complete. */
     @VisibleForTesting
     static void clearFeedProcessScopeForTesting() {
         destroy();
@@ -235,9 +239,9 @@
             sPrefChangeRegistrar.destroy();
             sPrefChangeRegistrar = null;
         }
-        if (sFeedProcessScope != null) {
-            sFeedProcessScope.onDestroy();
-            sFeedProcessScope = null;
+        if (sProcessScope != null) {
+            sProcessScope.onDestroy();
+            sProcessScope = null;
         }
         if (sFeedScheduler != null) {
             sFeedScheduler.destroy();
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index abb4276..88df612 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -16,7 +16,6 @@
     tools:ignore="MissingVersion">
     <!-- android:versionCode and android:versionName is set through gyp. See build/common.gypi -->
 
-    <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="{{target_sdk_version}}" />
     <uses-feature android:glEsVersion="0x00020000" />
 
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index 09c2af3..37ff48e 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -12,7 +12,6 @@
     package="{{ manifest_package }}"
     tools:ignore="MissingVersion,MissingLeanbackLauncher">
 
-    <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="{{target_sdk_version}}" />
     <uses-feature android:glEsVersion="0x00020000" />
     <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
     <uses-feature android:name="android.software.leanback" android:required="false" />
diff --git a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
index b1225fc..01cda890 100644
--- a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
@@ -279,18 +279,6 @@
 -keep class org.chromium.build.BuildHooksAndroidImpl
 
 ################################################################################
-# ../../build/android/multidex.flags
-################################################################################
-# Copyright 2017 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.
-
-# When multidex is enabled, need to keep the @MainDex annotation so that it
-# can be used to create the main dex list.
--keepattributes *Annotations*
--keep @interface org.chromium.base.annotations.MainDex
-
-################################################################################
 # ../../chrome/android/java/proguard.flags
 ################################################################################
 # Copyright 2016 The Chromium Authors. All rights reserved.
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
index ef8684df..07c4197 100644
--- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
+++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -1,6 +1,8 @@
 <?xml version="1.0" ?>
 <manifest
     package="org.chromium.chrome"
+    platformBuildVersionCode="28"
+    platformBuildVersionName="9"
     tools:ignore="MissingVersion"
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
diff --git a/chrome/android/java/res/xml/notifications_preferences.xml b/chrome/android/java/res/xml/notifications_preferences.xml
index 56a6565d..5eccf3c 100644
--- a/chrome/android/java/res/xml/notifications_preferences.xml
+++ b/chrome/android/java/res/xml/notifications_preferences.xml
@@ -3,9 +3,9 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
+    <org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat
         android:key="content_suggestions"
         android:title="@string/notifications_content_suggestions_title"
         android:summary="@string/notifications_content_suggestions_summary" />
@@ -14,4 +14,4 @@
         android:fragment="org.chromium.chrome.browser.preferences.website.SingleCategoryPreferences"
         android:title="@string/notifications_from_websites_title"
         android:key="from_websites" />
-</PreferenceScreen>
\ No newline at end of file
+</android.support.v7.preference.PreferenceScreen>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index 222725ed..94a686b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -21,7 +21,6 @@
 import org.chromium.base.CommandLineInitUtil;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.DiscardableReferencePool;
-import org.chromium.base.EarlyTraceEvent;
 import org.chromium.base.JNIUtils;
 import org.chromium.base.Log;
 import org.chromium.base.TraceEvent;
@@ -30,8 +29,6 @@
 import org.chromium.base.memory.MemoryPressureMonitor;
 import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 import org.chromium.base.task.AsyncTask;
-import org.chromium.base.task.PostTask;
-import org.chromium.base.task.TaskTraits;
 import org.chromium.build.BuildHooks;
 import org.chromium.build.BuildHooksAndroid;
 import org.chromium.build.BuildHooksConfig;
@@ -63,7 +60,6 @@
 
     private final DiscardableReferencePool mReferencePool = new DiscardableReferencePool();
     private static ChromeApplication sInstance;
-    private static EarlyTraceEvent.Event sFirstTraceEvent;
 
     /** Lock on creation of sComponent. */
     private static final Object sLock = new Object();
@@ -72,36 +68,17 @@
 
     @Override
     public void onCreate() {
-        EarlyTraceEvent.Event onCreateEvent =
-                new EarlyTraceEvent.Event("ChromeApplication.onCreate");
         super.onCreate();
-        // Cannot go in attachBaseContext() because it accesses SharedPreferences, which tests
-        // want to mock out.
-        // TODO(crbug.com/957569): Accessing SharedPreferences (via maybeEnableEarlyTracing) might
-        //     by slowing down start-up.
-        boolean isBrowserProcess = isBrowserProcess();
-        if (isBrowserProcess) {
-            TraceEvent.maybeEnableEarlyTracing();
-            EarlyTraceEvent.addEvent(sFirstTraceEvent);
-        }
-        sFirstTraceEvent = null;
-
         // These can't go in attachBaseContext because Context.getApplicationContext() (which they
         // use under-the-hood) does not work until after it returns.
         FontPreloadingWorkaround.maybeInstallWorkaround(this);
         MemoryPressureMonitor.INSTANCE.registerComponentCallbacks();
-
-        if (isBrowserProcess) {
-            onCreateEvent.end();
-            EarlyTraceEvent.addEvent(onCreateEvent);
-        }
     }
 
     // Called by the framework for ALL processes. Runs before ContentProviders are created.
     // Quirk: context.getApplicationContext() returns null during this method.
     @Override
     protected void attachBaseContext(Context context) {
-        sFirstTraceEvent = new EarlyTraceEvent.Event("ChromeApplication.attachBaseContext");
         sInstance = this;
         boolean isBrowserProcess = isBrowserProcess();
         if (isBrowserProcess) UmaUtils.recordMainEntryPointTime();
@@ -120,6 +97,10 @@
                     COMMAND_LINE_FILE, ChromeApplication::shouldUseDebugFlags);
             AppHooks.get().initCommandLine(CommandLine.getInstance());
 
+            // Requires command-line flags.
+            TraceEvent.maybeEnableEarlyTracing();
+            TraceEvent.begin("ChromeApplication.attachBaseContext");
+
             // Register for activity lifecycle callbacks. Must be done before any activities are
             // created and is needed only by processes that use the ApplicationStatus api (which for
             // Chrome is just the browser process).
@@ -140,7 +121,7 @@
 
             // Record via UMA all modules that have been requested and are currently installed. This
             // will tell us the install penetration of each module over time.
-            PostTask.postTask(TaskTraits.BEST_EFFORT, ModuleInstaller::recordModuleAvailability);
+            ModuleInstaller.recordModuleAvailability();
         }
 
         // Write installed modules to crash keys. This needs to be done as early as possible so that
@@ -160,7 +141,10 @@
         }
         AsyncTask.takeOverAndroidThreadPool();
         JNIUtils.setClassLoader(getClassLoader());
-        sFirstTraceEvent.end();
+
+        if (isBrowserProcess) {
+            TraceEvent.end("ChromeApplication.attachBaseContext");
+        }
     }
 
     private static Boolean shouldUseDebugFlags() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java
index 10b0721..c9d977d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java
@@ -6,9 +6,9 @@
 
 import android.os.Build;
 import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
 import android.support.annotation.Nullable;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ContentSettingsType;
@@ -23,7 +23,7 @@
  * notification channels at the top level and links to website specific notifications. This is only
  * used on pre-O devices, devices on Android O+ will link to the Android notification settings.
  */
-public class NotificationsPreferences extends PreferenceFragment {
+public class NotificationsPreferences extends PreferenceFragmentCompat {
     // These are package-private to be used in tests.
     static final String PREF_FROM_WEBSITES = "from_websites";
     static final String PREF_SUGGESTIONS = "content_suggestions";
@@ -33,18 +33,17 @@
     // The following field is only set if Feed is disabled, and should be null checked before
     // being used.
     @Nullable
-    private ChromeSwitchPreference mSuggestionsPref;
+    private ChromeSwitchPreferenceCompat mSuggestionsPref;
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         assert Build.VERSION.SDK_INT < Build.VERSION_CODES.O
             : "NotificationsPreferences should only be used pre-O.";
 
-        super.onCreate(savedInstanceState);
         PreferenceUtils.addPreferencesFromResource(this, R.xml.notifications_preferences);
         getActivity().setTitle(R.string.prefs_notifications);
 
-        mSuggestionsPref = (ChromeSwitchPreference) findPreference(PREF_SUGGESTIONS);
+        mSuggestionsPref = (ChromeSwitchPreferenceCompat) findPreference(PREF_SUGGESTIONS);
         mSuggestionsPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> {
             PrefetchPrefs.setNotificationEnabled((boolean) newValue);
             return true;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
index a85497d..a7f1506 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
@@ -228,7 +228,7 @@
 
     private OfflineItem findItemByUrl(String url) throws InterruptedException, TimeoutException {
         for (OfflineItem item : OfflineTestUtil.getOfflineItems()) {
-            if (item.pageUrl.equals(URL1)) {
+            if (item.pageUrl.equals(url)) {
                 return item;
             }
         }
@@ -266,7 +266,7 @@
     /**
      * Waits for |callbackHelper| to be notified. Runs the background task while waiting.
      * @param callbackHelper The callback helper to wait for.
-     * @param currentCallbacount |callbackHelper|'s current call count.
+     * @param currentCallCount |callbackHelper|'s current call count.
      * @param numberOfCallsToWaitFor number of calls to wait for.
      */
     private void runBackgroundTaskUntilCallCountReached(CallbackHelper callbackHelper,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/NotificationsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/NotificationsPreferencesTest.java
index 549ee67..03f8eeb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/NotificationsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/NotificationsPreferencesTest.java
@@ -6,10 +6,10 @@
 
 import android.app.Fragment;
 import android.os.Build;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -61,9 +61,11 @@
     public void testContentSuggestionsToggle() {
         // clang-format on
 
-        final PreferenceFragment fragment = (PreferenceFragment) mActivity.getMainFragment();
-        final ChromeSwitchPreference toggle = (ChromeSwitchPreference) fragment.findPreference(
-                NotificationsPreferences.PREF_SUGGESTIONS);
+        final PreferenceFragmentCompat fragment =
+                (PreferenceFragmentCompat) mActivity.getMainFragmentCompat();
+        final ChromeSwitchPreferenceCompat toggle =
+                (ChromeSwitchPreferenceCompat) fragment.findPreference(
+                        NotificationsPreferences.PREF_SUGGESTIONS);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             // Make sure the toggle reflects the state correctly.
@@ -71,17 +73,17 @@
             Assert.assertEquals(toggle.isChecked(), PrefetchPrefs.getNotificationEnabled());
 
             // Make sure we can change the state.
-            PreferencesTest.clickPreference(fragment, toggle);
+            toggle.performClick();
             Assert.assertEquals(toggle.isChecked(), !initiallyChecked);
             Assert.assertEquals(toggle.isChecked(), PrefetchPrefs.getNotificationEnabled());
 
             // Make sure we can change it back.
-            PreferencesTest.clickPreference(fragment, toggle);
+            toggle.performClick();
             Assert.assertEquals(toggle.isChecked(), initiallyChecked);
             Assert.assertEquals(toggle.isChecked(), PrefetchPrefs.getNotificationEnabled());
 
             // Click it one last time so we're in a toggled state for the UI Capture.
-            PreferencesTest.clickPreference(fragment, toggle);
+            toggle.performClick();
         });
 
         mScreenShooter.shoot("ContentSuggestionsToggle");
@@ -97,9 +99,11 @@
     public void testToggleDisabledWhenPrefetchingDisabled() {
         // clang-format on
 
-        PreferenceFragment fragment = (PreferenceFragment) mActivity.getMainFragment();
-        ChromeSwitchPreference toggle = (ChromeSwitchPreference) fragment.findPreference(
-                NotificationsPreferences.PREF_SUGGESTIONS);
+        PreferenceFragmentCompat fragment =
+                (PreferenceFragmentCompat) mActivity.getMainFragmentCompat();
+        ChromeSwitchPreferenceCompat toggle =
+                (ChromeSwitchPreferenceCompat) fragment.findPreference(
+                        NotificationsPreferences.PREF_SUGGESTIONS);
 
         Assert.assertFalse(toggle.isEnabled());
         Assert.assertFalse(toggle.isChecked());
@@ -117,11 +121,12 @@
         // clang-format on
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            PreferenceFragment fragment = (PreferenceFragment) mActivity.getMainFragment();
+            PreferenceFragmentCompat fragment =
+                    (PreferenceFragmentCompat) mActivity.getMainFragmentCompat();
             Preference fromWebsites =
                     fragment.findPreference(NotificationsPreferences.PREF_FROM_WEBSITES);
 
-            PreferencesTest.clickPreference(fragment, fromWebsites);
+            fromWebsites.performClick();
         });
 
         CriteriaHelper.pollUiThread(new Criteria() {
@@ -147,7 +152,8 @@
     public void testWebsiteNotificationsSummary() {
         // clang-format on
 
-        final PreferenceFragment fragment = (PreferenceFragment) mActivity.getMainFragment();
+        final PreferenceFragmentCompat fragment =
+                (PreferenceFragmentCompat) mActivity.getMainFragmentCompat();
         final Preference fromWebsites =
                 fragment.findPreference(NotificationsPreferences.PREF_FROM_WEBSITES);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/nfc_apk/AndroidManifest.xml b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/nfc_apk/AndroidManifest.xml
index 70a65d0..67ec8b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/nfc_apk/AndroidManifest.xml
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/nfc_apk/AndroidManifest.xml
@@ -4,7 +4,6 @@
        in the LICENSE file. -->
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.chrome.browser.vr.nfc_apk">
-    <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />
     <application>
       <activity android:name="org.chromium.chrome.browser.vr.nfc_apk.SimNfcActivity"
         android:exported="true"
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
index 1c9ac3e6..246abb6 100644
--- a/chrome/android/trichrome.gni
+++ b/chrome/android/trichrome.gni
@@ -44,11 +44,13 @@
   android_apk(target_name) {
     forward_variables_from(invoker,
                            [
-                             "apk_name",
                              "android_manifest",
                              "android_manifest_dep",
+                             "apk_name",
+                             "min_sdk_version",
                              "proguard_jar_path",
                              "static_library_dependent_targets",
+                             "target_sdk_version",
                            ])
 
     # TODO(torne): since there's no real java code in the library right now,
diff --git a/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/AndroidManifest.xml b/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/AndroidManifest.xml
index ca4dede478..70449ca 100644
--- a/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/AndroidManifest.xml
+++ b/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/AndroidManifest.xml
@@ -7,8 +7,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.webapk.lib.runtime_library.test.apk_with_webapk_service">
 
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
-
     <application>
         <service android:name="org.chromium.webapk.lib.runtime_library.test.TestWebApkServiceImplWrapper"
             android:exported="true">
diff --git a/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/BUILD.gn b/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/BUILD.gn
index 621899b3..b947475 100644
--- a/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/BUILD.gn
+++ b/chrome/android/webapk/libs/runtime_library/javatests/apk_with_webapk_service/BUILD.gn
@@ -20,4 +20,5 @@
     "//chrome/android/webapk/libs/runtime_library:runtime_library_for_tests_java",
     "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
   ]
+  min_sdk_version = 16
 }
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 3cf3229..45cd24e 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -24,10 +24,6 @@
     <uses-permission android:name="android.permission.VIBRATE"></uses-permission>
     {{{raw_manifest_tags}}}
 
-    <uses-sdk
-        android:minSdkVersion="16"
-        android:targetSdkVersion="28" />
-
     <application
         android:icon="@mipmap/ic_launcher"
         android:label="@string/short_name"
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index d6f80ad..2322927 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -176,6 +176,8 @@
 
     android_manifest = _manifest_output
     android_manifest_dep = ":$_manifest_target_name"
+    min_sdk_version = 16
+    target_sdk_version = 28
     never_incremental = true
     enable_multidex = false
 
diff --git a/chrome/android/webapk/shell_apk/javatests/dex_optimizer/AndroidManifest.xml b/chrome/android/webapk/shell_apk/javatests/dex_optimizer/AndroidManifest.xml
index 96510d7..58a84924 100644
--- a/chrome/android/webapk/shell_apk/javatests/dex_optimizer/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/javatests/dex_optimizer/AndroidManifest.xml
@@ -7,10 +7,6 @@
     package="org.chromium.webapk.shell_apk.test.dex_optimizer"
     android:versionName="1.0" >
 
-    <uses-sdk
-        android:minSdkVersion="16"
-        android:targetSdkVersion="23" />
-
     <application android:label="DexOptimizer">
         <service
             android:name="org.chromium.webapk.shell_apk.test.dex_optimizer.DexOptimizerServiceImpl"
diff --git a/chrome/android/webapk/shell_apk/javatests/dex_optimizer/BUILD.gn b/chrome/android/webapk/shell_apk/javatests/dex_optimizer/BUILD.gn
index 68b51f88..8939869 100644
--- a/chrome/android/webapk/shell_apk/javatests/dex_optimizer/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/javatests/dex_optimizer/BUILD.gn
@@ -21,6 +21,7 @@
   enable_multidex = false
 
   android_manifest = "AndroidManifest.xml"
+  min_sdk_version = 16
   apk_name = "DexOptimizer"
   chromium_code = false
   java_files = [ "src/org/chromium/webapk/shell_apk/test/dex_optimizer/DexOptimizerServiceImpl.java" ]
diff --git a/chrome/app/helper-Info.plist b/chrome/app/helper-Info.plist
index ec0b7b95..6f8600e3d 100644
--- a/chrome/app/helper-Info.plist
+++ b/chrome/app/helper-Info.plist
@@ -9,11 +9,11 @@
 	<key>CFBundleExecutable</key>
 	<string>${EXECUTABLE_NAME}</string>
 	<key>CFBundleIdentifier</key>
-	<string>${CHROMIUM_BUNDLE_ID}.helper</string>
+	<string>${CHROMIUM_BUNDLE_ID}.helper${CHROMIUM_HELPER_BUNDLE_ID_SUFFIX}</string>
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>
-	<string>${CHROMIUM_SHORT_NAME} Helper</string>
+	<string>${CHROMIUM_SHORT_NAME} Helper${CHROMIUM_HELPER_SUFFIX}</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleSignature</key>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 433cb3c..000d10a5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1491,6 +1491,8 @@
     "sessions/session_tab_helper.h",
     "sessions/tab_restore_service_factory.cc",
     "sessions/tab_restore_service_factory.h",
+    "sharing/features.cc",
+    "sharing/features.h",
     "sharing/sharing_device_info.cc",
     "sharing/sharing_device_info.h",
     "sharing/sharing_message_handler.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b9c8d8e..47730bf 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/prerender/prerender_field_trial.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 #include "chrome/browser/search/ntp_features.h"
+#include "chrome/browser/sharing/features.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
 #include "chrome/browser/ui/ui_features.h"
@@ -3440,6 +3441,12 @@
      kOsAll,
      FEATURE_VALUE_TYPE(data_reduction_proxy::features::
                             kDataReductionProxyEnabledWithNetworkService)},
+
+    {"enable-sharing-device-registration",
+     flag_descriptions::kSharingDeviceRegistrationName,
+     flag_descriptions::kSharingDeviceRegistrationDescription, kOsAll,
+     FEATURE_VALUE_TYPE(kSharingDeviceRegistration)},
+
 #if defined(OS_CHROMEOS)
     {"discover-app", flag_descriptions::kEnableDiscoverAppName,
      flag_descriptions::kEnableDiscoverAppDescription, kOsCrOS,
@@ -3930,6 +3937,10 @@
      flag_descriptions::kPeriodicBackgroundSyncDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kPeriodicBackgroundSync)},
 
+    {"font-src-local-matching", flag_descriptions::kFontSrcLocalMatchingName,
+     flag_descriptions::kFontSrcLocalMatchingDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kFontSrcLocalMatching)},
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/feed/feed_debugging_bridge.cc b/chrome/browser/android/feed/feed_debugging_bridge.cc
index 89a455fcf..5d6f501 100644
--- a/chrome/browser/android/feed/feed_debugging_bridge.cc
+++ b/chrome/browser/android/feed/feed_debugging_bridge.cc
@@ -20,7 +20,7 @@
 std::string GetFeedProcessScopeDumpForDebugging() {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jstring> j_string =
-      Java_FeedDebuggingBridge_getFeedProcessScopeDump(env);
+      Java_FeedDebuggingBridge_getProcessScopeDump(env);
   return ConvertJavaStringToUTF8(env, j_string);
 }
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 2bb13b3..612a68c7 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1556,8 +1556,6 @@
     "policy/cached_policy_key_loader_chromeos.h",
     "policy/cloud_external_data_manager_base.cc",
     "policy/cloud_external_data_manager_base.h",
-    "policy/cloud_external_data_policy_handler.cc",
-    "policy/cloud_external_data_policy_handler.h",
     "policy/cloud_external_data_policy_observer.cc",
     "policy/cloud_external_data_policy_observer.h",
     "policy/cloud_external_data_store.cc",
@@ -1574,8 +1572,6 @@
     "policy/device_auto_update_time_restrictions_decoder.h",
     "policy/device_auto_update_time_restrictions_utils.cc",
     "policy/device_auto_update_time_restrictions_utils.h",
-    "policy/device_cloud_external_data_policy_handler.cc",
-    "policy/device_cloud_external_data_policy_handler.h",
     "policy/device_cloud_external_data_policy_observer.cc",
     "policy/device_cloud_external_data_policy_observer.h",
     "policy/device_cloud_policy_initializer.cc",
@@ -1600,8 +1596,6 @@
     "policy/device_local_account_policy_service.h",
     "policy/device_local_account_policy_store.cc",
     "policy/device_local_account_policy_store.h",
-    "policy/device_native_printers_external_data_handler.cc",
-    "policy/device_native_printers_external_data_handler.h",
     "policy/device_network_configuration_updater.cc",
     "policy/device_network_configuration_updater.h",
     "policy/device_policy_cloud_external_data_manager.cc",
@@ -1611,12 +1605,8 @@
     "policy/device_policy_remover.h",
     "policy/device_scheduled_update_checker.cc",
     "policy/device_scheduled_update_checker.h",
-    "policy/device_wallpaper_image_external_data_handler.cc",
-    "policy/device_wallpaper_image_external_data_handler.h",
     "policy/device_wifi_allowed_handler.cc",
     "policy/device_wifi_allowed_handler.h",
-    "policy/device_wilco_dtc_configuration_external_data_handler.cc",
-    "policy/device_wilco_dtc_configuration_external_data_handler.h",
     "policy/display_resolution_handler.cc",
     "policy/display_resolution_handler.h",
     "policy/display_rotation_default_handler.cc",
@@ -1631,6 +1621,22 @@
     "policy/enrollment_handler_chromeos.h",
     "policy/enrollment_status_chromeos.cc",
     "policy/enrollment_status_chromeos.h",
+    "policy/external_data_handlers/cloud_external_data_policy_handler.cc",
+    "policy/external_data_handlers/cloud_external_data_policy_handler.h",
+    "policy/external_data_handlers/device_cloud_external_data_policy_handler.cc",
+    "policy/external_data_handlers/device_cloud_external_data_policy_handler.h",
+    "policy/external_data_handlers/device_native_printers_external_data_handler.cc",
+    "policy/external_data_handlers/device_native_printers_external_data_handler.h",
+    "policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc",
+    "policy/external_data_handlers/device_wallpaper_image_external_data_handler.h",
+    "policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc",
+    "policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h",
+    "policy/external_data_handlers/native_printers_external_data_handler.cc",
+    "policy/external_data_handlers/native_printers_external_data_handler.h",
+    "policy/external_data_handlers/user_avatar_image_external_data_handler.cc",
+    "policy/external_data_handlers/user_avatar_image_external_data_handler.h",
+    "policy/external_data_handlers/wallpaper_image_external_data_handler.cc",
+    "policy/external_data_handlers/wallpaper_image_external_data_handler.h",
     "policy/fake_auto_enrollment_client.cc",
     "policy/fake_auto_enrollment_client.h",
     "policy/heartbeat_scheduler.cc",
@@ -1643,8 +1649,6 @@
     "policy/login_profile_policy_provider.h",
     "policy/minimum_version_policy_handler.cc",
     "policy/minimum_version_policy_handler.h",
-    "policy/native_printers_external_data_handler.cc",
-    "policy/native_printers_external_data_handler.h",
     "policy/network_configuration_updater.cc",
     "policy/network_configuration_updater.h",
     "policy/off_hours/device_off_hours_controller.cc",
@@ -1718,8 +1722,6 @@
     "policy/upload_job.h",
     "policy/upload_job_impl.cc",
     "policy/upload_job_impl.h",
-    "policy/user_avatar_image_external_data_handler.cc",
-    "policy/user_avatar_image_external_data_handler.h",
     "policy/user_cloud_external_data_manager.cc",
     "policy/user_cloud_external_data_manager.h",
     "policy/user_cloud_policy_manager_chromeos.cc",
@@ -1741,8 +1743,6 @@
     "policy/value_validation/onc_policy_value_validator_base.h",
     "policy/value_validation/onc_user_policy_value_validator.cc",
     "policy/value_validation/onc_user_policy_value_validator.h",
-    "policy/wallpaper_image_external_data_handler.cc",
-    "policy/wallpaper_image_external_data_handler.h",
     "policy/wildcard_login_checker.cc",
     "policy/wildcard_login_checker.h",
     "power/auto_screen_brightness/adapter.cc",
@@ -2565,11 +2565,11 @@
     "policy/device_cloud_policy_manager_chromeos_unittest.cc",
     "policy/device_cloud_policy_store_chromeos_unittest.cc",
     "policy/device_local_account_policy_service_unittest.cc",
-    "policy/device_native_printers_external_data_handler_unittest.cc",
     "policy/device_policy_decoder_chromeos_unittest.cc",
     "policy/device_scheduled_update_checker_unittest.cc",
     "policy/dm_token_storage_unittest.cc",
     "policy/extension_cache_unittest.cc",
+    "policy/external_data_handlers/device_native_printers_external_data_handler_unittest.cc",
     "policy/fake_affiliated_invalidation_service_provider.cc",
     "policy/fake_affiliated_invalidation_service_provider.h",
     "policy/heartbeat_scheduler_unittest.cc",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index a5319789..3f6695e 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -2220,7 +2220,7 @@
   }
 
   if (name == "enableTabletMode") {
-    ash::ShellTestApi().EnableTabletModeWindowManager(true);
+    ash::ShellTestApi().SetTabletModeEnabledForTest(true);
     *output = "tabletModeEnabled";
     return;
   }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index e906258..7bb221b 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -51,9 +51,9 @@
 #include "chrome/browser/chromeos/login/users/supervised_user_manager_impl.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
-#include "chrome/browser/chromeos/policy/native_printers_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.h"
-#include "chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h"
 #include "chrome/browser/chromeos/printing/bulk_printers_calculator_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/session_length_limiter.h"
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 41369d37..f62c3bdaa 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -29,14 +29,14 @@
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
-#include "chrome/browser/chromeos/policy/device_native_printers_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/device_scheduled_update_checker.h"
-#include "chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/device_wifi_allowed_handler.h"
-#include "chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/hostname_handler.h"
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
 #include "chrome/browser/chromeos/policy/remote_commands/affiliated_remote_commands_invalidator.h"
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/OWNERS b/chrome/browser/chromeos/policy/external_data_handlers/OWNERS
new file mode 100644
index 0000000..19c7210
--- /dev/null
+++ b/chrome/browser/chromeos/policy/external_data_handlers/OWNERS
@@ -0,0 +1,4 @@
+emaxx@chromium.org
+nikitapodguzov@chromium.org
+
+# COMPONENT: Enterprise
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.cc
similarity index 85%
rename from chrome/browser/chromeos/policy/cloud_external_data_policy_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.cc
index 680b47c..3639172 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.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/chromeos/policy/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
 #include "components/user_manager/known_user.h"
 
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h
similarity index 70%
rename from chrome/browser/chromeos/policy/cloud_external_data_policy_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h
index e92185b..04e5157 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
 
 #include "chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h"
 
@@ -26,4 +26,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.cc
similarity index 73%
rename from chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.cc
index 1b395342..f643e31 100644
--- a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.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/chromeos/policy/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h
similarity index 67%
rename from chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h
index 9110277..415622f 100644
--- a/chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
 
 #include "chrome/browser/chromeos/policy/device_cloud_external_data_policy_observer.h"
 
@@ -24,4 +24,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_CLOUD_EXTERNAL_DATA_POLICY_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/device_native_printers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.cc
similarity index 93%
rename from chrome/browser/chromeos/policy/device_native_printers_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.cc
index d78affd..06543fb3 100644
--- a/chrome/browser/chromeos/policy/device_native_printers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.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/chromeos/policy/device_native_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/device_native_printers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.h
similarity index 71%
rename from chrome/browser/chromeos/policy/device_native_printers_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.h
index 76c979a2..2e948ed 100644
--- a/chrome/browser/chromeos/policy/device_native_printers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
 
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
 
 namespace policy {
 
@@ -38,4 +38,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/device_native_printers_external_data_handler_unittest.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler_unittest.cc
similarity index 97%
rename from chrome/browser/chromeos/policy/device_native_printers_external_data_handler_unittest.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler_unittest.cc
index 6e04767..5735e25 100644
--- a/chrome/browser/chromeos/policy/device_native_printers_external_data_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler_unittest.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/chromeos/policy/device_native_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_native_printers_external_data_handler.h"
 
 #include <memory>
 #include <string>
diff --git a/chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc
similarity index 93%
rename from chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.cc
index 33ca07d6..5c0e75e 100644
--- a/chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.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/chromeos/policy/device_wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h
similarity index 76%
rename from chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h
index e42f3ba5..964a9063 100644
--- a/chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
 
 class PrefRegistrySimple;
 class PrefService;
@@ -48,4 +48,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
similarity index 93%
rename from chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.cc
index bfd2c05..0403f9fb 100644
--- a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.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/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h"
 
 #include "chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_manager.h"
 #include "components/policy/policy_constants.h"
diff --git a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h
similarity index 73%
rename from chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h
index 89f8d3e..6f12691b 100644
--- a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/device_wilco_dtc_configuration_external_data_handler.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_WILCO_DTC_CONFIGURATION_EXTERNAL_DATA_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_WILCO_DTC_CONFIGURATION_EXTERNAL_DATA_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_WILCO_DTC_CONFIGURATION_EXTERNAL_DATA_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_WILCO_DTC_CONFIGURATION_EXTERNAL_DATA_HANDLER_H_
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "chrome/browser/chromeos/policy/device_cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_cloud_external_data_policy_handler.h"
 
 namespace policy {
 
@@ -41,4 +41,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_WILCO_DTC_CONFIGURATION_EXTERNAL_DATA_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_DEVICE_WILCO_DTC_CONFIGURATION_EXTERNAL_DATA_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/native_printers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.cc
similarity index 94%
rename from chrome/browser/chromeos/policy/native_printers_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.cc
index 3c97de6..db5ed4cf 100644
--- a/chrome/browser/chromeos/policy/native_printers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.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/chromeos/policy/native_printers_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/native_printers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.h
similarity index 76%
rename from chrome/browser/chromeos/policy/native_printers_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.h
index 52a87111..e7ce24c 100644
--- a/chrome/browser/chromeos/policy/native_printers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/native_printers_external_data_handler.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
 
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
 namespace chromeos {
 class CrosSettings;
@@ -45,4 +45,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_NATIVE_PRINTERS_EXTERNAL_DATA_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
similarity index 94%
rename from chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
index d22dec4..a01465bf 100644
--- a/chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.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/chromeos/policy/user_avatar_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
similarity index 76%
rename from chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
index 8bf1535..69c43d7 100644
--- a/chrome/browser/chromeos/policy/user_avatar_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_USER_AVATAR_IMAGE_EXTERNAL_DATA_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_USER_AVATAR_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_USER_AVATAR_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_USER_AVATAR_IMAGE_EXTERNAL_DATA_HANDLER_H_
 
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
 namespace chromeos {
 class CrosSettings;
@@ -45,4 +45,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_USER_AVATAR_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_USER_AVATAR_IMAGE_EXTERNAL_DATA_HANDLER_H_
diff --git a/chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
similarity index 93%
rename from chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.cc
rename to chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
index 1944de1..ceaa5edd 100644
--- a/chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.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/chromeos/policy/wallpaper_image_external_data_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
similarity index 75%
rename from chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.h
rename to chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
index ba2cf38..dd1550c 100644
--- a/chrome/browser/chromeos/policy/wallpaper_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
 
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/policy/cloud_external_data_policy_handler.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
 namespace chromeos {
 class CrosSettings;
@@ -43,4 +43,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_EXTERNAL_DATA_HANDLERS_WALLPAPER_IMAGE_EXTERNAL_DATA_HANDLER_H_
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
index f4f9013..ad64682 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
@@ -19,71 +19,22 @@
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "components/sync_device_info/device_info.h"
 #include "components/sync_device_info/device_info_sync_service.h"
-#include "components/sync_device_info/device_info_tracker.h"
+#include "components/sync_device_info/fake_device_info_tracker.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/common/extension.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using syncer::DeviceInfo;
-using syncer::DeviceInfoTracker;
+using syncer::FakeDeviceInfoTracker;
 using testing::Return;
 
 namespace extensions {
 
-class MockDeviceInfoTracker : public DeviceInfoTracker {
- public:
-  ~MockDeviceInfoTracker() override {}
-
-  bool IsSyncing() const override { return !devices_.empty(); }
-
-  std::unique_ptr<DeviceInfo> GetDeviceInfo(
-      const std::string& client_id) const override {
-    NOTREACHED();
-    return std::unique_ptr<DeviceInfo>();
-  }
-
-  static std::unique_ptr<DeviceInfo> CloneDeviceInfo(
-      const DeviceInfo& device_info) {
-    return std::make_unique<DeviceInfo>(
-        device_info.guid(), device_info.client_name(),
-        device_info.chrome_version(), device_info.sync_user_agent(),
-        device_info.device_type(), device_info.signin_scoped_device_id(),
-        device_info.last_updated_timestamp(),
-        device_info.send_tab_to_self_receiving_enabled());
-  }
-
-  std::vector<std::unique_ptr<DeviceInfo>> GetAllDeviceInfo() const override {
-    std::vector<std::unique_ptr<DeviceInfo>> list;
-
-    for (const DeviceInfo* device : devices_)
-      list.push_back(CloneDeviceInfo(*device));
-
-    return list;
-  }
-
-  void AddObserver(Observer* observer) override { NOTREACHED(); }
-
-  void RemoveObserver(Observer* observer) override { NOTREACHED(); }
-
-  int CountActiveDevices() const override {
-    NOTREACHED();
-    return 0;
-  }
-
-  void Add(const DeviceInfo* device) { devices_.push_back(device); }
-
-  void ForcePulseForTest() override { NOTREACHED(); }
-
- private:
-  // DeviceInfo stored here are not owned.
-  std::vector<const DeviceInfo*> devices_;
-};
-
 TEST(SignedInDevicesAPITest, GetSignedInDevices) {
   content::TestBrowserThreadBundle thread_bundle;
   TestingProfile profile;
-  MockDeviceInfoTracker device_tracker;
+  FakeDeviceInfoTracker device_tracker;
   TestExtensionPrefs extension_prefs(base::ThreadTaskRunnerHandle::Get().get());
 
   // Add a couple of devices and make sure we get back public ids for them.
@@ -140,7 +91,7 @@
   MockDeviceInfoSyncService() = default;
   ~MockDeviceInfoSyncService() override = default;
 
-  MockDeviceInfoTracker* mock_tracker() { return &tracker_; }
+  FakeDeviceInfoTracker* fake_tracker() { return &tracker_; }
 
   // DeviceInfoSyncService implementation.
   syncer::LocalDeviceInfoProvider* GetLocalDeviceInfoProvider() override {
@@ -155,7 +106,7 @@
   }
 
  private:
-  MockDeviceInfoTracker tracker_;
+  FakeDeviceInfoTracker tracker_;
 };
 
 std::unique_ptr<KeyedService> CreateMockDeviceInfoSyncService(
@@ -200,10 +151,10 @@
 }
 
 TEST_F(ExtensionSignedInDevicesTest, GetAll) {
-  MockDeviceInfoTracker* device_tracker =
+  FakeDeviceInfoTracker* device_tracker =
       static_cast<MockDeviceInfoSyncService*>(
           DeviceInfoSyncServiceFactory::GetForProfile(profile()))
-          ->mock_tracker();
+          ->fake_tracker();
 
   DeviceInfo device_info1(base::GenerateGUID(), "abc Device", "XYZ v1",
                           "XYZ SyncAgent v1",
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index bb577934..9cfe681 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -152,29 +152,6 @@
   SentMessages sent_messages_;
 };
 
-class TestLogger : public WebRequestInfoLogger {
- public:
-  TestLogger() = default;
-  ~TestLogger() override = default;
-
-  size_t log_size() const { return events_.size(); }
-  void clear() { events_.clear(); }
-
-  // WebRequestInfo::Logger:
-  void LogEvent(net::NetLogEventType event_type,
-                const std::string& extension_id) override {
-    events_.push_back({event_type, extension_id});
-  }
-  void LogBlockedBy(const std::string& blocker_info) override {}
-  void LogUnblocked() override {}
-
- private:
-  using Event = std::pair<net::NetLogEventType, std::string>;
-  std::vector<Event> events_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestLogger);
-};
-
 class ExtensionWebRequestTest : public testing::Test {
  public:
   ExtensionWebRequestTest()
@@ -561,7 +538,6 @@
 
 TEST(ExtensionWebRequestHelpersTest, TestMergeCancelOfResponses) {
   EventResponseDeltas deltas;
-  TestLogger logger;
   bool canceled = false;
 
   // Single event that does not cancel.
@@ -570,9 +546,8 @@
     d1.cancel = false;
     deltas.push_back(std::move(d1));
   }
-  MergeCancelOfResponses(deltas, &canceled, &logger);
+  MergeCancelOfResponses(deltas, &canceled);
   EXPECT_FALSE(canceled);
-  EXPECT_EQ(0u, logger.log_size());
 
   // Second event that cancels the request
   {
@@ -581,14 +556,12 @@
     deltas.push_back(std::move(d2));
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
-  MergeCancelOfResponses(deltas, &canceled, &logger);
+  MergeCancelOfResponses(deltas, &canceled);
   EXPECT_TRUE(canceled);
-  EXPECT_EQ(1u, logger.log_size());
 }
 
 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses) {
   EventResponseDeltas deltas;
-  TestLogger logger;
   helpers::IgnoredActions ignored_actions;
   GURL effective_new_url;
 
@@ -598,7 +571,7 @@
     deltas.push_back(std::move(d0));
   }
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_TRUE(effective_new_url.is_empty());
 
   // Single redirect.
@@ -609,12 +582,10 @@
     deltas.push_back(std::move(d1));
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_1, effective_new_url);
   EXPECT_TRUE(ignored_actions.empty());
-  EXPECT_EQ(1u, logger.log_size());
 
   // Ignored redirect (due to precedence).
   GURL new_url_2("http://bar.com");
@@ -625,14 +596,12 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_1, effective_new_url);
   EXPECT_EQ(1u, ignored_actions.size());
   EXPECT_TRUE(HasIgnoredAction(ignored_actions, "extid2",
                                web_request::IGNORED_ACTION_TYPE_REDIRECT));
-  EXPECT_EQ(2u, logger.log_size());
 
   // Overriding redirect.
   GURL new_url_3("http://baz.com");
@@ -643,16 +612,14 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_3, effective_new_url);
   EXPECT_EQ(2u, ignored_actions.size());
   EXPECT_TRUE(HasIgnoredAction(ignored_actions, "extid1",
                                web_request::IGNORED_ACTION_TYPE_REDIRECT));
   EXPECT_TRUE(HasIgnoredAction(ignored_actions, "extid2",
                                web_request::IGNORED_ACTION_TYPE_REDIRECT));
-  EXPECT_EQ(3u, logger.log_size());
 
   // Check that identical redirects don't cause a conflict.
   {
@@ -662,23 +629,20 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_3, effective_new_url);
   EXPECT_EQ(2u, ignored_actions.size());
   EXPECT_TRUE(HasIgnoredAction(ignored_actions, "extid1",
                                web_request::IGNORED_ACTION_TYPE_REDIRECT));
   EXPECT_TRUE(HasIgnoredAction(ignored_actions, "extid2",
                                web_request::IGNORED_ACTION_TYPE_REDIRECT));
-  EXPECT_EQ(4u, logger.log_size());
 }
 
 // This tests that we can redirect to data:// urls, which is considered
 // a kind of cancelling requests.
 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses2) {
   EventResponseDeltas deltas;
-  TestLogger logger;
   helpers::IgnoredActions ignored_actions;
   GURL effective_new_url;
 
@@ -690,7 +654,7 @@
     deltas.push_back(std::move(d0));
   }
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_0, effective_new_url);
 
   // Cancel request by redirecting to a data:// URL. This shall override
@@ -703,12 +667,10 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_1, effective_new_url);
   EXPECT_TRUE(ignored_actions.empty());
-  EXPECT_EQ(1u, logger.log_size());
 
   // Cancel request by redirecting to the same data:// URL. This shall
   // not create any conflicts as it is in line with d1.
@@ -720,13 +682,11 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
 
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_1, effective_new_url);
   EXPECT_TRUE(ignored_actions.empty());
-  EXPECT_EQ(2u, logger.log_size());
 
   // Cancel redirect by redirecting to a different data:// URL. This needs
   // to create a conflict.
@@ -738,21 +698,18 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_1, effective_new_url);
   EXPECT_EQ(1u, ignored_actions.size());
   EXPECT_TRUE(HasIgnoredAction(ignored_actions, "extid3",
                                web_request::IGNORED_ACTION_TYPE_REDIRECT));
-  EXPECT_EQ(3u, logger.log_size());
 }
 
 // This tests that we can redirect to about:blank, which is considered
 // a kind of cancelling requests.
 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses3) {
   EventResponseDeltas deltas;
-  TestLogger logger;
   helpers::IgnoredActions ignored_actions;
   GURL effective_new_url;
 
@@ -764,7 +721,7 @@
     deltas.push_back(std::move(d0));
   }
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_0, effective_new_url);
 
   // Cancel request by redirecting to about:blank. This shall override
@@ -777,18 +734,15 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   MergeOnBeforeRequestResponses(GURL(kExampleUrl), deltas, &effective_new_url,
-                                &ignored_actions, &logger);
+                                &ignored_actions);
   EXPECT_EQ(new_url_1, effective_new_url);
   EXPECT_TRUE(ignored_actions.empty());
-  EXPECT_EQ(1u, logger.log_size());
 }
 
 // This tests that WebSocket requests can not be redirected.
 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses4) {
   EventResponseDeltas deltas;
-  TestLogger logger;
   helpers::IgnoredActions ignored_actions;
   GURL effective_new_url;
 
@@ -799,7 +753,7 @@
     deltas.push_back(std::move(delta));
   }
   MergeOnBeforeRequestResponses(GURL("ws://example.com"), deltas,
-                                &effective_new_url, &ignored_actions, &logger);
+                                &effective_new_url, &ignored_actions);
   EXPECT_EQ(GURL(), effective_new_url);
 }
 
@@ -821,11 +775,8 @@
   net::HttpRequestHeaders headers0;
   headers0.MergeFrom(base_headers);
   WebRequestInfoInitParams info_params;
-  info_params.logger = std::make_unique<TestLogger>();
   WebRequestInfo info(std::move(info_params));
   info.dnr_action.emplace(Action::Type::NONE);
-  // Take a reference to TestLogger to simplify accessing TestLogger methods.
-  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
   MergeOnBeforeSendHeadersResponses(info, deltas, &headers0, &ignored_actions,
                                     &ignore1, &ignore2,
                                     &request_headers_modified0);
@@ -834,7 +785,6 @@
   ASSERT_TRUE(headers0.GetHeader("key2", &header_value));
   EXPECT_EQ("value 2", header_value);
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(0u, logger.log_size());
   EXPECT_FALSE(request_headers_modified0);
 
   // Delete, modify and add a header.
@@ -847,7 +797,6 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   ignore1.clear();
   ignore2.clear();
   bool request_headers_modified1;
@@ -862,7 +811,6 @@
   ASSERT_TRUE(headers1.GetHeader("key3", &header_value));
   EXPECT_EQ("value 3", header_value);
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(1u, logger.log_size());
   EXPECT_TRUE(request_headers_modified1);
 
   // Check that conflicts are atomic, i.e. if one header modification
@@ -876,7 +824,6 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   ignore1.clear();
   ignore2.clear();
   bool request_headers_modified2;
@@ -895,7 +842,6 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid2",
                        web_request::IGNORED_ACTION_TYPE_REQUEST_HEADERS));
-  EXPECT_EQ(2u, logger.log_size());
   EXPECT_TRUE(request_headers_modified2);
 
   // Check that identical modifications don't conflict and operations
@@ -909,7 +855,6 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   ignore1.clear();
   ignore2.clear();
   bool request_headers_modified3;
@@ -929,13 +874,11 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid2",
                        web_request::IGNORED_ACTION_TYPE_REQUEST_HEADERS));
-  EXPECT_EQ(3u, logger.log_size());
   EXPECT_TRUE(request_headers_modified3);
 
   // Check that headers removed by Declarative Net Request API can't be modified
   // and result in a conflict.
   ignored_actions.clear();
-  logger.clear();
   ignore1.clear();
   ignore2.clear();
   bool request_headers_modified4 = false;
@@ -963,7 +906,6 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid3",
                        web_request::IGNORED_ACTION_TYPE_REQUEST_HEADERS));
-  EXPECT_EQ(3u, logger.log_size());
   EXPECT_TRUE(request_headers_modified4);
 }
 
@@ -989,7 +931,6 @@
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
 
   WebRequestInfoInitParams info_params;
-  info_params.logger = std::make_unique<TestLogger>();
   WebRequestInfo info(std::move(info_params));
   info.dnr_action.emplace(Action::Type::NONE);
   helpers::IgnoredActions ignored_actions;
@@ -999,9 +940,6 @@
   net::HttpRequestHeaders headers;
   headers.SetHeader("key1", "value 1");
 
-  // Take a reference to TestLogger to simplify accessing TestLogger methods.
-  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
-
   MergeOnBeforeSendHeadersResponses(info, deltas, &headers, &ignored_actions,
                                     &removed_headers, &set_headers,
                                     &request_headers_modified);
@@ -1010,7 +948,6 @@
   ASSERT_TRUE(headers.GetHeader("key1", &header_value));
   EXPECT_EQ("ext1", header_value);
   EXPECT_EQ(1u, ignored_actions.size());
-  EXPECT_EQ(2u, logger.log_size());
   EXPECT_TRUE(request_headers_modified);
   EXPECT_THAT(removed_headers, ::testing::IsEmpty());
   EXPECT_THAT(set_headers, ElementsAre("key1"));
@@ -1067,10 +1004,7 @@
   ignored_actions.clear();
 
   WebRequestInfoInitParams info_params;
-  info_params.logger = std::make_unique<TestLogger>();
   WebRequestInfo info(std::move(info_params));
-  // Take a reference to TestLogger to simplify accessing TestLogger methods.
-  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
   MergeOnBeforeSendHeadersResponses(info, deltas, &headers1, &ignored_actions,
                                     &ignore1, &ignore2,
                                     &request_headers_modified1);
@@ -1078,7 +1012,6 @@
   ASSERT_TRUE(headers1.GetHeader("Cookie", &header_value));
   EXPECT_EQ("name=new value; name2=new value; name4=\"value 4\"", header_value);
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(0u, logger.log_size());
   EXPECT_FALSE(request_headers_modified1);
 }
 
@@ -1110,7 +1043,6 @@
 
 TEST(ExtensionWebRequestHelpersTest,
      TestMergeCookiesInOnHeadersReceivedResponses) {
-  TestLogger logger;
   std::string header_value;
   EventResponseDeltas deltas;
 
@@ -1144,9 +1076,8 @@
   }
   scoped_refptr<net::HttpResponseHeaders> new_headers0;
   MergeCookiesInOnHeadersReceivedResponses(GURL(), deltas, base_headers.get(),
-                                           &new_headers0, &logger);
+                                           &new_headers0);
   EXPECT_FALSE(new_headers0.get());
-  EXPECT_EQ(0u, logger.log_size());
 
   ResponseCookieModification add_cookie;
   add_cookie.type = helpers::ADD;
@@ -1294,7 +1225,7 @@
       net::HttpUtil::AssembleRawHeaders(base_headers_string));
   scoped_refptr<net::HttpResponseHeaders> new_headers1;
   MergeCookiesInOnHeadersReceivedResponses(GURL(), deltas, headers1.get(),
-                                           &new_headers1, &logger);
+                                           &new_headers1);
 
   EXPECT_TRUE(new_headers1->HasHeader("Foo"));
   size_t iter = 0;
@@ -1318,7 +1249,6 @@
   while (new_headers1->EnumerateHeader(&iter, "Set-Cookie", &cookie_string))
     actual_cookies.insert(cookie_string);
   EXPECT_EQ(expected_cookies, actual_cookies);
-  EXPECT_EQ(0u, logger.log_size());
 }
 
 TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) {
@@ -1344,11 +1274,8 @@
   GURL allowed_unsafe_redirect_url0;
   WebRequestInfoInitParams info_params;
   info_params.url = GURL(kExampleUrl);
-  info_params.logger = std::make_unique<TestLogger>();
   WebRequestInfo info(std::move(info_params));
   info.dnr_action.emplace(Action::Type::NONE);
-  // Take a reference to TestLogger to simplify accessing TestLogger methods.
-  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
 
   MergeOnHeadersReceivedResponses(info, deltas, base_headers.get(),
                                   &new_headers0, &allowed_unsafe_redirect_url0,
@@ -1357,7 +1284,6 @@
   EXPECT_FALSE(new_headers0.get());
   EXPECT_TRUE(allowed_unsafe_redirect_url0.is_empty());
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(0u, logger.log_size());
   EXPECT_FALSE(response_headers_modified0);
 
   {
@@ -1371,7 +1297,6 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   bool response_headers_modified1;
   scoped_refptr<net::HttpResponseHeaders> new_headers1;
   GURL allowed_unsafe_redirect_url1;
@@ -1393,7 +1318,6 @@
   }
   EXPECT_EQ(expected1, actual1);
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(1u, logger.log_size());
   EXPECT_TRUE(response_headers_modified1);
 
   // Check that we replace response headers only once.
@@ -1408,7 +1332,6 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   bool response_headers_modified2;
   scoped_refptr<net::HttpResponseHeaders> new_headers2;
   GURL allowed_unsafe_redirect_url2;
@@ -1428,7 +1351,6 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid2",
                        web_request::IGNORED_ACTION_TYPE_RESPONSE_HEADERS));
-  EXPECT_EQ(2u, logger.log_size());
   EXPECT_TRUE(response_headers_modified2);
 
   // Ensure headers removed by Declarative Net Request API can't be added by web
@@ -1436,7 +1358,6 @@
   info.dnr_action.emplace(Action::Type::REMOVE_HEADERS);
   info.dnr_action->response_headers_to_remove = {"key3"};
   ignored_actions.clear();
-  logger.clear();
   bool response_headers_modified3 = false;
   scoped_refptr<net::HttpResponseHeaders> new_headers3;
   GURL allowed_unsafe_redirect_url3;
@@ -1458,7 +1379,6 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid1",
                        web_request::IGNORED_ACTION_TYPE_RESPONSE_HEADERS));
-  EXPECT_EQ(2u, logger.log_size());
   EXPECT_TRUE(response_headers_modified3);
 }
 
@@ -1490,11 +1410,8 @@
 
   WebRequestInfoInitParams info_params;
   info_params.url = GURL(kExampleUrl);
-  info_params.logger = std::make_unique<TestLogger>();
   WebRequestInfo info(std::move(info_params));
   info.dnr_action.emplace(Action::Type::NONE);
-  // Take a reference to TestLogger to simplify accessing TestLogger methods.
-  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
 
   MergeOnHeadersReceivedResponses(info, deltas, base_headers.get(),
                                   &new_headers1, &allowed_unsafe_redirect_url1,
@@ -1515,7 +1432,6 @@
   }
   EXPECT_EQ(expected1, actual1);
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(1u, logger.log_size());
   EXPECT_TRUE(response_headers_modified1);
 }
 
@@ -1544,10 +1460,7 @@
 
   WebRequestInfoInitParams info_params;
   info_params.url = GURL(kExampleUrl);
-  info_params.logger = std::make_unique<TestLogger>();
   WebRequestInfo info(std::move(info_params));
-  // Take a reference to TestLogger to simplify accessing TestLogger methods.
-  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
 
   MergeOnHeadersReceivedResponses(info, deltas, base_headers.get(),
                                   &new_headers0, &allowed_unsafe_redirect_url0,
@@ -1556,7 +1469,6 @@
   EXPECT_FALSE(new_headers0.get());
   EXPECT_TRUE(allowed_unsafe_redirect_url0.is_empty());
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(0u, logger.log_size());
   EXPECT_FALSE(response_headers_modified0);
 
   // Single redirect.
@@ -1567,7 +1479,6 @@
     deltas.push_back(std::move(d1));
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
-  logger.clear();
   bool response_headers_modified1;
 
   scoped_refptr<net::HttpResponseHeaders> new_headers1;
@@ -1581,12 +1492,10 @@
   EXPECT_TRUE(new_headers1->HasHeaderValue("Location", new_url_1.spec()));
   EXPECT_EQ(new_url_1, allowed_unsafe_redirect_url1);
   EXPECT_TRUE(ignored_actions.empty());
-  EXPECT_EQ(1u, logger.log_size());
   EXPECT_FALSE(response_headers_modified1);
 }
 
 TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) {
-  TestLogger logger;
   helpers::IgnoredActions ignored_actions;
   EventResponseDeltas deltas;
   base::string16 username = base::ASCIIToUTF16("foo");
@@ -1600,11 +1509,10 @@
   }
   net::AuthCredentials auth0;
   bool credentials_set =
-      MergeOnAuthRequiredResponses(deltas, &auth0, &ignored_actions, &logger);
+      MergeOnAuthRequiredResponses(deltas, &auth0, &ignored_actions);
   EXPECT_FALSE(credentials_set);
   EXPECT_TRUE(auth0.Empty());
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(0u, logger.log_size());
 
   // Check that we can set AuthCredentials.
   {
@@ -1614,16 +1522,14 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   net::AuthCredentials auth1;
   credentials_set =
-      MergeOnAuthRequiredResponses(deltas, &auth1, &ignored_actions, &logger);
+      MergeOnAuthRequiredResponses(deltas, &auth1, &ignored_actions);
   EXPECT_TRUE(credentials_set);
   EXPECT_FALSE(auth1.Empty());
   EXPECT_EQ(username, auth1.username());
   EXPECT_EQ(password, auth1.password());
   EXPECT_EQ(0u, ignored_actions.size());
-  EXPECT_EQ(1u, logger.log_size());
 
   // Check that we set AuthCredentials only once.
   {
@@ -1633,10 +1539,9 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   net::AuthCredentials auth2;
   credentials_set =
-      MergeOnAuthRequiredResponses(deltas, &auth2, &ignored_actions, &logger);
+      MergeOnAuthRequiredResponses(deltas, &auth2, &ignored_actions);
   EXPECT_TRUE(credentials_set);
   EXPECT_FALSE(auth2.Empty());
   EXPECT_EQ(username, auth1.username());
@@ -1645,7 +1550,6 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid2",
                        web_request::IGNORED_ACTION_TYPE_AUTH_CREDENTIALS));
-  EXPECT_EQ(2u, logger.log_size());
 
   // Check that we can set identical AuthCredentials twice without causing
   // a conflict.
@@ -1656,10 +1560,9 @@
   }
   deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
   ignored_actions.clear();
-  logger.clear();
   net::AuthCredentials auth3;
   credentials_set =
-      MergeOnAuthRequiredResponses(deltas, &auth3, &ignored_actions, &logger);
+      MergeOnAuthRequiredResponses(deltas, &auth3, &ignored_actions);
   EXPECT_TRUE(credentials_set);
   EXPECT_FALSE(auth3.Empty());
   EXPECT_EQ(username, auth1.username());
@@ -1668,7 +1571,6 @@
   EXPECT_TRUE(
       HasIgnoredAction(ignored_actions, "extid2",
                        web_request::IGNORED_ACTION_TYPE_AUTH_CREDENTIALS));
-  EXPECT_EQ(3u, logger.log_size());
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc
index cdc589f..6795758 100644
--- a/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/system_display/display_info_provider_chromeos_unittest.cc
@@ -85,9 +85,7 @@
     // Wait for TabletModeController to take its initial state from the power
     // manager.
     base::RunLoop().RunUntilIdle();
-    EXPECT_FALSE(ash::Shell::Get()
-                     ->tablet_mode_controller()
-                     ->IsTabletModeWindowManagerEnabled());
+    EXPECT_FALSE(ash::Shell::Get()->tablet_mode_controller()->InTabletMode());
   }
 
   void TearDown() override {
@@ -129,7 +127,7 @@
   void EnableTabletMode(bool enable) {
     ash::TabletModeController* controller =
         ash::Shell::Get()->tablet_mode_controller();
-    controller->EnableTabletModeWindowManager(enable);
+    controller->SetEnabledForTest(enable);
   }
 
   display::DisplayManager* GetDisplayManager() const {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 6c52f90..d41e853 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1555,6 +1555,11 @@
     "expiry_milestone": 77
   },
   {
+    "name": "enable-sharing-device-registration",
+    "owners": [ "//chrome/browser/sharing/OWNERS" ],
+    "expiry_milestone": 77
+  },
+  {
     "name": "enable-show-autofill-signatures",
     "owners": [ "kolos" ],
     // Used for debugging and QA by the autofill team for the indefinite future.
@@ -1932,6 +1937,11 @@
     "expiry_milestone": -1
   },
   {
+    "name": "font-src-local-matching",
+    "owners": [ "drott", "layout-dev" ],
+    "expiry_milestone": 82
+  },
+  {
     "name": "force-use-chrome-camera",
     "owners": [ "shenghao", "chromeos-camera-app-eng@google.com" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 00dcfa8..4e07df4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -282,6 +282,14 @@
 const char kFocusModeDescription[] =
     "If enabled, allows the user to switch to Focus Mode";
 
+const char kFontSrcLocalMatchingName[] =
+    "Match @font-face { src: local(<name>) } names by PostScript and full font "
+    "name.";
+const char kFontSrcLocalMatchingDescription[] =
+    "Match local() src attributes in @font-face declarations precisely by "
+    "PostScript name and full font name instead of the previous behavior of "
+    "matching those unspecifically as family names.";
+
 const char kForceColorProfileSRGB[] = "sRGB";
 const char kForceColorProfileP3[] = "Display P3 D65";
 const char kForceColorProfileColorSpin[] = "Color spin with gamma 2.4";
@@ -1642,6 +1650,12 @@
 const char kSettingsWindowDescription[] =
     "Settings will be shown in a dedicated window instead of as a browser tab.";
 
+const char kSharingDeviceRegistrationName[] =
+    "Enable device registration for Sharing features";
+const char kSharingDeviceRegistrationDescription[] =
+    "Enables device registration with Sharing infrastructure. Required to use "
+    "cross-device Sharing features.";
+
 const char kShelfHoverPreviewsName[] =
     "Show previews of running apps when hovering over the shelf.";
 const char kShelfHoverPreviewsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index cdb3ada..f28e225 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -197,6 +197,9 @@
 extern const char kFCMInvalidationsName[];
 extern const char kFCMInvalidationsDescription[];
 
+extern const char kFontSrcLocalMatchingName[];
+extern const char kFontSrcLocalMatchingDescription[];
+
 extern const char kForceColorProfileSRGB[];
 extern const char kForceColorProfileP3[];
 extern const char kForceColorProfileColorSpin[];
@@ -592,8 +595,6 @@
 extern const char kFeaturePolicyName[];
 extern const char kFeaturePolicyDescription[];
 
-extern const char kFontCacheScalingDescription[];
-
 extern const char kForceEffectiveConnectionTypeName[];
 extern const char kForceEffectiveConnectionTypeDescription[];
 extern const char kEffectiveConnectionTypeUnknownDescription[];
@@ -976,6 +977,9 @@
 extern const char kSettingsWindowName[];
 extern const char kSettingsWindowDescription[];
 
+extern const char kSharingDeviceRegistrationName[];
+extern const char kSharingDeviceRegistrationDescription[];
+
 extern const char kShelfHoverPreviewsName[];
 extern const char kShelfHoverPreviewsDescription[];
 
diff --git a/chrome/browser/media/router/event_page_request_manager.cc b/chrome/browser/media/router/event_page_request_manager.cc
index 96fb7c4..492d92e 100644
--- a/chrome/browser/media/router/event_page_request_manager.cc
+++ b/chrome/browser/media/router/event_page_request_manager.cc
@@ -10,7 +10,7 @@
 #include "base/containers/circular_deque.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "extensions/browser/event_page_tracker.h"
+#include "extensions/browser/extension_host.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/process_manager_factory.h"
 
@@ -19,7 +19,7 @@
 EventPageRequestManager::~EventPageRequestManager() = default;
 
 void EventPageRequestManager::Shutdown() {
-  event_page_tracker_ = nullptr;
+  extension_process_manager_ = nullptr;
 }
 
 void EventPageRequestManager::SetExtensionId(const std::string& extension_id) {
@@ -77,9 +77,22 @@
   }
 }
 
+content::WebContents* EventPageRequestManager::GetEventPageWebContents() {
+  if (!extension_process_manager_)
+    return nullptr;
+
+  extensions::ExtensionHost* extension_host =
+      extension_process_manager_->GetBackgroundHostForExtension(
+          media_route_provider_extension_id_);
+  if (!extension_host)
+    return nullptr;
+
+  return extension_host->host_contents();
+}
+
 EventPageRequestManager::EventPageRequestManager(
     content::BrowserContext* context)
-    : event_page_tracker_(extensions::ProcessManager::Get(context)),
+    : extension_process_manager_(extensions::ProcessManager::Get(context)),
       weak_factory_(this) {}
 
 void EventPageRequestManager::EnqueueRequest(base::OnceClosure request) {
@@ -106,8 +119,9 @@
 }
 
 bool EventPageRequestManager::IsEventPageSuspended() const {
-  return !event_page_tracker_ || event_page_tracker_->IsEventPageSuspended(
-                                     media_route_provider_extension_id_);
+  return !extension_process_manager_ ||
+         extension_process_manager_->IsEventPageSuspended(
+             media_route_provider_extension_id_);
 }
 
 void EventPageRequestManager::AttemptWakeEventPage() {
@@ -123,16 +137,16 @@
 
   DVLOG(1) << "Attempting to wake up event page: attempt "
            << wakeup_attempt_count_;
-  if (!event_page_tracker_) {
+  if (!extension_process_manager_) {
     DLOG(ERROR) << "Attempted to wake up event page without a valid event page"
                    "tracker";
     return;
   }
 
   // This return false if the extension is already awake.
-  // Callback is bound using WeakPtr because |event_page_tracker_| outlives
-  // |this|.
-  if (!event_page_tracker_->WakeEventPage(
+  // Callback is bound using WeakPtr because |extension_process_manager_|
+  // outlives |this|.
+  if (!extension_process_manager_->WakeEventPage(
           media_route_provider_extension_id_,
           base::BindOnce(&EventPageRequestManager::OnWakeComplete,
                          weak_factory_.GetWeakPtr()))) {
diff --git a/chrome/browser/media/router/event_page_request_manager.h b/chrome/browser/media/router/event_page_request_manager.h
index fe1d643d..82a133c 100644
--- a/chrome/browser/media/router/event_page_request_manager.h
+++ b/chrome/browser/media/router/event_page_request_manager.h
@@ -16,10 +16,11 @@
 
 namespace content {
 class BrowserContext;
+class WebContents;
 }
 
 namespace extensions {
-class EventPageTracker;
+class ProcessManager;
 }
 
 namespace media_router {
@@ -52,6 +53,8 @@
   // is received.
   virtual void OnMojoConnectionError();
 
+  content::WebContents* GetEventPageWebContents();
+
   const std::string& media_route_provider_extension_id() const {
     return media_route_provider_extension_id_;
   }
@@ -122,7 +125,7 @@
   // Allows the extension to be monitored for suspend, and woken.
   // This is a reference to a BrowserContext keyed service that outlives this
   // instance.
-  extensions::EventPageTracker* event_page_tracker_;
+  extensions::ProcessManager* extension_process_manager_;
 
   int wakeup_attempt_count_ = 0;
 
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index e2f4cba5..2363feb 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -16,6 +16,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/media/cast_mirroring_service_host.h"
+#include "chrome/browser/media/router/event_page_request_manager.h"
+#include "chrome/browser/media/router/event_page_request_manager_factory.h"
 #include "chrome/browser/media/router/issues_observer.h"
 #include "chrome/browser/media/router/media_router_factory.h"
 #include "chrome/browser/media/router/media_router_feature.h"
@@ -1007,9 +1009,11 @@
     const std::string& desktop_stream_id,
     mirroring::mojom::MirroringServiceHostRequest request) {
   if (ShouldUseMirroringService()) {
+    // TODO(crbug.com/974335): Remove this code once we fully launch the native
+    // Cast Media Route Provider.
     mirroring::CastMirroringServiceHost::GetForDesktop(
-        GetWebContentsFromId(initiator_tab_id, context_,
-                             true /* include_incognito */),
+        EventPageRequestManagerFactory::GetApiForBrowserContext(context_)
+            ->GetEventPageWebContents(),
         desktop_stream_id, std::move(request));
   }
 }
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_browsertest.cc
index b60a261..8dbad7d 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest.cc
@@ -15,10 +15,14 @@
 #include "content/public/common/buildflags.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
+#include "content/public/common/service_manager_connection.h"
+#include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/network_service_test.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 #if defined(OS_MACOSX)
 #include "base/mac/mac_util.h"
@@ -99,6 +103,26 @@
     DetectVideoAndHangUp();
   }
 
+  uint32_t GetPeerToPeerConnectionsCountChangeFromNetworkService() {
+    network::mojom::NetworkServiceTestPtr network_service_test;
+    content::ServiceManagerConnection::GetForProcess()
+        ->GetConnector()
+        ->BindInterface(content::mojom::kNetworkServiceName,
+                        &network_service_test);
+    // TODO(crbug.com/901026): Make sure the network process is started to avoid
+    // a deadlock on Android.
+    network_service_test.FlushForTesting();
+
+    mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+    uint32_t connection_count = 0u;
+
+    bool available = network_service_test->GetPeerToPeerConnectionsCountChange(
+        &connection_count);
+    EXPECT_TRUE(available);
+
+    return connection_count;
+  }
+
  protected:
   void StartServerAndOpenTabs() {
     ASSERT_TRUE(embedded_test_server()->Start());
@@ -231,6 +255,23 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+                       GetPeerToPeerConnectionsCountChangeFromNetworkService) {
+  EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
+
+  StartServerAndOpenTabs();
+  SetupPeerconnectionWithLocalStream(left_tab_);
+
+  SetupPeerconnectionWithLocalStream(right_tab_);
+  NegotiateCall(left_tab_, right_tab_);
+
+  VerifyStatsGeneratedCallback(left_tab_);
+  EXPECT_EQ(2u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
+
+  DetectVideoAndHangUp();
+  EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
+}
+
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise) {
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
@@ -256,14 +297,17 @@
 IN_PROC_BROWSER_TEST_F(
     MAYBE_WebRtcBrowserTest,
     RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange) {
+  EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
   StartServerAndOpenTabs();
   SetupPeerconnectionWithLocalStream(left_tab_);
   SetupPeerconnectionWithLocalStream(right_tab_);
   NegotiateCall(left_tab_, right_tab_);
+  EXPECT_EQ(2u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
 
   std::string ice_gatheringstate =
       ExecuteJavascript("getLastGatheringState()", left_tab_);
 
   EXPECT_EQ("complete", ice_gatheringstate);
   DetectVideoAndHangUp();
+  EXPECT_EQ(0u, GetPeerToPeerConnectionsCountChangeFromNetworkService());
 }
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 85532a65..1b1f7dc 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -269,8 +269,8 @@
 #include "chrome/browser/chromeos/policy/auto_enrollment_client_impl.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
-#include "chrome/browser/chromeos/policy/device_wallpaper_image_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/dm_token_storage.h"
+#include "chrome/browser/chromeos/policy/external_data_handlers/device_wallpaper_image_external_data_handler.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/policy/status_collector/device_status_collector.h"
 #include "chrome/browser/chromeos/policy/status_collector/status_collector.h"
diff --git a/chrome/browser/previews/hints_fetcher_browsertest.cc b/chrome/browser/previews/hints_fetcher_browsertest.cc
index cb77c4f..a234d8e6 100644
--- a/chrome/browser/previews/hints_fetcher_browsertest.cc
+++ b/chrome/browser/previews/hints_fetcher_browsertest.cc
@@ -143,7 +143,8 @@
   void SetUpComponentUpdateHints(const GURL& hint_setup_url) {
     const optimization_guide::HintsComponentInfo& component_info =
         test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
-            optimization_guide::proto::NOSCRIPT, {hint_setup_url.host()}, {});
+            optimization_guide::proto::NOSCRIPT, {hint_setup_url.host()}, "*",
+            {});
 
     // Register a QuitClosure for when the next hint update is started below.
     base::RunLoop run_loop;
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc
index 7a9e09b..f8cef31 100644
--- a/chrome/browser/previews/previews_browsertest.cc
+++ b/chrome/browser/previews/previews_browsertest.cc
@@ -246,7 +246,8 @@
   void SetUpNoScriptWhitelist(const GURL& hint_setup_url) {
     const optimization_guide::HintsComponentInfo& component_info =
         test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
-            optimization_guide::proto::NOSCRIPT, {hint_setup_url.host()}, {});
+            optimization_guide::proto::NOSCRIPT, {hint_setup_url.host()}, "*",
+            {});
 
     base::HistogramTester histogram_tester;
 
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index 01b3f3a..8baa47e 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -1923,7 +1923,7 @@
 
     ProcessHintsComponent(
         test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
-            optimization_guide::proto::RESOURCE_LOADING, hints_sites,
+            optimization_guide::proto::RESOURCE_LOADING, hints_sites, "*",
             resource_patterns));
   }
 
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index fa75b62b..9e3c55f 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -93,6 +93,10 @@
     https_url_ = https_server_->GetURL("/resource_loading_hints.html");
     ASSERT_TRUE(https_url_.SchemeIs(url::kHttpsScheme));
 
+    https_second_url_ =
+        https_server_->GetURL("/resource_loading_hints_second.html");
+    ASSERT_TRUE(https_second_url_.SchemeIs(url::kHttpsScheme));
+
     https_no_transform_url_ = https_server_->GetURL(
         "/resource_loading_hints_with_no_transform_header.html");
     ASSERT_TRUE(https_no_transform_url_.SchemeIs(url::kHttpsScheme));
@@ -193,6 +197,12 @@
   }
 
   void SetDefaultOnlyResourceLoadingHints(const GURL& hint_setup_url) {
+    SetDefaultOnlyResourceLoadingHintsWithPagePattern(hint_setup_url, "*");
+  }
+
+  void SetDefaultOnlyResourceLoadingHintsWithPagePattern(
+      const GURL& hint_setup_url,
+      const std::string& page_pattern) {
     std::vector<std::string> resource_patterns;
     resource_patterns.push_back("foo.jpg");
     resource_patterns.push_back("png");
@@ -201,7 +211,7 @@
     ProcessHintsComponent(
         test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
             optimization_guide::proto::RESOURCE_LOADING,
-            {hint_setup_url.host()}, resource_patterns));
+            {hint_setup_url.host()}, page_pattern, resource_patterns));
     LoadHintsForUrl(hint_setup_url);
   }
 
@@ -242,6 +252,7 @@
   }
 
   const GURL& https_url() const { return https_url_; }
+  const GURL& https_second_url() const { return https_second_url_; }
   const GURL& https_no_transform_url() const { return https_no_transform_url_; }
   const GURL& https_hint_setup_url() const { return https_hint_setup_url_; }
   const GURL& http_url() const { return http_url_; }
@@ -326,6 +337,7 @@
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
   std::unique_ptr<net::EmbeddedTestServer> http_server_;
   GURL https_url_;
+  GURL https_second_url_;
   GURL https_no_transform_url_;
   GURL https_hint_setup_url_;
   GURL http_url_;
@@ -551,6 +563,107 @@
   EXPECT_TRUE(resource_loading_hint_intervention_header_seen());
 }
 
+// Sets the default hints with a non-wildcard page pattern. Loads a webpage from
+// an origin for which the hints are present, but the page pattern does not
+// match. Verifies that the hints are not used on that webpage.
+IN_PROC_BROWSER_TEST_F(
+    ResourceLoadingHintsBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMESOS(MatchingOrigin_NonMatchingPagePattern)) {
+  const GURL url = https_url();
+
+  // Whitelist resource loading hints for https_hint_setup_url()'s' host.
+  // Set pattern to a string that does not matches https_url() path.
+  ASSERT_EQ(std::string::npos, https_url().path().find("mismatched_pattern"));
+  SetDefaultOnlyResourceLoadingHintsWithPagePattern(https_url(),
+                                                    "mismatched_pattern");
+
+  SetExpectedFooJpgRequest(true);
+  SetExpectedBarJpgRequest(true);
+  ResetResourceLoadingHintInterventionHeaderSeen();
+  InitializeOptimizationHints();
+
+  base::HistogramTester histogram_tester;
+
+  // The URL is not whitelisted. Verify that the hints are not used.
+  ui_test_utils::NavigateToURL(browser(), url);
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester.ExpectBucketCount(
+      "Previews.EligibilityReason.ResourceLoadingHints",
+      static_cast<int>(
+          previews::PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
+      1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.PreviewShown.ResourceLoadingHints", 0);
+  histogram_tester.ExpectTotalCount(
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
+  EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
+}
+
+// Sets the default hints with a non-wildcard page pattern. First loads a
+// webpage from a host for which the hints are present (page pattern matches).
+// Next, loads a webpage from the same host but the webpage's URL does not match
+// the page patterns. Verifies that the hints are not used on that webpage.
+IN_PROC_BROWSER_TEST_F(
+    ResourceLoadingHintsBrowserTest,
+    DISABLE_ON_WIN_MAC_CHROMESOS(SameOriginDifferentPattern)) {
+  // Whitelist resource loading hints for https_url()'s' host and pattern.
+  SetDefaultOnlyResourceLoadingHintsWithPagePattern(https_url(),
+                                                    https_url().path());
+
+  // Hints should be used when loading https_url().
+  SetExpectedFooJpgRequest(false);
+  SetExpectedBarJpgRequest(true);
+  ResetResourceLoadingHintInterventionHeaderSeen();
+
+  base::HistogramTester histogram_tester_1;
+
+  ui_test_utils::NavigateToURL(browser(), https_url());
+
+  RetryForHistogramUntilCountReached(
+      &histogram_tester_1,
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1);
+  histogram_tester_1.ExpectUniqueSample(
+      "ResourceLoadingHints.ResourcePatternsAvailableAtCommit", 1, 1);
+  histogram_tester_1.ExpectTotalCount(
+      "ResourceLoadingHints.ResourcePatternsAvailableAtCommitForRedirect", 0);
+  histogram_tester_1.ExpectBucketCount(
+      "Previews.EligibilityReason.ResourceLoadingHints",
+      static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
+  histogram_tester_1.ExpectBucketCount(
+      "Previews.PreviewShown.ResourceLoadingHints", true, 1);
+  // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns.
+  histogram_tester_1.ExpectBucketCount(
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
+  EXPECT_TRUE(resource_loading_hint_intervention_header_seen());
+
+  // Load a different webpage on the same origin to ensure that the resource
+  // loading hints are not reused.
+  SetExpectedFooJpgRequest(true);
+  SetExpectedBarJpgRequest(true);
+  ResetResourceLoadingHintInterventionHeaderSeen();
+  base::HistogramTester histogram_tester_2;
+
+  // https_second_url() is hosted on the same host as https_url(), but the path
+  // for https_second_url() is not whitelisted.
+  ASSERT_EQ(https_url().host(), https_second_url().host());
+  ASSERT_NE(https_url().path(), https_second_url().path());
+
+  ui_test_utils::NavigateToURL(browser(), https_second_url());
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester_2.ExpectBucketCount(
+      "Previews.EligibilityReason.ResourceLoadingHints",
+      static_cast<int>(
+          previews::PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
+      1);
+  histogram_tester_2.ExpectTotalCount(
+      "Previews.PreviewShown.ResourceLoadingHints", 0);
+  histogram_tester_2.ExpectTotalCount(
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
+  EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
+}
+
 // Sets both the experimental and default hints, but does not enable the
 // matching experiment. Verifies that the hints from the experiment are not
 // used.
diff --git a/chrome/browser/profiles/profile_metrics.cc b/chrome/browser/profiles/profile_metrics.cc
index a34826b..99e998de 100644
--- a/chrome/browser/profiles/profile_metrics.cc
+++ b/chrome/browser/profiles/profile_metrics.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/signin/chrome_signin_helper.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/installer/util/google_update_settings.h"
+#include "components/profile_metrics/browser_profile_type.h"
 #include "components/profile_metrics/counts.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -213,24 +214,25 @@
   return true;
 }
 
-ProfileMetrics::BrowserProfileType ProfileMetrics::GetBrowserProfileType(
+profile_metrics::BrowserProfileType ProfileMetrics::GetBrowserProfileType(
     Profile* profile) {
   if (profile->IsSystemProfile())
-    return BrowserProfileType::kSystem;
+    return profile_metrics::BrowserProfileType::kSystem;
   if (profile->IsGuestSession())
-    return BrowserProfileType::kGuest;
+    return profile_metrics::BrowserProfileType::kGuest;
   // A regular profile can be in a guest session or a system profile. Hence it
   // should be checked after them.
   if (profile->IsRegularProfile())
-    return BrowserProfileType::kRegular;
+    return profile_metrics::BrowserProfileType::kRegular;
   if (profile->IsIncognitoProfile()) {
     return profile->IsIndependentOffTheRecordProfile()
-               ? BrowserProfileType::kIndependentIncognitoProfile
-               : BrowserProfileType::kIncognito;
+               ? profile_metrics::BrowserProfileType::
+                     kIndependentIncognitoProfile
+               : profile_metrics::BrowserProfileType::kIncognito;
   }
 
   NOTREACHED();
-  return BrowserProfileType::kMaxValue;
+  return profile_metrics::BrowserProfileType::kMaxValue;
 }
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/profiles/profile_metrics.h b/chrome/browser/profiles/profile_metrics.h
index 675727f7..72fedfc 100644
--- a/chrome/browser/profiles/profile_metrics.h
+++ b/chrome/browser/profiles/profile_metrics.h
@@ -20,6 +20,7 @@
 }
 
 namespace profile_metrics {
+enum class BrowserProfileType;
 struct Counts;
 }
 
@@ -111,17 +112,6 @@
     NUM_PROFILE_AUTH_METRICS
   };
 
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class BrowserProfileType {
-    kRegular = 0,
-    kIncognito = 1,
-    kGuest = 2,
-    kSystem = 3,
-    kIndependentIncognitoProfile = 4,
-    kMaxValue = kIndependentIncognitoProfile,
-  };
-
   // Enum for tracking user interactions with the user menu and user manager.
   // Interactions initiated from the content area are logged into a different
   // histogram from those that were initiated from the avatar button.
@@ -187,7 +177,8 @@
 #endif
 
   // Returns profile type for logging.
-  static BrowserProfileType GetBrowserProfileType(Profile* profile);
+  static profile_metrics::BrowserProfileType GetBrowserProfileType(
+      Profile* profile);
 
   static void LogNumberOfProfiles(ProfileManager* manager);
   static void LogProfileAddNewUser(ProfileAdd metric);
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 665a63ed..3a7dd95 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -1692,7 +1692,6 @@
   TabStripModel* tab_strip = browser->tab_strip_model();
 
   // Simulate being offline.
-  net::NetworkChangeNotifier::DisableForTest disable_for_test;
   FakeOfflineNetworkChangeNotifier fake_offline_state;
 
   tab_strip->AppendWebContents(CreateWebContents(), /*foreground=*/true);
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index 554e497..20bc9df 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -551,7 +551,7 @@
   $(customize.IDS.TITLE).textContent =
       configData.translatedStrings.selectChromeWallpaper;
   if (!configData.richerPicker) {
-    menu.classList.toggle(customize.CLASSES.COLLECTION_DIALOG);
+    menu.classList.add(customize.CLASSES.COLLECTION_DIALOG);
     menu.classList.remove(customize.CLASSES.IMAGE_DIALOG);
   }
 
@@ -677,6 +677,7 @@
   const re = /w\d+\-h\d+/;
   $(customize.IDS.CUSTOM_BG).style.backgroundImage =
       tile.style.backgroundImage.replace(re, 'w1280-h720');
+  $(customize.IDS.CUSTOM_BG).style.opacity = 1;
 };
 
 /**
@@ -896,23 +897,13 @@
   for (let i = 0; i < collImg.length; ++i) {
     const dataset = {};
 
-    // TODO(crbug.com/854028): Remove this hardcoded check when wallpaper
-    // previews are supported.
-    if (collImg[i].collectionId === 'solidcolors') {
-      dataset.attributionLine1 = '';
-      dataset.attributionLine2 = '';
-      dataset.attributionActionUrl = '';
-    } else {
-      dataset.attributionLine1 =
-          (collImg[i].attributions[0] !== undefined ?
-               collImg[i].attributions[0] :
-               '');
-      dataset.attributionLine2 =
-          (collImg[i].attributions[1] !== undefined ?
-               collImg[i].attributions[1] :
-               '');
-      dataset.attributionActionUrl = collImg[i].attributionActionUrl;
-    }
+    dataset.attributionLine1 =
+        (collImg[i].attributions[0] !== undefined ? collImg[i].attributions[0] :
+                                                    '');
+    dataset.attributionLine2 =
+        (collImg[i].attributions[1] !== undefined ? collImg[i].attributions[1] :
+                                                    '');
+    dataset.attributionActionUrl = collImg[i].attributionActionUrl;
     dataset.url = collImg[i].imageUrl;
     dataset.tileNum = i;
 
@@ -958,15 +949,8 @@
  *     loading.
  */
 customize.loadTile = function(tile, imageData, countLoad) {
-  if (imageData[tile.dataset.tileNum].collectionId === 'solidcolors') {
-    tile.style.backgroundImage = [
-      customize.CUSTOM_BACKGROUND_OVERLAY,
-      'url(' + imageData[tile.dataset.tileNum].thumbnailImageUrl + ')'
-    ].join(',').trim();
-  } else {
-    tile.style.backgroundImage =
-        'url(' + imageData[tile.dataset.tileNum].thumbnailImageUrl + ')';
-  }
+  tile.style.backgroundImage =
+      'url(' + imageData[tile.dataset.tileNum].thumbnailImageUrl + ')';
   customize.fadeInImageTile(
       tile, imageData[tile.dataset.tileNum].thumbnailImageUrl, countLoad);
 };
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 9cfeb66..1f29c9e 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -1331,16 +1331,17 @@
 }
 
 .sh-option-image .selected-circle {
-  box-shadow: 0 3px 6px rgba(0, 0, 0, .16), 0 1px 2px rgba(0, 0, 0, .23);
-  height: 24px;
-  left: 208px;
-  top: 8px;
-  width: 24px;
+  box-shadow: 0 3px 6px 1px rgba(0, 0, 0, .16),
+      0 1px 2px 1px rgba(0, 0, 0, .23);
+  height: 22px;
+  left: 209px;
+  top: 9px;
+  width: 22px;
 }
 
 html[dir=rtl] .sh-option-image .selected-circle {
   left: 0;
-  right: 208px;
+  right: 209px;
 }
 
 .sh-option-image .selected-check {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index d15764a7..a75da42 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -398,27 +398,34 @@
   setCustomThemeStyle(info);
 
   if (info.customBackgroundConfigured) {
-    const imageWithOverlay = [
-      customize.CUSTOM_BACKGROUND_OVERLAY, 'url(' + info.imageUrl + ')'
-    ].join(',').trim();
+    // Do anything only if the custom background changed.
+    if (!$(IDS.CUSTOM_BG).style.backgroundImage.includes(info.imageUrl)) {
+      const imageWithOverlay = [
+        customize.CUSTOM_BACKGROUND_OVERLAY, 'url(' + info.imageUrl + ')'
+      ].join(',').trim();
+      // If the theme update is because of uploading a local image then we
+      // should close the customization menu. Closing the menu before the image
+      // is selected doesn't look good.
+      const localImageFileName = 'background.jpg';
+      if (imageWithOverlay.includes(localImageFileName) &&
+          !$(IDS.CUSTOM_BG)
+               .style.backgroundImage.includes(localImageFileName)) {
+        customize.closeCustomizationDialog();
+      }
+      // |image| and |imageWithOverlay| use the same url as their source.
+      // Waiting to display the custom background until |image| is fully
+      // loaded ensures that |imageWithOverlay| is also loaded.
+      $(IDS.CUSTOM_BG).style.backgroundImage = imageWithOverlay;
+      const image = new Image();
+      image.onload = function() {
+        $(IDS.CUSTOM_BG).style.opacity = '1';
+      };
+      image.src = info.imageUrl;
 
-    if (imageWithOverlay != $(IDS.CUSTOM_BG).style.backgroundImage) {
-      customize.closeCustomizationDialog();
       customize.clearAttribution();
+      customize.setAttribution(
+          info.attribution1, info.attribution2, info.attributionActionUrl);
     }
-
-    // |image| and |imageWithOverlay| use the same url as their source. Waiting
-    // to display the custom background until |image| is fully loaded ensures
-    // that |imageWithOverlay| is also loaded.
-    $(IDS.CUSTOM_BG).style.backgroundImage = imageWithOverlay;
-    const image = new Image();
-    image.onload = function() {
-      $(IDS.CUSTOM_BG).style.opacity = '1';
-    };
-    image.src = info.imageUrl;
-
-    customize.setAttribution(
-        info.attribution1, info.attribution2, info.attributionActionUrl);
   } else {
     $(IDS.CUSTOM_BG).style.opacity = '0';
     window.setTimeout(function() {
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 419f9cc..c2b093f 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -252,13 +252,13 @@
 
 /* During reorder background is white. Therefore use dark grey for
  * title. */
-.reorder .md-title {
+.reorder {
   color: rgb(var(--GG800-rgb));
 }
 
 /* During reorder in dark mode background is dark. Therefore use light
  * grey for title. */
-html[darkmode=true] .reorder .md-title {
+html[darkmode=true] .reorder {
   color: rgb(var(--GG100-rgb));
 }
 
@@ -285,7 +285,7 @@
   padding: 0 8px;
 }
 
-body.use-title-container .md-tile:not(.reorder) .md-title {
+body.use-title-container .md-tile:not(.reorder) {
   color: rgb(var(--GG800-rgb));
   filter: unset;
 }
diff --git a/chrome/browser/resources/print_preview/ui/header.js b/chrome/browser/resources/print_preview/ui/header.js
index bac4c25..21dc46b 100644
--- a/chrome/browser/resources/print_preview/ui/header.js
+++ b/chrome/browser/resources/print_preview/ui/header.js
@@ -182,6 +182,10 @@
    * @private
    */
   getSummary_: function(labelInfo) {
+    if (labelInfo.numSheets === 0) {
+      return '';
+    }
+
     let html = loadTimeData.getStringF(
         'printPreviewSummaryFormatShort',
         '<b>' + labelInfo.numSheets.toLocaleString() + '</b>',
diff --git a/chrome/browser/resources/print_preview/ui/header_new.html b/chrome/browser/resources/print_preview/ui/header_new.html
index 42785f8..9983f9f2 100644
--- a/chrome/browser/resources/print_preview/ui/header_new.html
+++ b/chrome/browser/resources/print_preview/ui/header_new.html
@@ -61,7 +61,7 @@
            alt="" title="$i18n{managedSettings}">
       </iron-icon>
     </div>
-    <span class="summary" aria-label$="[[summaryLabel_]]">[[summary_]]</span>
+    <span class="summary">[[summary_]]</span>
   </template>
   <script src="header_new.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/print_preview/ui/header_new.js b/chrome/browser/resources/print_preview/ui/header_new.js
index d9b344a..9d639b1f 100644
--- a/chrome/browser/resources/print_preview/ui/header_new.js
+++ b/chrome/browser/resources/print_preview/ui/header_new.js
@@ -36,12 +36,6 @@
       type: String,
       value: null,
     },
-
-    /** @private {?string} */
-    summaryLabel_: {
-      type: String,
-      value: null,
-    },
   },
 
   observers: [
@@ -102,20 +96,16 @@
       case (print_preview.State.PRINTING):
         this.summary_ = loadTimeData.getString(
             this.isPdfOrDrive_() ? 'saving' : 'printing');
-        this.summaryLabel_ = this.summary_;
         break;
       case (print_preview.State.READY):
         const labelInfo = this.computeLabelInfo_();
         this.summary_ = this.getSummary_(labelInfo);
-        this.summaryLabel_ = this.getSummaryLabel_(labelInfo);
         break;
       case (print_preview.State.FATAL_ERROR):
         this.summary_ = this.getErrorMessage_();
-        this.summaryLabel_ = this.getErrorMessage_();
         break;
       default:
         this.summary_ = null;
-        this.summaryLabel_ = null;
         break;
     }
   },
@@ -141,19 +131,10 @@
    * @private
    */
   getSummary_: function(labelInfo) {
-    return loadTimeData.getStringF(
-        'printPreviewNewSummaryFormatShort',
-        labelInfo.numSheets.toLocaleString(), labelInfo.summaryLabel);
-  },
-
-  /**
-   * @param {!print_preview.HeaderNew.LabelInfo} labelInfo
-   * @return {string}
-   * @private
-   */
-  getSummaryLabel_: function(labelInfo) {
-    return loadTimeData.getStringF(
-        'printPreviewNewSummaryFormatShort',
-        labelInfo.numSheets.toLocaleString(), labelInfo.summaryLabel);
+    return labelInfo.numSheets === 0 ?
+        '' :
+        loadTimeData.getStringF(
+            'printPreviewNewSummaryFormatShort',
+            labelInfo.numSheets.toLocaleString(), labelInfo.summaryLabel);
   },
 });
diff --git a/chrome/browser/resources/settings/internet_page/BUILD.gn b/chrome/browser/resources/settings/internet_page/BUILD.gn
index 29c26dab..a5443e5 100644
--- a/chrome/browser/resources/settings/internet_page/BUILD.gn
+++ b/chrome/browser/resources/settings/internet_page/BUILD.gn
@@ -27,7 +27,6 @@
     "../settings_page:settings_animated_pages",
     "//chromeos/services/network_config/public/mojom:mojom_js_library_for_compile",
     "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider",
-    "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:i18n_behavior",
@@ -67,6 +66,7 @@
     ":internet_page_browser_proxy",
     ":tether_connection_dialog",
     "..:route",
+    "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
     "//ui/webui/resources/js:assert",
@@ -81,6 +81,7 @@
 
 js_library("internet_known_networks_page") {
   deps = [
+    "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
     "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
@@ -94,6 +95,7 @@
   deps = [
     ":internet_page_browser_proxy",
     "..:route",
+    "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
     "//ui/webui/resources/js:assert",
@@ -118,6 +120,7 @@
 
 js_library("network_summary") {
   deps = [
+    "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
     "//ui/webui/resources/js:assert",
diff --git a/chrome/browser/resources/settings/internet_page/internet_config.js b/chrome/browser/resources/settings/internet_page/internet_config.js
index 97cca74..0b3760d 100644
--- a/chrome/browser/resources/settings/internet_page/internet_config.js
+++ b/chrome/browser/resources/settings/internet_page/internet_config.js
@@ -113,7 +113,6 @@
    */
   onClose_: function(event) {
     this.close();
-    this.fire('networks-changed');
     event.stopPropagation();
   },
 
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 a380b921..a6b78bae 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -7,6 +7,7 @@
 <link rel="import" href="chrome://resources/cr_components/chromeos/network/network_property_list.html">
 <link rel="import" href="chrome://resources/cr_components/chromeos/network/network_siminfo.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
+<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
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 090c91a9..abf4d55 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -13,8 +13,12 @@
 Polymer({
   is: 'settings-internet-detail-page',
 
-  behaviors:
-      [CrPolicyNetworkBehavior, settings.RouteObserverBehavior, I18nBehavior],
+  behaviors: [
+    CrNetworkListenerBehavior,
+    CrPolicyNetworkBehavior,
+    settings.RouteObserverBehavior,
+    I18nBehavior,
+  ],
 
   properties: {
     /** The network GUID to display details for. */
@@ -65,9 +69,9 @@
 
     /**
      * Whether the network has been lost (e.g., has gone out of range). A
-     * network is considered to be lost when a 'network-list-changed' event
-     * occurs, and the new network list does not contain the GUID of the current
-     * network.
+     * network is considered to be lost when a OnNetworkStateListChanged
+     * is signaled and the new network list does not contain the GUID of the
+     * current network.
      * @private
      */
     outOfRange_: {
@@ -178,11 +182,6 @@
     'autoConnectChanged_(autoConnect_.*)', 'alwaysOnVpnChanged_(alwaysOnVpn_.*)'
   ],
 
-  listeners: {
-    'network-list-changed': 'checkNetworkExists_',
-    'networks-changed': 'updateNetworkDetails_'
-  },
-
   /** @private {boolean} */
   didSetFocus_: false,
 
@@ -276,7 +275,33 @@
     });
   },
 
-  /** @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy */
+  /**
+   * CrosNetworkConfigObserver impl
+   * @param {!Array<chromeos.networkConfig.mojom.NetworkStateProperties>}
+   *     networks
+   */
+  onActiveNetworksChanged: function(networks) {
+    if (networks.find(network => network.guid == this.guid)) {
+      this.getNetworkDetails_();
+    }
+  },
+
+  /** CrosNetworkConfigObserver impl */
+  onNetworkStateListChanged: function() {
+    this.checkNetworkExists_();
+  },
+
+  /** CrosNetworkConfigObserver impl */
+  onDeviceStateListChanged: function() {
+    if (this.guid) {
+      this.getNetworkDetails_();
+    }
+  },
+
+  /**
+   * @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
+   * @private
+   */
   globalPolicyChanged_: function(globalPolicy) {
     this.updateAutoConnectPref_(
         !!(this.autoConnect_ && this.autoConnect_.value), globalPolicy);
@@ -384,24 +409,25 @@
     this.setNetworkProperties_(onc);
   },
 
-  /**
-   * @param {!CustomEvent<!Array<string>>} event
-   * @private
-   */
-  checkNetworkExists_: function(event) {
-    const networkIds = event.detail;
-    this.outOfRange_ = networkIds.indexOf(this.guid) == -1;
-  },
-
-  /**
-   * @param {!CustomEvent<!Array<string>>} event
-   * @private
-   */
-  updateNetworkDetails_: function(event) {
-    const networkIds = event.detail;
-    if (networkIds.indexOf(this.guid) != -1) {
-      this.getNetworkDetails_();
-    }
+  /** @private */
+  checkNetworkExists_: function() {
+    const filter = {
+      networkType: CrOnc.Type.ALL,
+      visible: true,
+      configured: false
+    };
+    this.networkingPrivate.getNetworks(filter, networks => {
+      if (networks.find(network => network.GUID == this.guid)) {
+        return;
+      }
+      this.outOfRange_ = true;
+      if (this.networkProperties_) {
+        // Set the connection state since we won't receive an update for a non
+        // existent network.
+        this.networkProperties_.ConnectionState =
+            CrOnc.ConnectionState.NOT_CONNECTED;
+      }
+    });
   },
 
   /**
@@ -444,7 +470,7 @@
     }
 
     if (!properties) {
-      console.error('No properties for: ' + this.guid);
+      // Edge case, may occur when disabling. Close this.
       this.close();
       return;
     }
@@ -467,9 +493,7 @@
    */
   getStateCallback_: function(state) {
     if (!state) {
-      // If |state| is null, the network is no longer visible, close this.
-      console.error('Network no longer exists: ' + this.guid);
-      this.networkProperties_ = undefined;
+      // Edge case, may occur when disabling. Close this.
       this.close();
       return;
     }
@@ -850,8 +874,7 @@
   /** @private */
   updateAlwaysOnVpnPrefValue_: function() {
     this.alwaysOnVpn_.value = this.prefs.arc && this.prefs.arc.vpn &&
-        this.prefs.arc.vpn.always_on &&
-        this.prefs.arc.vpn.always_on.lockdown &&
+        this.prefs.arc.vpn.always_on && this.prefs.arc.vpn.always_on.lockdown &&
         this.prefs.arc.vpn.always_on.lockdown.value;
   },
 
@@ -868,8 +891,7 @@
     // Only mark VPN networks as enforced. This fake pref also controls the
     // policy indicator on the connect/disconnect buttons, so it shouldn't be
     // shown on non-VPN networks.
-    if (this.isVpn_(this.networkProperties_) &&
-        this.prefs.vpn_config_allowed &&
+    if (this.isVpn_(this.networkProperties_) && this.prefs.vpn_config_allowed &&
         !this.prefs.vpn_config_allowed.value) {
       fakeAlwaysOnVpnEnforcementPref.enforcement =
           chrome.settingsPrivate.Enforcement.ENFORCED;
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
index 3685d4c..c9db328 100644
--- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js
index f5196b0..b52f897d3 100644
--- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.js
@@ -10,7 +10,10 @@
 Polymer({
   is: 'settings-internet-known-networks-page',
 
-  behaviors: [CrPolicyNetworkBehavior],
+  behaviors: [
+    CrNetworkListenerBehavior,
+    CrPolicyNetworkBehavior,
+  ],
 
   properties: {
     /**
@@ -54,11 +57,14 @@
     enableForget_: Boolean,
   },
 
-  listeners: {'network-list-changed': 'refreshNetworks_'},
-
   /** @private {string} */
   selectedGuid_: '',
 
+  /** CrosNetworkConfigObserver impl */
+  onNetworkStateListChanged: function() {
+    this.refreshNetworks_();
+  },
+
   /** @private */
   networkTypeChanged_: function() {
     this.refreshNetworks_();
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html
index 59e490d..063144d 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -1,7 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_components/chromeos/network/mojo_interface_provider.html">
-<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js
index 016b3f4e4..da5717c 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -11,8 +11,9 @@
   is: 'settings-internet-page',
 
   behaviors: [
-    I18nBehavior, settings.RouteObserverBehavior, WebUIListenerBehavior,
-    CrNetworkListenerBehavior
+    I18nBehavior,
+    settings.RouteObserverBehavior,
+    WebUIListenerBehavior,
   ],
 
   properties: {
@@ -93,31 +94,6 @@
       value: false,
     },
 
-    /** Overridden from NetworkListenerBehavior. */
-    networkListChangeSubscriberSelectors_: {
-      type: Array,
-      value: function() {
-        return [
-          'network-summary',
-          'settings-internet-detail-page',
-          'settings-internet-known-networks-page',
-          'settings-internet-subpage',
-        ];
-      }
-    },
-
-    /** Overridden from NetworkListenerBehavior. */
-    networksChangeSubscriberSelectors_: {
-      type: Array,
-      value: function() {
-        return [
-          'network-summary',
-          'settings-internet-detail-page',
-          'settings-internet-subpage',
-        ];
-      }
-    },
-
     /**
      * List of third party VPN providers.
      * @type {!Array<!chrome.networkingPrivate.ThirdPartyVPNProperties>}
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html
index 6378a878..0cc871e 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.html
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -1,6 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_list.html">
+<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chrome/browser/resources/settings/internet_page/internet_subpage.js
index a7e399e..1e47c0dd 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.js
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -11,6 +11,7 @@
   is: 'settings-internet-subpage',
 
   behaviors: [
+    CrNetworkListenerBehavior,
     CrPolicyNetworkBehavior,
     settings.RouteObserverBehavior,
     I18nBehavior,
@@ -125,11 +126,6 @@
     },
   },
 
-  listeners: {
-    'network-list-changed': 'getNetworkStateList_',
-    'networks-changed': 'getNetworkStateList_',
-  },
-
   observers: ['deviceStateChanged_(networkingPrivate, deviceState)'],
 
   /** @private {number|null} */
@@ -174,6 +170,20 @@
     this.updateScanning_();
   },
 
+  /**
+   * CrosNetworkConfigObserver impl
+   * @param {!Array<chromeos.networkConfig.mojom.NetworkStateProperties>}
+   *     networks
+   */
+  onActiveNetworksChanged: function(networks) {
+    this.getNetworkStateList_();
+  },
+
+  /** CrosNetworkConfigObserver impl */
+  onNetworkStateListChanged: function() {
+    this.getNetworkStateList_();
+  },
+
   /** @private */
   deviceStateChanged_: function() {
     this.showSpinner =
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html
index f31a25c..ed9f6e73 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
 <link rel="import" href="network_summary_item.html">
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js
index 4bdfa6b5..e28764d 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -32,7 +32,10 @@
 Polymer({
   is: 'network-summary',
 
-  behaviors: [CrPolicyNetworkBehavior],
+  behaviors: [
+    CrNetworkListenerBehavior,
+    CrPolicyNetworkBehavior,
+  ],
 
   properties: {
     /**
@@ -91,18 +94,6 @@
     },
   },
 
-  listeners: {
-    'network-list-changed': 'getNetworkLists_',
-    'networks-changed': 'updateActiveNetworks_',
-  },
-
-  /**
-   * Listener function for chrome.networkingPrivate.onDeviceStateListChanged
-   * event.
-   * @private {?function(!Array<string>)}
-   */
-  deviceStateListChangedListener_: null,
-
   /**
    * Set of GUIDs identifying active networks, one for each type.
    * @private {?Set<string>}
@@ -112,43 +103,35 @@
   /** @override */
   attached: function() {
     this.getNetworkLists_();
-
-    this.deviceStateListChangedListener_ =
-        this.deviceStateListChangedListener_ ||
-        this.onDeviceStateListChangedEvent_.bind(this);
-    this.networkingPrivate.onDeviceStateListChanged.addListener(
-        this.deviceStateListChangedListener_);
-  },
-
-  /** @override */
-  detached: function() {
-    this.networkingPrivate.onDeviceStateListChanged.removeListener(
-        assert(this.deviceStateListChangedListener_));
   },
 
   /**
-   * networkingPrivate.onDeviceStateListChanged event callback.
-   * @private
+   * CrosNetworkConfigObserver impl
+   * @param {!Array<chromeos.networkConfig.mojom.NetworkStateProperties>}
+   *     networks
    */
-  onDeviceStateListChangedEvent_: function() {
-    this.getNetworkLists_();
-  },
-
-  /**
-   * @param {!CustomEvent<!Array<string>>} event
-   * @private
-   */
-  updateActiveNetworks_: function(event) {
+  onActiveNetworksChanged: function(networks) {
     if (!this.activeNetworkIds_) {
+      // Initial list of networks not received yet.
       return;
-    }  // Initial list of networks not received yet.
-    const networkIds = event.detail;
-    networkIds.forEach(function(id) {
+    }
+    networks.forEach(network => {
+      const id = network.guid;
       if (this.activeNetworkIds_.has(id)) {
         this.networkingPrivate.getState(
             id, this.getActiveStateCallback_.bind(this, id));
       }
-    }, this);
+    });
+  },
+
+  /** CrosNetworkConfigObserver impl */
+  onNetworkStateListChanged: function() {
+    this.getNetworkLists_();
+  },
+
+  /** CrosNetworkConfigObserver impl */
+  onDeviceStateListChanged: function() {
+    this.getNetworkLists_();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/multidevice_page/BUILD.gn b/chrome/browser/resources/settings/multidevice_page/BUILD.gn
index f00e9cb..6f6bd02 100644
--- a/chrome/browser/resources/settings/multidevice_page/BUILD.gn
+++ b/chrome/browser/resources/settings/multidevice_page/BUILD.gn
@@ -108,6 +108,7 @@
     deps = [
       ":multidevice_feature_behavior",
       "..:route",
+      "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
       "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
     ]
     externs_list = [ "$externs_path/networking_private.js" ]
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
index 08bc3dfb..11bea12e 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
@@ -12,10 +12,7 @@
 Polymer({
   is: 'settings-multidevice-subpage',
 
-  behaviors: [
-    MultiDeviceFeatureBehavior,
-    CrNetworkListenerBehavior,
-  ],
+  behaviors: [MultiDeviceFeatureBehavior],
 
   properties: {
     /**
@@ -32,18 +29,6 @@
       type: Object,
       value: chrome.networkingPrivate,
     },
-
-    /** Overridden from NetworkListenerBehavior. */
-    networkListChangeSubscriberSelectors_: {
-      type: Array,
-      value: () => ['settings-multidevice-tether-item'],
-    },
-
-    /** Overridden from NetworkListenerBehavior. */
-    networksChangeSubscriberSelectors_: {
-      type: Array,
-      value: () => ['settings-multidevice-tether-item'],
-    },
   },
 
   /** @private {?settings.MultiDeviceBrowserProxy} */
@@ -140,9 +125,10 @@
    * @private
    */
   isAndroidMessagesSetupButtonDisabled_: function() {
-    const messagesFeatureState = this.getFeatureState(
-        settings.MultiDeviceFeature.MESSAGES);
-    return !this.isSuiteOn() ||  messagesFeatureState ===
+    const messagesFeatureState =
+        this.getFeatureState(settings.MultiDeviceFeature.MESSAGES);
+    return !this.isSuiteOn() ||
+        messagesFeatureState ===
         settings.MultiDeviceFeatureState.PROHIBITED_BY_POLICY;
   }
 });
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.html b/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.html
index 42431eb..6475b01 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.html
@@ -2,6 +2,7 @@
 
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
+<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="../route.html">
 <link rel="import" href="../settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.js b/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.js
index a5c84407..210705b 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.js
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_tether_item.js
@@ -14,7 +14,10 @@
 Polymer({
   is: 'settings-multidevice-tether-item',
 
-  behaviors: [MultiDeviceFeatureBehavior],
+  behaviors: [
+    CrNetworkListenerBehavior,
+    MultiDeviceFeatureBehavior,
+  ],
 
   properties: {
     /**
@@ -62,54 +65,25 @@
     },
   },
 
-  listeners: {
-    'network-list-changed': 'updateTetherNetworkState_',
-    // network-changed is fired by the settings-multidevice-subpage element's
-    // CrNetworkListenerBehavior.
-    // TODO (jordynass): Refactor to allow this element to listen to network
-    // changes without requiring the settings-multidevice-subpage to communicate
-    // with the networkingPrivate API.
-    'networks-changed': 'onNetworksChanged_',
-  },
-
-  /**
-   * Listener function for chrome.networkingPrivate.onDeviceStateListChanged
-   * event.
-   * @private {?function(!Array<string>)}
-   */
-  deviceStateListChangedListener_: null,
-
   /** @override */
   attached: function() {
     this.updateTetherDeviceState_();
     this.updateTetherNetworkState_();
-
-    this.deviceStateListChangedListener_ =
-        this.deviceStateListChangedListener_ ||
-        this.updateTetherDeviceState_.bind(this);
-    this.networkingPrivate_.onDeviceStateListChanged.addListener(
-        this.deviceStateListChangedListener_);
-  },
-
-  /** @override */
-  detached: function() {
-    this.networkingPrivate_.onDeviceStateListChanged.removeListener(
-        assert(this.deviceStateListChangedListener_));
   },
 
   /**
-   * Callback for the a network changing state. Note that any change to leading
-   * to a new active network would fire the 'network-list-changed' event,
-   * triggering updateTetherNetworkState_ and rendering this callback
-   * redundant. As a result, we return early if the active network is not
-   * changed.
-   * @param {!CustomEvent<!Array<string>>} event stores an array of the GUIDs of
-   *     all networks that changed in its detail property.
+   * CrosNetworkConfigObserver impl
+   * Note that any change to leading to a new active network will also trigger
+   * onNetworkStateListChanged, triggering updateTetherNetworkState_ and
+   * rendering this callback redundant. As a result, we return early if the
+   * active network is not changed.
+   * @param {!Array<chromeos.networkConfig.mojom.NetworkStateProperties>}
+   *     networks
    * @private
    */
-  onNetworksChanged_: function(event) {
+  onActiveNetworksChanged: function(networks) {
     const id = this.activeNetworkState_.GUID;
-    if (!event.detail.includes(id)) {
+    if (!networks.find(network => network.guid == id)) {
       return;
     }
     this.networkingPrivate_.getState(id, newNetworkState => {
@@ -127,6 +101,16 @@
     });
   },
 
+  /** CrosNetworkConfigObserver impl */
+  onNetworkStateListChanged: function() {
+    this.updateTetherNetworkState_();
+  },
+
+  /** CrosNetworkConfigObserver impl */
+  onDeviceStateListChanged: function() {
+    this.updateTetherDeviceState_();
+  },
+
   /**
    * Retrieves device states (CrOnc.DeviceStateProperties) and sets
    * this.deviceState_ to the retrieved Instant Tethering state (or undefined if
diff --git a/chrome/browser/sessions/tab_loader.cc b/chrome/browser/sessions/tab_loader.cc
index 8a034275..e723a246 100644
--- a/chrome/browser/sessions/tab_loader.cc
+++ b/chrome/browser/sessions/tab_loader.cc
@@ -276,11 +276,8 @@
   // Create a TabLoaderDelegate which will allow OS specific behavior for tab
   // loading. This needs to be done before any calls to AddTab, as the delegate
   // is used there.
-  bool delegate_existed = true;
-  if (!delegate_) {
+  if (!delegate_)
     delegate_ = TabLoaderDelegate::Create(this);
-    delegate_existed = false;
-  }
 
   // Add the tabs to the list of tabs loading/to load. Also, restore the
   // favicons of the background tabs (the title has already been set by now).
diff --git a/chrome/browser/sharing/features.cc b/chrome/browser/sharing/features.cc
new file mode 100644
index 0000000..9edbe35a
--- /dev/null
+++ b/chrome/browser/sharing/features.cc
@@ -0,0 +1,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.
+
+#include "chrome/browser/sharing/features.h"
+
+const base::Feature kSharingDeviceRegistration{
+    "SharingDeviceRegistration", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/sharing/features.h b/chrome/browser/sharing/features.h
new file mode 100644
index 0000000..3117e1a
--- /dev/null
+++ b/chrome/browser/sharing/features.h
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_FEATURES_H_
+#define CHROME_BROWSER_SHARING_FEATURES_H_
+
+#include "base/feature_list.h"
+
+// Feature to allow device registration for sharing features.
+extern const base::Feature kSharingDeviceRegistration;
+
+#endif  // CHROME_BROWSER_SHARING_FEATURES_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index be73aa2..ed529c07a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1338,6 +1338,7 @@
       "//components/feedback/proto",
       "//components/keep_alive_registry",
       "//components/network_session_configurator/common",
+      "//components/profile_metrics",
       "//components/ui_metrics",
       "//components/url_formatter",
       "//components/vector_icons",
diff --git a/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc b/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc
index d5e992c9..8c315bf 100644
--- a/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc
@@ -80,7 +80,7 @@
   }
   void SetUpOnMainThread() override {
     UIPerformanceTest::SetUpOnMainThread();
-    ash::ShellTestApi().EnableTabletModeWindowManager(true);
+    ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
     if (base::SysInfo::IsRunningOnChromeOS()) {
       base::RunLoop run_loop;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 0df23da..5bca344 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
-#include "chrome/browser/ui/app_list/app_sync_ui_state.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_icon_loader.h"
@@ -222,10 +221,6 @@
     profile = ProfileManager::GetActiveUserProfile();
     if (!profile->IsGuestSession() && !profile->IsSystemProfile())
       profile = profile->GetOriginalProfile();
-
-    app_sync_ui_state_ = AppSyncUIState::Get(profile);
-    if (app_sync_ui_state_)
-      app_sync_ui_state_->AddObserver(this);
   }
 
   // All profile relevant settings get bound to the current profile.
@@ -1185,9 +1180,6 @@
 }
 
 void ChromeLauncherController::ReleaseProfile() {
-  if (app_sync_ui_state_)
-    app_sync_ui_state_->RemoveObserver(this);
-
   app_updaters_.clear();
 
   pref_change_registrar_.RemoveAll();
@@ -1275,22 +1267,3 @@
     RemovePinPosition(profile(), old_item.id);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// AppSyncUIStateObserver:
-
-void ChromeLauncherController::OnAppSyncUIStatusChanged() {
-  // Update the app list button title to reflect the syncing status.
-  base::string16 title = l10n_util::GetStringUTF16(
-      app_sync_ui_state_->status() == AppSyncUIState::STATUS_SYNCING
-          ? IDS_ASH_SHELF_APP_LIST_LAUNCHER_SYNCING_TITLE
-          : IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE);
-
-  const int app_list_index =
-      model_->GetItemIndexForType(ash::TYPE_APP_LIST_DEPRECATED);
-  DCHECK_GE(app_list_index, 0);
-  ash::ShelfItem item = model_->items()[app_list_index];
-  if (item.title != title) {
-    item.title = title;
-    model_->Set(app_list_index, item);
-  }
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 99c6dd1..3bafaab7 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -17,7 +17,6 @@
 #include "base/memory/weak_ptr.h"
 #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"
@@ -28,7 +27,6 @@
 #include "components/sync_preferences/pref_service_syncable_observer.h"
 
 class AppIconLoader;
-class AppSyncUIState;
 class AppWindowLauncherController;
 class BrowserShortcutLauncherItemController;
 class BrowserStatusMonitor;
@@ -66,7 +64,6 @@
     : public LauncherAppUpdater::Delegate,
       public AppIconLoaderDelegate,
       private ash::ShelfModelObserver,
-      private AppSyncUIStateObserver,
       private app_list::AppListSyncableService::Observer,
       private sync_preferences::PrefServiceSyncableObserver {
  public:
@@ -340,9 +337,6 @@
   void ShelfItemMoved(int start_index, int target_index) override;
   void ShelfItemChanged(int index, const ash::ShelfItem& old_item) override;
 
-  // AppSyncUIStateObserver:
-  void OnAppSyncUIStatusChanged() override;
-
   // app_list::AppListSyncableService::Observer:
   void OnSyncModelUpdated() override;
 
@@ -409,8 +403,6 @@
 
   PrefChangeRegistrar pref_change_registrar_;
 
-  AppSyncUIState* app_sync_ui_state_ = nullptr;
-
   // The owned browser status monitor.
   std::unique_ptr<BrowserStatusMonitor> browser_status_monitor_;
 
diff --git a/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc
index a07d83e..bf8f784 100644
--- a/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc
@@ -61,7 +61,7 @@
 
     // switch to tablet-mode if necessary.
     if (is_tablet_mode_)
-      shell_test_api.EnableTabletModeWindowManager(true);
+      shell_test_api.SetTabletModeEnabledForTest(true);
 
     // Open the fullscreen app; required for page switching.
     BrowserView* browser_view =
diff --git a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
index e62b33f..3590419 100644
--- a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
@@ -885,14 +885,14 @@
   EXPECT_FALSE(wm::GetWindowState(window(0))->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(window(1))->IsMaximized());
 
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
   EXPECT_TRUE(wm::GetWindowState(window(0))->IsMaximized());
   EXPECT_TRUE(wm::GetWindowState(window(1))->IsMaximized());
 
   // Tests that on exiting tablet mode, the window states return to not
   // maximized.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
   EXPECT_FALSE(wm::GetWindowState(window(0))->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(window(1))->IsMaximized());
 }
@@ -1563,7 +1563,7 @@
   window(1)->SetBounds(bounds);
 
   // Enter tablet mode.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
   // Tests that bounds of both windows are maximized.
   const gfx::Rect maximized_bounds(0, 0, 400,
                                    200 - ShelfConstants::shelf_size());
@@ -1577,7 +1577,7 @@
                               display::Display::RotationSource::ACTIVE);
   test_api.SetDisplayRotation(display::Display::ROTATE_0,
                               display::Display::RotationSource::ACTIVE);
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
 
   // Tests that both windows have the same bounds as when they entered tablet
   // mode.
diff --git a/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc b/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc
index 1390f43..f4d8546 100644
--- a/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc
@@ -34,7 +34,7 @@
     tablet_mode_ = std::get<2>(GetParam());
 
     if (tablet_mode_)
-      ash::ShellTestApi().EnableTabletModeWindowManager(true);
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
     GURL ntp_url("chrome://newtab");
     // The default is blank page.
diff --git a/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc b/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc
index faa5b37..77293b0 100644
--- a/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc
@@ -76,7 +76,7 @@
   // UIPerformanceTest:
   void SetUpOnMainThread() override {
     UIPerformanceTest::SetUpOnMainThread();
-    ash::ShellTestApi().EnableTabletModeWindowManager(true);
+    ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
     int additional_browsers = std::get<0>(GetParam()) - 1;
     bool blank_page = std::get<1>(GetParam());
diff --git a/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc b/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
index 42520d1..ed0ee4e 100644
--- a/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
@@ -34,7 +34,7 @@
   // UIPerformanceTest:
   void SetUpOnMainThread() override {
     UIPerformanceTest::SetUpOnMainThread();
-    ash::ShellTestApi().EnableTabletModeWindowManager(true);
+    ash::ShellTestApi().SetTabletModeEnabledForTest(true);
     auto* pref = browser()->profile()->GetPrefs();
     pref->SetBoolean(
         ash::prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted, true);
diff --git a/chrome/browser/ui/ash/split_view_interactive_uitest.cc b/chrome/browser/ui/ash/split_view_interactive_uitest.cc
index f29aa3e..72de74e2 100644
--- a/chrome/browser/ui/ash/split_view_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/split_view_interactive_uitest.cc
@@ -108,7 +108,7 @@
   aura::Window* browser2_window = browser2->window()->GetNativeWindow();
   test::ActivateAndSnapWindow(browser2_window,
                               ash::WindowStateType::kRightSnapped);
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   WaitForWarmup();
 
@@ -126,7 +126,7 @@
   generator.Wait();
   TRACE_EVENT_ASYNC_END0("ui", "Interaction.ui_WindowResize", this);
 
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
 }
 
 IN_PROC_BROWSER_TEST_P(SplitViewTest, ResizeWithOverview) {
@@ -139,7 +139,7 @@
   test::ActivateAndSnapWindow(browser2_window,
                               ash::WindowStateType::kRightSnapped);
 
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   ash::ShellTestApi().WaitForOverviewAnimationState(
       ash::OverviewAnimationState::kEnterAnimationComplete);
 
@@ -158,7 +158,7 @@
   generator.Wait();
   TRACE_EVENT_ASYNC_END0("ui", "Interaction.ui_WindowResize", this);
 
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
 }
 
 INSTANTIATE_TEST_SUITE_P(,
diff --git a/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc b/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc
index 729792f1d..bcce0967 100644
--- a/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc
@@ -96,7 +96,7 @@
     base::RunLoop run_loop;
     ui::LayerAnimator* animator = browser_window->layer()->GetAnimator();
     TestLayerAnimationObserver waiter(animator, run_loop.QuitClosure());
-    ash::ShellTestApi().EnableTabletModeWindowManager(true);
+    ash::ShellTestApi().SetTabletModeEnabledForTest(true);
     run_loop.Run();
   }
 
@@ -104,7 +104,7 @@
     base::RunLoop run_loop;
     ui::LayerAnimator* animator = browser_window->layer()->GetAnimator();
     TestLayerAnimationObserver waiter(animator, run_loop.QuitClosure());
-    ash::ShellTestApi().EnableTabletModeWindowManager(false);
+    ash::ShellTestApi().SetTabletModeEnabledForTest(false);
     run_loop.Run();
   }
 }
diff --git a/chrome/browser/ui/bookmarks/bookmark_stats.cc b/chrome/browser/ui/bookmarks/bookmark_stats.cc
index 647fc43f..aca328d 100644
--- a/chrome/browser/ui/bookmarks/bookmark_stats.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_stats.cc
@@ -37,7 +37,7 @@
 
 void RecordBookmarkLaunch(const BookmarkNode* node,
                           BookmarkLaunchLocation location,
-                          ProfileMetrics::BrowserProfileType profile_type) {
+                          profile_metrics::BrowserProfileType profile_type) {
   if (IsBookmarkBarLocation(location)) {
     base::RecordAction(base::UserMetricsAction("ClickedBookmarkBarURLButton"));
   } else if (location == BOOKMARK_LAUNCH_LOCATION_APP_MENU) {
diff --git a/chrome/browser/ui/bookmarks/bookmark_stats.h b/chrome/browser/ui/bookmarks/bookmark_stats.h
index d8adeec8..32717631 100644
--- a/chrome/browser/ui/bookmarks/bookmark_stats.h
+++ b/chrome/browser/ui/bookmarks/bookmark_stats.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_STATS_H_
 #define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_STATS_H_
 
-#include "chrome/browser/profiles/profile_metrics.h"
+#include "components/profile_metrics/browser_profile_type.h"
 
 namespace bookmarks {
 class BookmarkNode;
@@ -48,7 +48,7 @@
 // Records the launch of a bookmark for UMA purposes.
 void RecordBookmarkLaunch(const bookmarks::BookmarkNode* node,
                           BookmarkLaunchLocation location,
-                          ProfileMetrics::BrowserProfileType profile_type);
+                          profile_metrics::BrowserProfileType profile_type);
 
 // Records the user launching all bookmarks in a folder (via middle-click, etc.)
 // for UMA purposes.
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 18db3e5..eb01cab 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -572,8 +572,7 @@
   // destroyed directly by Browser (e.g. for offscreen tabs,
   // https://crbug.com/664351).
   if (profile_->IsOffTheRecord() &&
-      profile_->GetOriginalProfile()->HasOffTheRecordProfile() &&
-      profile_->GetOriginalProfile()->GetOffTheRecordProfile() == profile_ &&
+      !profile_->IsIndependentOffTheRecordProfile() &&
       !BrowserList::IsIncognitoSessionInUse(profile_) &&
       !profile_->GetOriginalProfile()->IsSystemProfile()) {
     if (profile_->IsGuestSession()) {
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash_browsertest.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash_browsertest.cc
index 71fd742..c6533cb 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash_browsertest.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash_browsertest.cc
@@ -101,11 +101,11 @@
   // Verify that since the auto hide title bars in tablet mode feature turned
   // on, immersive mode is enabled once tablet mode is entered, and disabled
   // once tablet mode is exited.
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   EXPECT_TRUE(IsImmersiveActive());
   ViewBoundsChangeWaiter::VerifyY(client_view, 0);
 
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   EXPECT_FALSE(IsImmersiveActive());
   ViewBoundsChangeWaiter::VerifyY(client_view, kFrameHeight);
 
@@ -113,22 +113,22 @@
   // will remain fullscreened after exiting tablet mode.
   app_window_->OSFullscreen();
   EXPECT_TRUE(IsImmersiveActive());
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   EXPECT_TRUE(IsImmersiveActive());
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   EXPECT_TRUE(IsImmersiveActive());
   app_window_->Restore();
 
   // Verify that minimized windows do not have immersive mode enabled.
   app_window_->Minimize();
   EXPECT_FALSE(IsImmersiveActive());
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   EXPECT_FALSE(IsImmersiveActive());
   window()->Restore();
   EXPECT_TRUE(IsImmersiveActive());
   app_window_->Minimize();
   EXPECT_FALSE(IsImmersiveActive());
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   EXPECT_FALSE(IsImmersiveActive());
 
   // Verify that activation change should not change the immersive
@@ -153,10 +153,10 @@
 
   app_window_->OSFullscreen();
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, window()->GetRestoredState());
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   EXPECT_TRUE(window()->IsFullscreen());
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, window()->GetRestoredState());
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, window()->GetRestoredState());
 
   CloseAppWindow(app_window_);
@@ -171,9 +171,9 @@
 
   app_window_->ForcedFullscreen();
 
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   EXPECT_FALSE(IsImmersiveActive());
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   EXPECT_FALSE(IsImmersiveActive());
 }
 
@@ -207,7 +207,7 @@
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, window()->GetRestoredState());
   EXPECT_TRUE(window()->IsFullscreen());
   EXPECT_TRUE(IsImmersiveActive());
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   EXPECT_TRUE(window()->IsFullscreen());
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, window()->GetRestoredState());
 
@@ -219,7 +219,7 @@
 
   // Immersive fullscreen should be disabled if window exits fullscreen in
   // clamshell mode.
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   app_window_->OSFullscreen();
   EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, window()->GetRestoredState());
   EXPECT_TRUE(window()->IsFullscreen());
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
index 1e3c8a0..cfd70e5f 100644
--- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
@@ -234,7 +234,7 @@
   storage_checkbox->SetBorder(views::CreateEmptyBorder(gfx::Insets()));
   storage_checkbox->SetChecked(controller_->GetStoreLocallyStartState());
   storage_checkbox->SetEnabledTextColors(views::style::GetColor(
-      *storage_checkbox_, ChromeTextContext::CONTEXT_BODY_TEXT_SMALL,
+      *storage_checkbox.get(), ChromeTextContext::CONTEXT_BODY_TEXT_SMALL,
       STYLE_SECONDARY));
   storage_checkbox_ = storage_checkbox.get();
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
index 28208233..02bd954 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
@@ -35,7 +35,7 @@
       observer_(NULL),
       for_drop_(for_drop),
       bookmark_bar_(NULL) {
-  menu_delegate_->Init(this, NULL, node, int{start_child_index},
+  menu_delegate_->Init(this, NULL, node, start_child_index,
                        BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
                        BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER);
   int run_type = 0;
@@ -169,7 +169,7 @@
   if (!node || !node->is_folder())
     return NULL;
 
-  menu_delegate_->SetActiveMenu(node, int{start_index});
+  menu_delegate_->SetActiveMenu(node, start_index);
   *button = bookmark_bar_->GetMenuButtonForNode(node);
   bookmark_bar_->GetAnchorPositionForButton(*button, anchor);
   *has_mnemonics = false;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
index a80aa71..a6a017d 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
@@ -88,7 +88,7 @@
 void BookmarkMenuDelegate::Init(views::MenuDelegate* real_delegate,
                                 MenuItemView* parent,
                                 const BookmarkNode* node,
-                                int start_child_index,
+                                size_t start_child_index,
                                 ShowOptions show_options,
                                 BookmarkLaunchLocation location) {
   GetBookmarkModel()->AddObserver(this);
@@ -111,7 +111,7 @@
     bool show_managed =
         show_forced_folders && !managed->managed_node()->children().empty();
     bool has_children =
-        (start_child_index < node->child_count()) || show_managed;
+        (start_child_index < node->children().size()) || show_managed;
     if (has_children && parent->GetSubmenu() &&
         !parent->GetSubmenu()->GetMenuItems().empty())
       parent->AppendSeparator();
@@ -142,7 +142,7 @@
 }
 
 void BookmarkMenuDelegate::SetActiveMenu(const BookmarkNode* node,
-                                         int start_index) {
+                                         size_t start_index) {
   DCHECK(!parent_menu_item_);
   if (!node_to_menu_map_[node])
     CreateMenu(node, start_index, HIDE_PERMANENT_FOLDERS);
@@ -478,7 +478,7 @@
 }
 
 MenuItemView* BookmarkMenuDelegate::CreateMenu(const BookmarkNode* parent,
-                                               int start_child_index,
+                                               size_t start_child_index,
                                                ShowOptions show_options) {
   MenuItemView* menu = new MenuItemView(real_delegate_);
   menu->SetCommand(next_menu_id_++);
@@ -535,15 +535,15 @@
 }
 
 void BookmarkMenuDelegate::BuildMenu(const BookmarkNode* parent,
-                                     int start_child_index,
+                                     size_t start_child_index,
                                      MenuItemView* menu) {
-  DCHECK(parent->children().empty() ||
-         start_child_index < parent->child_count());
+  DCHECK_LE(start_child_index, parent->children().size());
   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
   const gfx::ImageSkia folder_icon =
       chrome::GetBookmarkFolderIcon(TextColorForMenu(menu, parent_));
-  for (int i = start_child_index; i < parent->child_count(); ++i) {
-    const BookmarkNode* node = parent->GetChild(i);
+  for (auto i = parent->children().cbegin() + start_child_index;
+       i != parent->children().cend(); ++i) {
+    const BookmarkNode* node = i->get();
     const int id = next_menu_id_++;
     MenuItemView* child_menu_item;
     if (node->is_url()) {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
index 9e0e3aaf..b2fc3930 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
@@ -67,7 +67,7 @@
   void Init(views::MenuDelegate* real_delegate,
             views::MenuItemView* parent,
             const bookmarks::BookmarkNode* node,
-            int start_child_index,
+            size_t start_child_index,
             ShowOptions show_options,
             BookmarkLaunchLocation location);
 
@@ -79,7 +79,7 @@
 
   // Makes the menu for |node| the active menu. |start_index| is the index of
   // the first child of |node| to show in the menu.
-  void SetActiveMenu(const bookmarks::BookmarkNode* node, int start_index);
+  void SetActiveMenu(const bookmarks::BookmarkNode* node, size_t start_index);
 
   bookmarks::BookmarkModel* GetBookmarkModel() {
     return const_cast<bookmarks::BookmarkModel*>(
@@ -153,7 +153,7 @@
 
   // Creates a menu. This uses BuildMenu() to recursively populate the menu.
   views::MenuItemView* CreateMenu(const bookmarks::BookmarkNode* parent,
-                                  int start_child_index,
+                                  size_t start_child_index,
                                   ShowOptions show_options);
 
   // Invokes BuildMenuForPermanentNode() for the permanent nodes (excluding
@@ -174,7 +174,7 @@
   // Creates an entry in menu for each child node of |parent| starting at
   // |start_child_index|.
   void BuildMenu(const bookmarks::BookmarkNode* parent,
-                 int start_child_index,
+                 size_t start_child_index,
                  views::MenuItemView* menu);
 
   // Registers the necessary mappings for |menu| and |node|.
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 2472da3..ecf4131a 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -1266,7 +1266,7 @@
   EXPECT_TRUE(frame_view->caption_button_container_->GetVisible());
 
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(true));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true));
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
   ToggleOverview();
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
@@ -1301,7 +1301,7 @@
   EXPECT_TRUE(frame_view2->caption_button_container_->GetVisible());
 
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(true));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true));
   ToggleOverview();
   EXPECT_FALSE(frame_view2->caption_button_container_->GetVisible());
 
@@ -1407,7 +1407,7 @@
 
   EXPECT_TRUE(frame_view->caption_button_container_->GetVisible());
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(true));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true));
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
 
   ToggleOverview();
@@ -1416,7 +1416,7 @@
   EXPECT_FALSE(frame_view->caption_button_container_->GetVisible());
 
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(false));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(false));
   EXPECT_TRUE(frame_view->caption_button_container_->GetVisible());
 }
 
@@ -1439,7 +1439,7 @@
 
   // Tablet mode doesn't affect app's caption button's visibility.
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(true));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true));
   EXPECT_TRUE(frame_view->caption_button_container_->GetVisible());
 
   // However, overview mode does.
@@ -1449,7 +1449,7 @@
   EXPECT_TRUE(frame_view->caption_button_container_->GetVisible());
 
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(false));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(false));
   EXPECT_TRUE(frame_view->caption_button_container_->GetVisible());
 }
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
index db7d341..d9253a8 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -219,7 +219,7 @@
   // the associated window's top inset is 0 (the top of the window is not
   // visible).
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(true));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true));
   EXPECT_TRUE(controller()->IsEnabled());
   EXPECT_EQ(0, aura_window->GetProperty(aura::client::kTopViewInset));
 
@@ -237,13 +237,13 @@
   ToggleFullscreen();
   EXPECT_TRUE(controller()->IsEnabled());
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(false));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(false));
   EXPECT_TRUE(controller()->IsEnabled());
 
   // Verify that immersive mode remains if the browser was fullscreened when
   // entering tablet mode.
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(true));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(true));
   EXPECT_TRUE(controller()->IsEnabled());
 
   // Verify that if the browser is not fullscreened, upon exiting tablet mode,
@@ -252,7 +252,7 @@
   ToggleFullscreen();
   EXPECT_TRUE(controller()->IsEnabled());
   ASSERT_NO_FATAL_FAILURE(
-      ash::ShellTestApi().EnableTabletModeWindowManager(false));
+      ash::ShellTestApi().SetTabletModeEnabledForTest(false));
   EXPECT_FALSE(controller()->IsEnabled());
 
   EXPECT_GT(aura_window->GetProperty(aura::client::kTopViewInset), 0);
@@ -276,7 +276,7 @@
   EXPECT_TRUE(frame_test_api.size_button()->GetVisible());
 
   // Verify the size button is hidden in tablet mode.
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
   frame_test_api.EndAnimations();
 
   EXPECT_TRUE(frame_test_api.size_button()->GetVisible());
@@ -285,7 +285,7 @@
 
   // Verify the size button is visible in clamshell mode, and that it does not
   // cover the other two buttons.
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   frame_test_api.EndAnimations();
 
   EXPECT_TRUE(frame_test_api.size_button()->GetVisible());
@@ -302,7 +302,7 @@
 IN_PROC_BROWSER_TEST_F(ImmersiveModeControllerAshHostedAppBrowserTest,
                        FrameLayoutStartInTabletMode) {
   // Start in tablet mode
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   BrowserNonClientFrameViewAsh* frame_view = nullptr;
   {
@@ -323,6 +323,6 @@
 
   // Verify the size button is visible in clamshell mode, and that it does not
   // cover the other two buttons.
-  ash::ShellTestApi().EnableTabletModeWindowManager(false);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(false);
   VerifyButtonsInImmersiveMode(frame_view);
 }
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index 88d4429..a16e831 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -25,7 +25,7 @@
 namespace gfx {
 class FontList;
 class ImageSkia;
-}
+}  // namespace gfx
 
 namespace ui {
 struct AXNodeData;
diff --git a/chrome/browser/ui/views/location_bar/intent_picker_view.cc b/chrome/browser/ui/views/location_bar/intent_picker_view.cc
index d45416d04..6d4f9f8 100644
--- a/chrome/browser/ui/views/location_bar/intent_picker_view.cc
+++ b/chrome/browser/ui/views/location_bar/intent_picker_view.cc
@@ -25,8 +25,7 @@
 
 IntentPickerView::IntentPickerView(Browser* browser,
                                    PageActionIconView::Delegate* delegate)
-    : PageActionIconView(nullptr, 0, delegate), browser_(browser) {
-}
+    : PageActionIconView(nullptr, 0, delegate), browser_(browser) {}
 
 IntentPickerView::~IntentPickerView() = default;
 
diff --git a/chrome/browser/ui/views/location_bar/location_bar_layout.cc b/chrome/browser/ui/views/location_bar/location_bar_layout.cc
index 4bbcd07..31ac277 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_layout.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_layout.cc
@@ -59,14 +59,12 @@
   DCHECK((max_fraction == 0.0) || (!auto_collapse && (max_fraction > 0.0)));
 }
 
-
 // LocationBarLayout ---------------------------------------------------------
 
 LocationBarLayout::LocationBarLayout(Position position, int item_edit_padding)
     : position_(position), item_edit_padding_(item_edit_padding) {}
 
-LocationBarLayout::~LocationBarLayout() {
-}
+LocationBarLayout::~LocationBarLayout() {}
 
 void LocationBarLayout::AddDecoration(int y,
                                       int height,
@@ -94,7 +92,7 @@
   *entry_width -= item_edit_padding_;
 }
 
-void LocationBarLayout::LayoutPass2(int *entry_width) {
+void LocationBarLayout::LayoutPass2(int* entry_width) {
   for (const auto& decoration : decorations_) {
     if (decoration->max_fraction > 0.0) {
       int max_width = static_cast<int>(*entry_width * decoration->max_fraction);
@@ -128,16 +126,16 @@
     first_visible = false;
 
     // Layout visible decorations.
-    int x = (position_ == LEFT_EDGE)
+    int x = (position_ == Position::kLeftEdge)
                 ? (bounds->x() + padding)
                 : (bounds->right() - padding - decoration->computed_width);
     decoration->view->SetBounds(x, decoration->y, decoration->computed_width,
                                 decoration->height);
     bounds->set_width(bounds->width() - padding - decoration->computed_width);
-    if (position_ == LEFT_EDGE)
+    if (position_ == Position::kLeftEdge)
       bounds->set_x(bounds->x() + padding + decoration->computed_width);
   }
   bounds->set_width(bounds->width() - item_edit_padding_);
-  if (position_ == LEFT_EDGE)
+  if (position_ == Position::kLeftEdge)
     bounds->set_x(bounds->x() + item_edit_padding_);
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_layout.h b/chrome/browser/ui/views/location_bar/location_bar_layout.h
index 192ccbdb..d87fec0 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_layout.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_layout.h
@@ -22,11 +22,10 @@
 
 // Helper class used to layout a list of decorations inside the omnibox.
 class LocationBarLayout {
-
  public:
-  enum Position {
-    LEFT_EDGE = 0,
-    RIGHT_EDGE,
+  enum class Position {
+    kLeftEdge,
+    kRightEdge,
   };
 
   LocationBarLayout(Position position, int item_edit_padding);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 897edfa0..bb913a9 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -483,10 +483,10 @@
   // an extended I-beam click target without affecting actual layout.
   leading_edit_item_padding -= omnibox_view_->GetInsets().left();
 
-  LocationBarLayout leading_decorations(LocationBarLayout::LEFT_EDGE,
+  LocationBarLayout leading_decorations(LocationBarLayout::Position::kLeftEdge,
                                         leading_edit_item_padding);
-  LocationBarLayout trailing_decorations(LocationBarLayout::RIGHT_EDGE,
-                                         edge_padding);
+  LocationBarLayout trailing_decorations(
+      LocationBarLayout::Position::kRightEdge, edge_padding);
 
   const base::string16 keyword(omnibox_view_->model()->keyword());
   // In some cases (e.g. fullscreen mode) we may have 0 height.  We still want
@@ -507,12 +507,13 @@
     if (selected_keyword_view_->keyword() != keyword) {
       selected_keyword_view_->SetKeyword(keyword);
       const TemplateURL* template_url =
-          TemplateURLServiceFactory::GetForProfile(profile())->
-          GetTemplateURLForKeyword(keyword);
+          TemplateURLServiceFactory::GetForProfile(profile())
+              ->GetTemplateURLForKeyword(keyword);
       if (template_url &&
           (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)) {
-        gfx::Image image = extensions::OmniboxAPI::Get(profile())->
-            GetOmniboxIcon(template_url->GetExtensionId());
+        gfx::Image image =
+            extensions::OmniboxAPI::Get(profile())->GetOmniboxIcon(
+                template_url->GetExtensionId());
         selected_keyword_view_->SetImage(image.AsImageSkia());
       } else if (template_url && template_url->type() == TemplateURL::NORMAL &&
                  OmniboxFieldTrial::IsExperimentalKeywordModeEnabled()) {
@@ -1123,9 +1124,9 @@
   DCHECK_EQ(location_icon_view_, sender);
   WebContents* web_contents = delegate_->GetWebContents();
   return (web_contents && web_contents->GetURL().is_valid() &&
-          (!GetOmniboxView()->IsEditingOrEmpty())) ?
-      (ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK) :
-      ui::DragDropTypes::DRAG_NONE;
+          (!GetOmniboxView()->IsEditingOrEmpty()))
+             ? (ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK)
+             : ui::DragDropTypes::DRAG_NONE;
 }
 
 bool LocationBarView::CanStartDragForView(View* sender,
@@ -1312,11 +1313,11 @@
   security_state::SecurityLevel level = security_state::SecurityLevel::NONE;
   if (!IsEditingOrEmpty())
     level = GetLocationBarModel()->GetSecurityLevel();
-  return omnibox_view() ? omnibox_view()->GetIcon(
-                              GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
-                              GetSecurityChipColor(level),
-                              std::move(on_icon_fetched))
-                        : gfx::ImageSkia();
+  return omnibox_view()
+             ? omnibox_view()->GetIcon(
+                   GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
+                   GetSecurityChipColor(level), std::move(on_icon_fetched))
+             : gfx::ImageSkia();
 }
 
 SkColor LocationBarView::GetLocationIconInkDropColor() const {
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index b0d34d4..d1db40e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -54,7 +54,7 @@
 namespace autofill {
 class LocalCardMigrationIconView;
 class SaveCardIconView;
-}
+}  // namespace autofill
 
 namespace send_tab_to_self {
 class SendTabToSelfIconView;
@@ -63,7 +63,7 @@
 namespace views {
 class ImageButton;
 class Label;
-}
+}  // namespace views
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -96,7 +96,7 @@
 
     // Returns ContentSettingBubbleModelDelegate.
     virtual ContentSettingBubbleModelDelegate*
-        GetContentSettingBubbleModelDelegate() = 0;
+    GetContentSettingBubbleModelDelegate() = 0;
 
    protected:
     virtual ~Delegate() {}
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc
index cbf3a0b..713a40a 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -39,8 +39,7 @@
   label()->SetAutoColorReadabilityEnabled(false);
 }
 
-LocationIconView::~LocationIconView() {
-}
+LocationIconView::~LocationIconView() {}
 
 gfx::Size LocationIconView::GetMinimumSize() const {
   return GetMinimumSizeForPreferredSize(GetPreferredSize());
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
index 02b8ef7c..bc3bc7c 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
@@ -42,10 +42,8 @@
   scoped_refptr<content::MessageLoopRunner> runner1 =
       new content::MessageLoopRunner;
   ui_test_utils::MoveMouseToCenterAndPress(
-      location_icon_view,
-      ui_controls::LEFT,
-      ui_controls::DOWN | ui_controls::UP,
-      runner1->QuitClosure());
+      location_icon_view, ui_controls::LEFT,
+      ui_controls::DOWN | ui_controls::UP, runner1->QuitClosure());
   runner1->Run();
 
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_PAGE_INFO,
@@ -55,10 +53,8 @@
   scoped_refptr<content::MessageLoopRunner> runner2 =
       new content::MessageLoopRunner;
   ui_test_utils::MoveMouseToCenterAndPress(
-      location_icon_view,
-      ui_controls::LEFT,
-      ui_controls::DOWN | ui_controls::UP,
-      runner2->QuitClosure());
+      location_icon_view, ui_controls::LEFT,
+      ui_controls::DOWN | ui_controls::UP, runner2->QuitClosure());
   runner2->Run();
 
   EXPECT_EQ(PageInfoBubbleView::BUBBLE_NONE,
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
index 0d36dc1..e419f174 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -32,8 +32,7 @@
   label()->SetElideBehavior(gfx::FADE_TAIL);
 }
 
-SelectedKeywordView::~SelectedKeywordView() {
-}
+SelectedKeywordView::~SelectedKeywordView() {}
 
 void SelectedKeywordView::ResetImage() {
   SetImage(gfx::CreateVectorIcon(vector_icons::kSearchIcon,
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.h b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
index 0f3ea308..4490015 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.h
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
@@ -10,14 +10,16 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/views/controls/label.h"
 
 class LocationBarView;
 class Profile;
+
 namespace gfx {
 class FontList;
 class Size;
-}
+}  // namespace gfx
 
 // SelectedKeywordView displays the tab-to-search UI in the location bar view.
 class SelectedKeywordView : public IconLabelBubbleView {
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc
index 198c143..8712890 100644
--- a/chrome/browser/ui/views/location_bar/star_view.cc
+++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -86,8 +86,7 @@
       entry_point = BOOKMARK_ENTRY_POINT_STAR_GESTURE;
       break;
   }
-  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
-                            entry_point,
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint", entry_point,
                             BOOKMARK_ENTRY_POINT_LIMIT);
 }
 
diff --git a/chrome/browser/ui/views/location_bar/star_view_browsertest.cc b/chrome/browser/ui/views/location_bar/star_view_browsertest.cc
index 1acff6b..e07e0f5 100644
--- a/chrome/browser/ui/views/location_bar/star_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/star_view_browsertest.cc
@@ -52,13 +52,13 @@
 #define MAYBE_HideOnSecondClick HideOnSecondClick
 #endif
 IN_PROC_BROWSER_TEST_F(StarViewTest, MAYBE_HideOnSecondClick) {
-  BrowserView* browser_view = reinterpret_cast<BrowserView*>(
-      browser()->window());
+  BrowserView* browser_view =
+      reinterpret_cast<BrowserView*>(browser()->window());
   views::View* star_view = browser_view->toolbar()->location_bar()->star_view();
 
-  ui::MouseEvent pressed_event(
-      ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
-      ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+                               ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                               ui::EF_LEFT_MOUSE_BUTTON);
   ui::MouseEvent released_event(
       ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
       ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
index 012ca6e6..30b977d55 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
@@ -509,8 +509,9 @@
     Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
     DCHECK(browser);
     chrome::AddSelectedTabWithURL(
-        browser, GURL(base::StringPrintf("chrome://extensions?id=%s",
-                                         extension_info_.id.c_str())),
+        browser,
+        GURL(base::StringPrintf("chrome://extensions?id=%s",
+                                extension_info_.id.c_str())),
         ui::PAGE_TRANSITION_FROM_API);
   } else if (sender == zoom_out_button_) {
     zoom::PageZoom::Zoom(web_contents(), content::PAGE_ZOOM_OUT);
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index a3b7a1c..4ba49d0b 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -313,10 +313,9 @@
         /*required=*/true, EditorField::ControlType::COMBOBOX};
     std::unique_ptr<ValidatingCombobox> month_combobox =
         CreateComboboxForField(tmp_month, error_message);
-    *focusable_field = month_combobox.get();
-    combobox_layout->AddView(month_combobox.release(), 1, 1,
-                             views::GridLayout::FILL, views::GridLayout::FILL,
-                             0, kInputFieldHeight);
+    *focusable_field = combobox_layout->AddView(
+        std::move(month_combobox), 1, 1, views::GridLayout::FILL,
+        views::GridLayout::FILL, 0, kInputFieldHeight);
 
     EditorField tmp_year{
         autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR,
@@ -325,7 +324,7 @@
         /*required=*/true, EditorField::ControlType::COMBOBOX};
     std::unique_ptr<ValidatingCombobox> year_combobox =
         CreateComboboxForField(tmp_year, error_message);
-    combobox_layout->AddView(year_combobox.release(), 1, 1,
+    combobox_layout->AddView(std::move(year_combobox), 1, 1,
                              views::GridLayout::FILL, views::GridLayout::FILL,
                              0, kInputFieldHeight);
   }
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
index 628f3fe7..2b04820 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
@@ -144,14 +144,13 @@
   layout->StartRow(views::GridLayout::kFixedSize, 0);
   // The prompt for server cards should reference Google Payments, whereas the
   // prompt for local cards should not.
-  std::unique_ptr<views::Label> instructions =
-      std::make_unique<views::Label>(l10n_util::GetStringUTF16(
-          credit_card_.record_type() == autofill::CreditCard::LOCAL_CARD
-              ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_LOCAL_CARD
-              : IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS));
+  auto instructions = std::make_unique<views::Label>(l10n_util::GetStringUTF16(
+      credit_card_.record_type() == autofill::CreditCard::LOCAL_CARD
+          ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_LOCAL_CARD
+          : IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS));
   instructions->SetMultiLine(true);
   instructions->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  layout->AddView(instructions.release());
+  layout->AddView(std::move(instructions));
 
   // Space between the instructions and the CVC field.
   layout->AddPaddingRow(views::GridLayout::kFixedSize, 16);
@@ -196,18 +195,17 @@
     month->SetID(static_cast<int>(DialogViewID::CVC_MONTH));
     month->SelectValue(credit_card_.ExpirationMonthAsString());
     month->SetInvalid(true);
-    layout->AddView(month.release());
+    layout->AddView(std::move(month));
 
     auto year = std::make_unique<views::Combobox>(&year_combobox_model_);
     year->set_listener(this);
     year->SetID(static_cast<int>(DialogViewID::CVC_YEAR));
     year->SelectValue(credit_card_.Expiration4DigitYearAsString());
     year->SetInvalid(true);
-    layout->AddView(year.release());
+    layout->AddView(std::move(year));
   }
 
-  std::unique_ptr<views::ImageView> cvc_image =
-      std::make_unique<views::ImageView>();
+  auto cvc_image = std::make_unique<views::ImageView>();
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   // TODO(anthonyvd): Consider using
   // CardUnmaskPromptControllerImpl::GetCvcImageRid.
@@ -217,14 +215,12 @@
           : IDR_CREDIT_CARD_CVC_HINT));
   cvc_image->set_tooltip_text(l10n_util::GetStringUTF16(
       IDS_AUTOFILL_CARD_UNMASK_CVC_IMAGE_DESCRIPTION));
-  layout->AddView(cvc_image.release());
+  layout->AddView(std::move(cvc_image));
 
-  std::unique_ptr<views::Textfield> cvc_field =
-      std::unique_ptr<views::Textfield>(autofill::CreateCvcTextfield());
+  std::unique_ptr<views::Textfield> cvc_field = autofill::CreateCvcTextfield();
   cvc_field->set_controller(this);
   cvc_field->SetID(static_cast<int>(DialogViewID::CVC_PROMPT_TEXT_FIELD));
-  cvc_field_ = cvc_field.get();
-  layout->AddView(cvc_field.release());
+  cvc_field_ = layout->AddView(std::move(cvc_field));
 
   // Space between the CVC field and the error field.
   layout->AddPaddingRow(views::GridLayout::kFixedSize, 16);
@@ -242,17 +238,16 @@
                            views::GridLayout::SizeType::USE_PREF, 0, 0);
 
   layout->StartRow(views::GridLayout::kFixedSize, 2);
-  std::unique_ptr<views::ImageView> error_icon =
-      std::make_unique<views::ImageView>();
+  auto error_icon = std::make_unique<views::ImageView>();
   error_icon->SetID(static_cast<int>(DialogViewID::CVC_ERROR_ICON));
   error_icon->SetImage(
       gfx::CreateVectorIcon(vector_icons::kWarningIcon, 16,
                             error_icon->GetNativeTheme()->GetSystemColor(
                                 ui::NativeTheme::kColorId_AlertSeverityHigh)));
   error_icon->SetVisible(false);
-  layout->AddView(error_icon.release());
+  layout->AddView(std::move(error_icon));
 
-  std::unique_ptr<views::Label> error_label = std::make_unique<views::Label>();
+  auto error_label = std::make_unique<views::Label>();
   error_label->SetID(static_cast<int>(DialogViewID::CVC_ERROR_LABEL));
   error_label->SetMultiLine(true);
   error_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -260,7 +255,7 @@
       ui::NativeTheme::kColorId_AlertSeverityHigh));
   error_label->SetVisible(false);
 
-  layout->AddView(error_label.release());
+  layout->AddView(std::move(error_label));
 }
 
 std::unique_ptr<views::Button> CvcUnmaskViewController::CreatePrimaryButton() {
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index 60100f8..6789c03 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -349,10 +349,8 @@
   editor_layout->StartRow(views::GridLayout::kFixedSize, 3);
 
   // Adds the "* indicates a required field" label in "hint" grey text.
-  editor_layout->AddView(
-      CreateHintLabel(
-          l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE))
-          .release());
+  editor_layout->AddView(CreateHintLabel(
+      l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE)));
 
   return editor_view;
 }
@@ -379,7 +377,7 @@
 
   label->SetMultiLine(true);
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  layout->AddView(label.release());
+  layout->AddView(std::move(label));
 
   views::View* focusable_field = nullptr;
   constexpr int kInputFieldHeight = 28;
@@ -393,13 +391,13 @@
       ValidationDelegate* delegate_ptr = validation_delegate.get();
 
       base::string16 initial_value = GetInitialValueForType(field.type);
-      ValidatingTextfield* text_field =
-          new ValidatingTextfield(std::move(validation_delegate));
+      auto text_field =
+          std::make_unique<ValidatingTextfield>(std::move(validation_delegate));
       // Set the initial value and validity state.
       text_field->SetText(initial_value);
       text_field->SetAccessibleName(field.label);
       *valid = IsEditingExistingItem() &&
-               delegate_ptr->IsValidTextfield(text_field, &error_message);
+               delegate_ptr->IsValidTextfield(text_field.get(), &error_message);
       if (IsEditingExistingItem())
         text_field->SetInvalid(!(*valid));
 
@@ -408,26 +406,26 @@
       text_field->set_controller(this);
       // Using autofill field type as a view ID (for testing).
       text_field->SetID(GetInputFieldViewId(field.type));
-      text_fields_.insert(std::make_pair(text_field, field));
-      focusable_field = text_field;
+      text_fields_.insert(std::make_pair(text_field.get(), field));
 
       // |text_field| will now be owned by |row|.
-      layout->AddView(text_field, 1.0, 1.0, views::GridLayout::FILL,
-                      views::GridLayout::FILL, views::GridLayout::kFixedSize,
-                      kInputFieldHeight);
+      focusable_field =
+          layout->AddView(std::move(text_field), 1.0, 1.0,
+                          views::GridLayout::FILL, views::GridLayout::FILL,
+                          views::GridLayout::kFixedSize, kInputFieldHeight);
       break;
     }
     case EditorField::ControlType::COMBOBOX: {
       std::unique_ptr<ValidatingCombobox> combobox =
           CreateComboboxForField(field, &error_message);
 
-      focusable_field = combobox.get();
       *valid = combobox->IsValid();
 
       // |combobox| will now be owned by |row|.
-      layout->AddView(combobox.release(), 1.0, 1.0, views::GridLayout::FILL,
-                      views::GridLayout::FILL, views::GridLayout::kFixedSize,
-                      kInputFieldHeight);
+      focusable_field =
+          layout->AddView(std::move(combobox), 1.0, 1.0,
+                          views::GridLayout::FILL, views::GridLayout::FILL,
+                          views::GridLayout::kFixedSize, kInputFieldHeight);
       break;
     }
     case EditorField::ControlType::CUSTOMFIELD: {
@@ -437,7 +435,7 @@
           field.type, &focusable_field, valid, &error_message);
       DCHECK(field_view);
 
-      layout->AddView(field_view.release(), 1, 1, views::GridLayout::FILL,
+      layout->AddView(std::move(field_view), 1, 1, views::GridLayout::FILL,
                       views::GridLayout::FILL, views::GridLayout::kFixedSize,
                       kInputFieldHeight);
       break;
@@ -447,7 +445,7 @@
           std::make_unique<views::Label>(GetInitialValueForType(field.type));
       label->SetID(GetInputFieldViewId(field.type));
       label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-      layout->AddView(label.release(), 1, 1, views::GridLayout::FILL,
+      layout->AddView(std::move(label), 1, 1, views::GridLayout::FILL,
                       views::GridLayout::FILL, 0, kInputFieldHeight);
       break;
     }
@@ -457,7 +455,7 @@
   // last column.
   std::unique_ptr<views::View> extra_view = CreateExtraViewForField(field.type);
   if (extra_view)
-    layout->AddView(extra_view.release());
+    layout->AddView(std::move(extra_view));
 
   layout->StartRow(views::GridLayout::kFixedSize, 2);
   layout->SkipColumns(1);
@@ -468,7 +466,7 @@
   if (IsEditingExistingItem() && !error_message.empty())
     AddOrUpdateErrorMessageForField(field.type, error_message);
 
-  layout->AddView(error_label_view.release());
+  layout->AddView(std::move(error_label_view));
 
   // Bottom padding for the row.
   layout->AddPaddingRow(views::GridLayout::kFixedSize, kInputRowSpacing);
diff --git a/chrome/browser/ui/views/payments/order_summary_view_controller.cc b/chrome/browser/ui/views/payments/order_summary_view_controller.cc
index b6149ea..644edb5 100644
--- a/chrome/browser/ui/views/payments/order_summary_view_controller.cc
+++ b/chrome/browser/ui/views/payments/order_summary_view_controller.cc
@@ -106,11 +106,11 @@
 
   wrapper_layout->StartRow(views::GridLayout::kFixedSize, 0);
   currency_text->SetID(static_cast<int>(currency_label_id));
-  wrapper_layout->AddView(currency_text.release());
-  wrapper_layout->AddView(amount_text.release());
+  wrapper_layout->AddView(std::move(currency_text));
+  wrapper_layout->AddView(std::move(amount_text));
 
-  layout->AddView(label_text.release());
-  layout->AddView(amount_wrapper.release());
+  layout->AddView(std::move(label_text));
+  layout->AddView(std::move(amount_wrapper));
 
   return row;
 }
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index d4482ab..cca70446 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -82,12 +82,12 @@
       // contrast into account.
       title_label->SetAutoColorReadabilityEnabled(false);
       title_label->SetEnabledColor(foreground);
-      title_origin_layout->AddView(title_label.release());
+      title_origin_layout->AddView(std::move(title_label));
     }
 
     title_origin_layout->StartRow(views::GridLayout::kFixedSize, 0);
-    views::Label* origin_label =
-        new views::Label(base::UTF8ToUTF16(origin.host()));
+    auto origin_label =
+        std::make_unique<views::Label>(base::UTF8ToUTF16(origin.host()));
     origin_label->SetElideBehavior(gfx::ELIDE_HEAD);
     if (!title_is_valid) {
       // Set the origin as title when the page title is invalid.
@@ -104,7 +104,7 @@
     origin_label->SetEnabledColor(foreground);
 
     origin_label->SetBackgroundColor(background_color);
-    title_origin_layout->AddView(origin_label);
+    title_origin_layout->AddView(std::move(origin_label));
 
     views::GridLayout* top_level_layout =
         SetLayoutManager(std::make_unique<views::GridLayout>());
@@ -129,7 +129,7 @@
     }
 
     top_level_layout->StartRow(views::GridLayout::kFixedSize, 0);
-    top_level_layout->AddView(title_origin_container.release());
+    top_level_layout->AddView(std::move(title_origin_container));
     if (has_icon) {
       std::unique_ptr<views::ImageView> instrument_icon_view =
           CreateInstrumentIconView(/*icon_id=*/0, icon_image_skia,
@@ -139,7 +139,7 @@
       instrument_icon_view->SetImageSize(gfx::Size(
           adjusted_width,
           IconSizeCalculator::kPaymentAppDeviceIndependentIdealIconHeight));
-      top_level_layout->AddView(instrument_icon_view.release());
+      top_level_layout->AddView(std::move(instrument_icon_view));
     }
   }
   ~ReadOnlyOriginView() override {}
@@ -223,11 +223,13 @@
 }
 
 std::unique_ptr<views::View>
-PaymentHandlerWebFlowViewController::CreateHeaderContentView() {
+PaymentHandlerWebFlowViewController::CreateHeaderContentView(
+    views::View* header_view) {
   const GURL origin = web_contents()
                           ? web_contents()->GetVisibleURL().GetOrigin()
                           : target_.GetOrigin();
-  std::unique_ptr<views::Background> background = GetHeaderBackground();
+  std::unique_ptr<views::Background> background =
+      GetHeaderBackground(header_view);
   return std::make_unique<ReadOnlyOriginView>(
       GetPaymentHandlerDialogTitle(web_contents(), https_prefix_), origin,
       state()->selected_instrument()->icon_image_skia(),
@@ -242,9 +244,10 @@
 }
 
 std::unique_ptr<views::Background>
-PaymentHandlerWebFlowViewController::GetHeaderBackground() {
+PaymentHandlerWebFlowViewController::GetHeaderBackground(
+    views::View* header_view) {
   auto default_header_background =
-      PaymentRequestSheetController::GetHeaderBackground();
+      PaymentRequestSheetController::GetHeaderBackground(header_view);
   if (web_contents()) {
     return views::CreateSolidBackground(color_utils::GetResultingPaintColor(
         web_contents()->GetThemeColor().value_or(SK_ColorTRANSPARENT),
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
index f84aa4b..3d3306c 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
@@ -59,9 +59,11 @@
   base::string16 GetSheetTitle() override;
   void FillContentView(views::View* content_view) override;
   bool ShouldShowSecondaryButton() override;
-  std::unique_ptr<views::View> CreateHeaderContentView() override;
+  std::unique_ptr<views::View> CreateHeaderContentView(
+      views::View* header_view) override;
   views::View* CreateHeaderContentSeparatorView() override;
-  std::unique_ptr<views::Background> GetHeaderBackground() override;
+  std::unique_ptr<views::Background> GetHeaderBackground(
+      views::View* header_view) override;
   bool GetSheetId(DialogViewID* sheet_id) override;
   bool DisplayDynamicBorderForHiddenContents() override;
 
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index 7e95aac8..969180d 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -68,7 +68,7 @@
 PaymentRequestDialogView::PaymentRequestDialogView(
     PaymentRequest* request,
     PaymentRequestDialogView::ObserverForTest* observer)
-    : request_(request), observer_for_testing_(observer), being_closed_(false) {
+    : request_(request), observer_for_testing_(observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   request->spec()->AddObserver(this);
@@ -174,14 +174,14 @@
 }
 
 void PaymentRequestDialogView::ShowProcessingSpinner() {
-  throbber_.Start();
-  throbber_overlay_.SetVisible(true);
+  throbber_->Start();
+  throbber_overlay_->SetVisible(true);
   if (observer_for_testing_)
     observer_for_testing_->OnProcessingSpinnerShown();
 }
 
 bool PaymentRequestDialogView::IsInteractive() const {
-  return !throbber_overlay_.GetVisible();
+  return !throbber_overlay_->GetVisible();
 }
 
 void PaymentRequestDialogView::ShowPaymentHandlerScreen(
@@ -413,8 +413,8 @@
 }
 
 void PaymentRequestDialogView::HideProcessingSpinner() {
-  throbber_.Stop();
-  throbber_overlay_.SetVisible(false);
+  throbber_->Stop();
+  throbber_overlay_->SetVisible(false);
   if (observer_for_testing_)
     observer_for_testing_->OnProcessingSpinnerHidden();
 }
@@ -441,18 +441,18 @@
 }
 
 void PaymentRequestDialogView::SetupSpinnerOverlay() {
-  throbber_.set_owned_by_client();
+  auto throbber = std::make_unique<views::Throbber>();
+  auto throbber_overlay = std::make_unique<views::View>();
 
-  throbber_overlay_.set_owned_by_client();
-  throbber_overlay_.SetPaintToLayer();
-  throbber_overlay_.SetVisible(false);
+  throbber_overlay->SetPaintToLayer();
+  throbber_overlay->SetVisible(false);
   // The throbber overlay has to have a solid white background to hide whatever
   // would be under it.
-  throbber_overlay_.SetBackground(views::CreateThemedSolidBackground(
-      &throbber_overlay_, ui::NativeTheme::kColorId_DialogBackground));
+  throbber_overlay->SetBackground(views::CreateThemedSolidBackground(
+      throbber_overlay.get(), ui::NativeTheme::kColorId_DialogBackground));
 
   views::GridLayout* layout =
-      throbber_overlay_.SetLayoutManager(std::make_unique<views::GridLayout>());
+      throbber_overlay->SetLayoutManager(std::make_unique<views::GridLayout>());
   views::ColumnSet* throbber_columns = layout->AddColumnSet(0);
   throbber_columns->AddPaddingColumn(0.5, 0);
   throbber_columns->AddColumn(views::GridLayout::Alignment::CENTER,
@@ -470,13 +470,13 @@
   label_columns->AddPaddingColumn(0.5, 0);
 
   layout->StartRow(0.5, 0);
-  layout->AddView(&throbber_);
+  throbber_ = layout->AddView(std::move(throbber));
 
   layout->StartRow(0.5, 1);
-  layout->AddView(new views::Label(
+  layout->AddView(std::make_unique<views::Label>(
       l10n_util::GetStringUTF16(IDS_PAYMENTS_PROCESSING_MESSAGE)));
 
-  AddChildView(&throbber_overlay_);
+  throbber_overlay_ = AddChildView(std::move(throbber_overlay));
 }
 
 gfx::Size PaymentRequestDialogView::CalculatePreferredSize() const {
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.h b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
index 9dfea0d..d6d57f7 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
@@ -180,7 +180,7 @@
   Profile* GetProfile();
 
   ViewStack* view_stack_for_testing() { return view_stack_.get(); }
-  views::View* throbber_overlay_for_testing() { return &throbber_overlay_; }
+  views::View* throbber_overlay_for_testing() { return throbber_overlay_; }
 
  private:
   void ShowInitialPaymentSheet();
@@ -201,15 +201,15 @@
 
   // A full dialog overlay that shows a spinner and the "processing" label. It's
   // hidden until ShowProcessingSpinner is called.
-  views::View throbber_overlay_;
-  views::Throbber throbber_;
+  views::View* throbber_overlay_;
+  views::Throbber* throbber_;
 
   // May be null.
   ObserverForTest* observer_for_testing_;
 
   // Used when the dialog is being closed to avoid re-entrancy into the
   // controller_map_.
-  bool being_closed_;
+  bool being_closed_ = false;
 
   // The number of initialization tasks that are not yet initialized.
   size_t number_of_initialization_tasks_ = 0;
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc
index 1aee1ac1..a3a5fcc 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list.cc
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -96,12 +96,12 @@
 
   layout->StartRow(views::GridLayout::kFixedSize, 0);
   content->set_can_process_events_within_subtree(false);
-  layout->AddView(content.release());
+  layout->AddView(std::move(content));
 
-  layout->AddView(CreateCheckmark(selected() && clickable()).release());
+  layout->AddView(CreateCheckmark(selected() && clickable()));
 
   if (extra_view)
-    layout->AddView(extra_view.release());
+    layout->AddView(std::move(extra_view));
 
   if (show_edit_button_) {
     auto edit_button = views::CreateVectorImageButton(this);
@@ -115,7 +115,7 @@
     edit_button->SetID(static_cast<int>(DialogViewID::EDIT_ITEM_BUTTON));
     edit_button->SetAccessibleName(
         l10n_util::GetStringUTF16(IDS_PAYMENTS_EDIT));
-    layout->AddView(edit_button.release());
+    layout->AddView(std::move(edit_button));
   }
 
   UpdateAccessibleName();
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
index 29d09eb..11614cbb 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -233,17 +233,16 @@
                      views::GridLayout::USE_PREF, 0, 0);
 
   layout->StartRow(views::GridLayout::kFixedSize, 0);
-  header_view_ = std::make_unique<views::View>();
-  PopulateSheetHeaderView(ShouldShowHeaderBackArrow(),
-                          CreateHeaderContentView(), this, header_view_.get(),
-                          GetHeaderBackground());
-  header_view_->set_owned_by_client();
-  layout->AddView(header_view_.get());
+  auto header_view = std::make_unique<views::View>();
+  PopulateSheetHeaderView(
+      ShouldShowHeaderBackArrow(), CreateHeaderContentView(header_view.get()),
+      this, header_view.get(), GetHeaderBackground(header_view.get()));
+  header_view_ = layout->AddView(std::move(header_view));
 
   layout->StartRow(views::GridLayout::kFixedSize, 0);
-  header_content_separator_container_ = std::make_unique<views::View>();
-  header_content_separator_container_->set_owned_by_client();
-  layout->AddView(header_content_separator_container_.get());
+  auto header_content_separator_container = std::make_unique<views::View>();
+  header_content_separator_container_ =
+      layout->AddView(std::move(header_content_separator_container));
   UpdateHeaderContentSeparatorView();
 
   layout->StartRow(1.0, 0);
@@ -251,7 +250,6 @@
   // otherwise it'll be sized to the ScrollView's viewport height, preventing
   // the scroll bar from ever being shown.
   auto pane = std::make_unique<views::View>();
-  pane_ = pane.get();
   views::GridLayout* pane_layout =
       pane->SetLayoutManager(std::make_unique<views::GridLayout>());
   views::ColumnSet* pane_columns = pane_layout->AddColumnSet(0);
@@ -261,26 +259,26 @@
       GetActualDialogWidth(), GetActualDialogWidth());
   pane_layout->StartRow(views::GridLayout::kFixedSize, 0);
   // This is owned by its parent. It's the container passed to FillContentView.
-  content_view_ = new views::View;
-  content_view_->SetPaintToLayer();
-  content_view_->layer()->SetFillsBoundsOpaquely(true);
-  content_view_->SetBackground(views::CreateThemedSolidBackground(
-      content_view_, ui::NativeTheme::kColorId_DialogBackground));
-  content_view_->SetID(static_cast<int>(DialogViewID::CONTENT_VIEW));
-  pane_layout->AddView(content_view_);
+  auto content_view = std::make_unique<views::View>();
+  content_view->SetPaintToLayer();
+  content_view->layer()->SetFillsBoundsOpaquely(true);
+  content_view->SetBackground(views::CreateThemedSolidBackground(
+      content_view.get(), ui::NativeTheme::kColorId_DialogBackground));
+  content_view->SetID(static_cast<int>(DialogViewID::CONTENT_VIEW));
+  content_view_ = pane_layout->AddView(std::move(content_view));
   pane->SizeToPreferredSize();
 
-  scroll_ = DisplayDynamicBorderForHiddenContents()
-                ? std::make_unique<BorderedScrollView>()
-                : std::make_unique<views::ScrollView>();
-  scroll_->set_owned_by_client();
-  scroll_->SetHideHorizontalScrollBar(true);
-  scroll_->SetContents(std::move(pane));
-  layout->AddView(scroll_.get());
+  std::unique_ptr<views::ScrollView> scroll =
+      DisplayDynamicBorderForHiddenContents()
+          ? std::make_unique<BorderedScrollView>()
+          : std::make_unique<views::ScrollView>();
+  scroll->SetHideHorizontalScrollBar(true);
+  pane_ = scroll->SetContents(std::move(pane));
+  scroll_ = layout->AddView(std::move(scroll));
 
   if (footer) {
     layout->StartRow(views::GridLayout::kFixedSize, 0);
-    layout->AddView(footer.release());
+    layout->AddView(std::move(footer));
   }
 
   UpdateContentView();
@@ -298,8 +296,8 @@
 void PaymentRequestSheetController::UpdateHeaderView() {
   header_view_->RemoveAllChildViews(true);
   PopulateSheetHeaderView(ShouldShowHeaderBackArrow(),
-                          CreateHeaderContentView(), this, header_view_.get(),
-                          GetHeaderBackground());
+                          CreateHeaderContentView(header_view_), this,
+                          header_view_, GetHeaderBackground(header_view_));
   header_view_->Layout();
   header_view_->SchedulePaint();
 }
@@ -380,7 +378,8 @@
 }
 
 std::unique_ptr<views::View>
-PaymentRequestSheetController::CreateHeaderContentView() {
+PaymentRequestSheetController::CreateHeaderContentView(
+    views::View* header_view) {
   std::unique_ptr<views::Label> title_label = std::make_unique<views::Label>(
       GetSheetTitle(), views::style::CONTEXT_DIALOG_TITLE);
   title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -395,9 +394,9 @@
 }
 
 std::unique_ptr<views::Background>
-PaymentRequestSheetController::GetHeaderBackground() {
+PaymentRequestSheetController::GetHeaderBackground(views::View* header_view) {
   return views::CreateThemedSolidBackground(
-      header_view_.get(), ui::NativeTheme::kColorId_DialogBackground);
+      header_view, ui::NativeTheme::kColorId_DialogBackground);
 }
 
 void PaymentRequestSheetController::ButtonPressed(views::Button* sender,
@@ -444,7 +443,7 @@
   layout->StartRow(views::GridLayout::kFixedSize, 0);
   std::unique_ptr<views::View> extra_view = CreateExtraFooterView();
   if (extra_view)
-    layout->AddView(extra_view.release());
+    layout->AddView(std::move(extra_view));
   else
     layout->SkipColumns(1);
 
@@ -471,17 +470,17 @@
     return nullptr;
   }
 
-  layout->AddView(trailing_buttons_container.release());
+  layout->AddView(std::move(trailing_buttons_container));
 
   return container;
 }
 
 views::View* PaymentRequestSheetController::GetFirstFocusedView() {
   if (primary_button_ && primary_button_->GetEnabled())
-    return primary_button_.get();
+    return primary_button_;
 
   if (secondary_button_)
-    return secondary_button_.get();
+    return secondary_button_;
 
   DCHECK(content_view_);
   return content_view_;
@@ -501,28 +500,27 @@
     return true;
 
   if (primary_button_ && primary_button_->GetEnabled())
-    ButtonPressed(primary_button_.get(), DummyEvent());
+    ButtonPressed(primary_button_, DummyEvent());
   return true;
 }
 
 void PaymentRequestSheetController::AddPrimaryButton(views::View* container) {
-  primary_button_ = CreatePrimaryButton();
-  if (primary_button_) {
-    primary_button_->set_owned_by_client();
-    primary_button_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
-    container->AddChildView(primary_button_.get());
+  std::unique_ptr<views::Button> primary_button = CreatePrimaryButton();
+  if (primary_button) {
+    primary_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+    primary_button_ = container->AddChildView(std::move(primary_button));
   }
 }
 
 void PaymentRequestSheetController::AddSecondaryButton(views::View* container) {
   if (ShouldShowSecondaryButton()) {
-    secondary_button_ = views::MdTextButton::CreateSecondaryUiButton(
-        this, GetSecondaryButtonLabel());
-    secondary_button_->set_owned_by_client();
-    secondary_button_->set_tag(GetSecondaryButtonTag());
-    secondary_button_->SetID(GetSecondaryButtonId());
-    secondary_button_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
-    container->AddChildView(secondary_button_.get());
+    std::unique_ptr<views::Button> secondary_button =
+        views::MdTextButton::CreateSecondaryUiButton(this,
+                                                     GetSecondaryButtonLabel());
+    secondary_button->set_tag(GetSecondaryButtonTag());
+    secondary_button->SetID(GetSecondaryButtonId());
+    secondary_button->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+    secondary_button_ = container->AddChildView(std::move(secondary_button));
   }
 }
 
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
index 83704e1..d0c141eb 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
@@ -129,14 +129,16 @@
   // close/back button. This is typically the sheet's title but it can be
   // overriden to return a different kind of view as long as it fits inside the
   // header.
-  virtual std::unique_ptr<views::View> CreateHeaderContentView();
+  virtual std::unique_ptr<views::View> CreateHeaderContentView(
+      views::View* header_view);
 
   // Creates and returns the view to be inserted in the header content separator
   // container betweem header and content.
   virtual views::View* CreateHeaderContentSeparatorView();
 
   // Returns the background to use for the header section of the sheet.
-  virtual std::unique_ptr<views::Background> GetHeaderBackground();
+  virtual std::unique_ptr<views::Background> GetHeaderBackground(
+      views::View* header_view);
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
@@ -160,7 +162,7 @@
   // Returns true to display dynamic top and bottom border for hidden contents.
   virtual bool DisplayDynamicBorderForHiddenContents();
 
-  views::Button* primary_button() { return primary_button_.get(); }
+  views::Button* primary_button() { return primary_button_; }
 
  private:
   // Called when the Enter accelerator is pressed. Perform the action associated
@@ -173,24 +175,24 @@
   void AddSecondaryButton(views::View* container);
 
   // All these are not owned. Will outlive this.
-  PaymentRequestSpec* spec_;
-  PaymentRequestState* state_;
-  PaymentRequestDialogView* dialog_;
+  PaymentRequestSpec* spec_ = nullptr;
+  PaymentRequestState* state_ = nullptr;
+  PaymentRequestDialogView* dialog_ = nullptr;
 
   // This view is owned by its encompassing ScrollView.
-  views::View* pane_;
-  views::View* content_view_;
+  views::View* pane_ = nullptr;
+  views::View* content_view_ = nullptr;
 
   // Hold on to the ScrollView because it must be explicitly laid out in some
   // cases.
-  std::unique_ptr<views::ScrollView> scroll_;
+  views::ScrollView* scroll_ = nullptr;
 
   // Hold on to the primary and secondary buttons to use them as initial focus
   // targets when subclasses don't want to focus anything else.
-  std::unique_ptr<views::Button> primary_button_;
-  std::unique_ptr<views::Button> secondary_button_;
-  std::unique_ptr<views::View> header_view_;
-  std::unique_ptr<views::View> header_content_separator_container_;
+  views::Button* primary_button_ = nullptr;
+  views::Button* secondary_button_ = nullptr;
+  views::View* header_view_ = nullptr;
+  views::View* header_content_separator_container_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequestSheetController);
 };
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index 2065ce9..5edfc7c6 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -229,10 +229,10 @@
         static_cast<int>(PaymentRequestCommonTags::BACK_BUTTON_TAG));
     back_arrow->SetID(static_cast<int>(DialogViewID::BACK_BUTTON));
     back_arrow->SetAccessibleName(l10n_util::GetStringUTF16(IDS_PAYMENTS_BACK));
-    layout->AddView(back_arrow.release());
+    layout->AddView(std::move(back_arrow));
   }
 
-  layout->AddView(header_content_view.release());
+  layout->AddView(std::move(header_content_view));
 }
 
 std::unique_ptr<views::ImageView> CreateInstrumentIconView(
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 519e860..ea905e9 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -185,23 +185,23 @@
   std::unique_ptr<views::Label> name_label = CreateMediumLabel(section_name);
   name_label->SetMultiLine(true);
   name_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  layout->AddView(name_label.release());
+  layout->AddView(std::move(name_label));
 
   if (content_view) {
     content_view->set_can_process_events_within_subtree(false);
-    layout->AddView(content_view.release());
+    layout->AddView(std::move(content_view));
   } else {
     layout->SkipColumns(1);
   }
 
   if (extra_content_view) {
     extra_content_view->set_can_process_events_within_subtree(false);
-    layout->AddView(extra_content_view.release());
+    layout->AddView(std::move(extra_content_view));
   } else {
     layout->SkipColumns(1);
   }
 
-  layout->AddView(trailing_button.release());
+  layout->AddView(std::move(trailing_button));
 
   row->SetAccessibleName(
       l10n_util::GetStringFUTF16(IDS_PAYMENTS_ROW_ACCESSIBLE_NAME_FORMAT,
@@ -243,8 +243,8 @@
   amount_label->SetAllowCharacterBreak(true);
 
   item_amount_layout->StartRow(views::GridLayout::kFixedSize, 0);
-  item_amount_layout->AddView(currency_label.release());
-  item_amount_layout->AddView(amount_label.release());
+  item_amount_layout->AddView(std::move(currency_label));
+  item_amount_layout->AddView(std::move(amount_label));
 
   return item_amount_line;
 }
@@ -428,7 +428,7 @@
     std::unique_ptr<views::View> warning_view =
         CreateWarningView(spec()->retry_error_message(), true /* show_icon */);
     layout->StartRow(views::GridLayout::kFixedSize, 0);
-    layout->AddView(warning_view.release());
+    layout->AddView(std::move(warning_view));
   }
 
   // The shipping address and contact info rows are optional.
@@ -436,14 +436,14 @@
       CreatePaymentSheetSummaryRow();
   PaymentRequestRowView* previous_row = summary_row.get();
   layout->StartRow(views::GridLayout::kFixedSize, 0);
-  layout->AddView(summary_row.release());
+  layout->AddView(std::move(summary_row));
 
   if (spec()->request_shipping()) {
     std::unique_ptr<PaymentRequestRowView> shipping_row = CreateShippingRow();
     shipping_row->set_previous_row(previous_row->AsWeakPtr());
     previous_row = shipping_row.get();
     layout->StartRow(views::GridLayout::kFixedSize, 0);
-    layout->AddView(shipping_row.release());
+    layout->AddView(std::move(shipping_row));
     // It's possible for requestShipping to be true and for there to be no
     // shipping options yet (they will come in updateWith).
     // TODO(crbug.com/707353): Put a better placeholder row, instead of no row.
@@ -453,7 +453,7 @@
       shipping_option_row->set_previous_row(previous_row->AsWeakPtr());
       previous_row = shipping_option_row.get();
       layout->StartRow(views::GridLayout::kFixedSize, 0);
-      layout->AddView(shipping_option_row.release());
+      layout->AddView(std::move(shipping_option_row));
     }
   }
   std::unique_ptr<PaymentRequestRowView> payment_method_row =
@@ -461,7 +461,7 @@
   payment_method_row->set_previous_row(previous_row->AsWeakPtr());
   previous_row = payment_method_row.get();
   layout->StartRow(views::GridLayout::kFixedSize, 0);
-  layout->AddView(payment_method_row.release());
+  layout->AddView(std::move(payment_method_row));
   if (spec()->request_payer_name() || spec()->request_payer_email() ||
       spec()->request_payer_phone()) {
     std::unique_ptr<PaymentRequestRowView> contact_info_row =
@@ -469,10 +469,10 @@
     contact_info_row->set_previous_row(previous_row->AsWeakPtr());
     previous_row = contact_info_row.get();
     layout->StartRow(views::GridLayout::kFixedSize, 0);
-    layout->AddView(contact_info_row.release());
+    layout->AddView(std::move(contact_info_row));
   }
   layout->StartRow(views::GridLayout::kFixedSize, 0);
-  layout->AddView(CreateDataSourceRow().release());
+  layout->AddView(CreateDataSourceRow());
 }
 
 // Adds the product logo to the footer.
@@ -618,17 +618,13 @@
     std::unique_ptr<views::Label> summary =
         std::make_unique<views::Label>(base::UTF8ToUTF16((*items[i])->label));
     summary->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    layout->AddView(summary.release());
+    layout->AddView(std::move(summary));
 
-    layout->AddView(
-        CreateInlineCurrencyAmountItem(
-            is_mixed_currency
-                ? base::UTF8ToUTF16(
-                      spec()->GetFormattedCurrencyCode((*items[i])->amount))
-                : base::string16(),
-            spec()->GetFormattedCurrencyAmount((*items[i])->amount), true,
-            false)
-            .release());
+    layout->AddView(CreateInlineCurrencyAmountItem(
+        is_mixed_currency ? base::UTF8ToUTF16(spec()->GetFormattedCurrencyCode(
+                                (*items[i])->amount))
+                          : base::string16(),
+        spec()->GetFormattedCurrencyAmount((*items[i])->amount), true, false));
   }
 
   size_t hidden_item_count = items.size() - displayed_items;
@@ -637,12 +633,12 @@
     std::unique_ptr<views::Label> label =
         CreateHintLabel(l10n_util::GetPluralStringFUTF16(
             IDS_PAYMENT_REQUEST_ORDER_SUMMARY_MORE_ITEMS, hidden_item_count));
-    layout->AddView(label.release());
+    layout->AddView(std::move(label));
     if (is_mixed_currency) {
       std::unique_ptr<views::Label> multiple_currency_label =
           CreateHintLabel(l10n_util::GetStringUTF16(
               IDS_PAYMENT_REQUEST_ORDER_SUMMARY_MULTIPLE_CURRENCY_INDICATOR));
-      layout->AddView(multiple_currency_label.release());
+      layout->AddView(std::move(multiple_currency_label));
     }
   }
 
@@ -651,7 +647,7 @@
   const mojom::PaymentItemPtr& total = spec()->GetTotal(selected_instrument);
   base::string16 total_label_text = base::UTF8ToUTF16(total->label);
   std::unique_ptr<views::Label> total_label = CreateBoldLabel(total_label_text);
-  layout->AddView(total_label.release());
+  layout->AddView(std::move(total_label));
 
   base::string16 total_currency_code =
       base::UTF8ToUTF16(spec()->GetFormattedCurrencyCode(
@@ -659,8 +655,7 @@
   base::string16 total_amount = spec()->GetFormattedCurrencyAmount(
       spec()->GetTotal(state()->selected_instrument())->amount);
   layout->AddView(CreateInlineCurrencyAmountItem(total_currency_code,
-                                                 total_amount, false, true)
-                      .release());
+                                                 total_amount, false, true));
 
   PaymentSheetRowBuilder builder(
       this, l10n_util::GetStringUTF16(IDS_PAYMENTS_ORDER_SUMMARY_LABEL));
@@ -770,13 +765,13 @@
     std::unique_ptr<views::Label> selected_instrument_label =
         std::make_unique<views::Label>(selected_instrument->GetLabel());
     selected_instrument_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    layout->AddView(selected_instrument_label.release());
+    layout->AddView(std::move(selected_instrument_label));
 
     layout->StartRow(views::GridLayout::kFixedSize, 0);
     std::unique_ptr<views::Label> selected_instrument_sublabel =
         std::make_unique<views::Label>(selected_instrument->GetSublabel());
     selected_instrument_sublabel->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    layout->AddView(selected_instrument_sublabel.release());
+    layout->AddView(std::move(selected_instrument_sublabel));
 
     std::unique_ptr<views::ImageView> icon_view =
         CreateInstrumentIconView(selected_instrument->icon_resource_id(),
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
index c73ba58..fd05699 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -371,7 +371,7 @@
   ASSERT_NE(nullptr, owning_window);
 
   // Setup tablet mode.
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   // Open the file dialog on the default path.
   ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE,
@@ -458,7 +458,7 @@
   ASSERT_NE(nullptr, owning_window);
 
   // Setup tablet mode.
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   // Enable the virtual keyboard.
   ash::ShellTestApi().EnableVirtualKeyboard();
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index a306da76..d8de5239 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1747,7 +1747,7 @@
   // bounds are different from the maximized bound's origin.
   browser()->window()->SetBounds(browser()->window()->GetBounds() +
                                  gfx::Vector2d(100, 50));
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   DragWindowAndVerifyOffset(this, GetTabStripForBrowser(browser()), 1);
   ASSERT_FALSE(TabDragController::IsActive());
@@ -1755,7 +1755,7 @@
 
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        OffsetForDraggingRightSnappedWindowInTabletMode) {
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   // Right snap the browser window.
   aura::Window* window = browser()->window()->GetNativeWindow();
@@ -2196,7 +2196,7 @@
   TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
   EXPECT_EQ(2u, browser_list->size());
 
-  ash::ShellTestApi().EnableTabletModeWindowManager(true);
+  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
 
   // Move to the first tab of |browser2| and drag it toward to browser(). Note
   // dragging on |browser2| which only has one tab in tablet mode will open
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index a4cefe4..e56e5ff1 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1321,7 +1321,7 @@
       // When tabs are wide enough, selecting a new tab cannot change the
       // ideal bounds, so only a repaint is necessary.
       SchedulePaint();
-    } else if (IsAnimating()) {
+    } else if (bounds_animator_.IsAnimating()) {
       // The selection change will have modified the ideal bounds of the tabs
       // in |selected_tabs_| and |new_selection|.  We need to recompute.
       // Note: This is safe even if we're in the midst of mouse-based tab
@@ -1330,7 +1330,7 @@
       // |available_width_for_tabs_| already.
       UpdateIdealBounds();
       AnimateToIdealBounds();
-    } else {
+    } else if (!animator_->IsAnimating()) {
       // As in the animating case above, the selection change will have
       // affected the desired bounds of the tabs, but since we're not animating
       // we can just snap to the new bounds.
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 61d1075..7b8f140 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -119,7 +119,7 @@
 #include "chromeos/constants/chromeos_pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/services/multidevice_setup/public/cpp/prefs.h"
-#include "chromeos/services/network_config/public/mojom/constants.mojom.h"
+#include "chromeos/services/network_config/public/mojom/constants.mojom.h"  // nogncheck
 #include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
 #include "services/service_manager/public/cpp/connector.h"
diff --git a/chrome/browser/ui/webui/settings/settings_ui.h b/chrome/browser/ui/webui/settings/settings_ui.h
index 45703738..16d535fe 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.h
+++ b/chrome/browser/ui/webui/settings/settings_ui.h
@@ -10,7 +10,7 @@
 #include "chrome/browser/ui/webui/webui_load_timer.h"
 
 #if defined(OS_CHROMEOS)
-#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
+#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"  // nogncheck
 #include "ui/webui/mojo_web_ui_controller.h"
 #else
 #include "content/public/browser/web_ui_controller.h"
diff --git a/chrome/browser/usb/web_usb_detector_unittest.cc b/chrome/browser/usb/web_usb_detector_unittest.cc
index 909b655..cbfb280 100644
--- a/chrome/browser/usb/web_usb_detector_unittest.cc
+++ b/chrome/browser/usb/web_usb_detector_unittest.cc
@@ -21,7 +21,6 @@
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "net/base/network_change_notifier.h"
 #include "services/device/public/cpp/test/fake_usb_device_info.h"
 #include "services/device/public/cpp/test/fake_usb_device_manager.h"
 #include "services/device/public/mojom/usb_device.mojom.h"
@@ -62,14 +61,6 @@
   }
 
   void SetUp() override {
-    // Avoid the leaky NetworkChangeNotifier created during the initialization
-    // of the global leaky singleton NetworkService which affects subsequent
-    // unit tests.
-    // See https://bugs.chromium.org/p/chromium/issues/detail?id=867414
-    // and
-    // https://groups.google.com/a/chromium.org/forum/#!msg/network-service-dev/IgNFrq1zFHI/FNCAplsCCQAJ
-    network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
-
     BrowserWithTestWindowTest::SetUp();
 #if defined(OS_CHROMEOS)
     profile_manager()->SetLoggedIn(true);
@@ -102,7 +93,6 @@
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
 
  private:
-  std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
   DISALLOW_COPY_AND_ASSIGN(WebUsbDetectorTest);
 };
 
diff --git a/chrome/installer/mac/signing/signing.py b/chrome/installer/mac/signing/signing.py
index ddd5aee..5e684384 100644
--- a/chrome/installer/mac/signing/signing.py
+++ b/chrome/installer/mac/signing/signing.py
@@ -75,6 +75,20 @@
                 '{}.helper'.format(uncustomized_bundle_id),
                 options=CodeSignOptions.RESTRICT,
                 verify_options=VerifyOptions.DEEP),
+        'helper-renderer-app':
+            CodeSignedProduct(
+                '{0.framework_dir}/Helpers/{0.product} Helper (Renderer).app'
+                .format(config),
+                '{}.helper.renderer'.format(uncustomized_bundle_id),
+                options=CodeSignOptions.RESTRICT,
+                verify_options=VerifyOptions.DEEP),
+        'helper-plugin-app':
+            CodeSignedProduct(
+                '{0.framework_dir}/Helpers/{0.product} Helper (Plugin).app'
+                .format(config),
+                '{}.helper.plugin'.format(uncustomized_bundle_id),
+                options=CodeSignOptions.RESTRICT,
+                verify_options=VerifyOptions.DEEP),
         'app-mode-app':
             CodeSignedProduct(
                 '{.framework_dir}/Helpers/app_mode_loader'.format(config),
diff --git a/chrome/installer/mac/signing/signing_test.py b/chrome/installer/mac/signing/signing_test.py
index 4f1f8055..e4ffabd 100644
--- a/chrome/installer/mac/signing/signing_test.py
+++ b/chrome/installer/mac/signing/signing_test.py
@@ -66,6 +66,12 @@
             set(model.CodeSignOptions.RESTRICT),
             set(parts['helper-app'].options))
         self.assertEqual(
+            set(model.CodeSignOptions.RESTRICT),
+            set(parts['helper-renderer-app'].options))
+        self.assertEqual(
+            set(model.CodeSignOptions.RESTRICT),
+            set(parts['helper-plugin-app'].options))
+        self.assertEqual(
             set(model.CodeSignOptions.RESTRICT +
                 model.CodeSignOptions.LIBRARY_VALIDATION),
             set(parts['crashpad'].options))
diff --git a/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc b/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
index e972ec8a..25526bb 100644
--- a/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
+++ b/chrome/renderer/subresource_redirect/subresource_redirect_url_loader_throttle.cc
@@ -69,7 +69,8 @@
       "SubresourceRedirect.DidCompress.CompressionPercent",
       static_cast<int>(100 - ((content_length / ofcl) * 100)));
 
-  // TODO(harrisonsean): Add bytes saved histogram.
+  UMA_HISTOGRAM_COUNTS_1M("SubresourceRedirect.DidCompress.BytesSaved",
+                          static_cast<int>(ofcl - content_length));
 }
 
 void SubresourceRedirectURLLoaderThrottle::DetachFromCurrentSequence() {}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c6db6b64..02e87121 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3304,6 +3304,7 @@
     "//components/strings",
     "//components/subresource_filter/core/browser:test_support",
     "//components/sync:test_support",
+    "//components/sync_device_info:test_support",
     "//components/sync_sessions:test_support",
     "//components/sync_user_events:test_support",
     "//components/ukm/content",
diff --git a/chrome/test/android/chrome_public_test_support/AndroidManifest.xml b/chrome/test/android/chrome_public_test_support/AndroidManifest.xml
index bac5256..6f801d2 100644
--- a/chrome/test/android/chrome_public_test_support/AndroidManifest.xml
+++ b/chrome/test/android/chrome_public_test_support/AndroidManifest.xml
@@ -5,7 +5,6 @@
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:tools="http://schemas.android.com/tools"
       package="org.chromium.chrome.tests.support">
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="22" />
     <uses-permission android:name="android.permission.INTERNET" />
     <application>
         <service android:name="org.chromium.chrome.browser.media.TestMediaRouteProviderService"
diff --git a/chrome/test/android/chrome_public_test_support/BUILD.gn b/chrome/test/android/chrome_public_test_support/BUILD.gn
index f278f73..e8cbd03e 100644
--- a/chrome/test/android/chrome_public_test_support/BUILD.gn
+++ b/chrome/test/android/chrome_public_test_support/BUILD.gn
@@ -20,4 +20,5 @@
 
   apk_name = "ChromePublicTestSupport"
   android_manifest = "AndroidManifest.xml"
+  target_sdk_version = 22
 }
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index 6196b16b..7f730c3 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -32,8 +32,8 @@
 #include "third_party/webdriver/atoms.h"
 
 const int kFlickTouchEventsPerSecond = 30;
-const std::set<std::string> textControlTypes = {"text", "search", "tel",
-                                                "url",  "email",  "password"};
+const std::set<std::string> textControlTypes = {"text", "search", "tel", "url",
+                                                "password"};
 
 namespace {
 
@@ -92,8 +92,8 @@
   Status status = FocusToElement(session, web_view, element_id);
   if (status.IsError())
         return Status(kElementNotInteractable);
-  // Move cursor/caret to append the input keys if element's type is
-  // text-related
+  // Move cursor/caret to append the input
+  // keys if element's type is text-related
   if (is_text) {
     base::ListValue args;
     args.Append(CreateElement(element_id));
@@ -441,6 +441,46 @@
     return web_view->SetFileInputFiles(session->GetCurrentFrameId(), *element,
                                        paths, multiple);
   } else {
+    std::unique_ptr<base::Value> get_content_editable;
+    base::ListValue args;
+    args.Append(CreateElement(element_id));
+    status = web_view->CallFunction(session->GetCurrentFrameId(),
+                                    "element => element.isContentEditable",
+                                    args, &get_content_editable);
+    if (status.IsError())
+      return status;
+    bool is_content_editable;
+    if (get_content_editable->GetAsBoolean(&is_content_editable) &&
+        is_content_editable) {
+      // If element is contentEditable, will move caret
+      // at end of element text. W3C mandates that the
+      // caret be moved "after any child content"
+      std::unique_ptr<base::Value> result;
+      status = web_view->CallFunction(
+          session->GetCurrentFrameId(),
+          "function(element) {"
+          "var range = document.createRange();"
+          "range.selectNodeContents(element);"
+          "range.collapse();"
+          "var sel = window.getSelection();"
+          "sel.removeAllRanges();"
+          "sel.addRange(range);"
+          "while (element.parentElement.isContentEditable) {"
+          "    element = element.parentElement;"
+          "  }"
+          "return element;"
+          "}",
+          args, &result);
+      if (status.IsError())
+        return status;
+      const base::DictionaryValue* element_dict;
+      std::string target_element_id;
+      if (!result->GetAsDictionary(&element_dict) ||
+          !element_dict->GetString(GetElementKey(), &target_element_id))
+        return Status(kUnknownError, "no element reference returned by script");
+      return SendKeysToElement(session, web_view, target_element_id, false,
+                               key_list);
+    }
     // If element_type is in textControlTypes, sendKeys should append
     bool is_text = is_input && textControlTypes.find(element_type) !=
                                    textControlTypes.end();
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 7692a95..59541f3 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1965,16 +1965,44 @@
   def testSendKeysToElementAppend(self):
       self._driver.Load(self.GetHttpUrlForFile(
           '/chromedriver/empty.html'))
+      textControlTypes = ["text", "search", "tel", "url",  "password"]
+      for textType in textControlTypes:
+          element = self._driver.ExecuteScript(
+              'document.body.innerHTML = '
+              '\'<input type="{}" value="send_this_value">\';'
+              'var input = document.getElementsByTagName("input")[0];'
+              'input.focus();'
+              'input.setSelectionRange(0,0);'
+              'return input;'.format(textType))
+          element.SendKeys('hello')
+          value = self._driver.ExecuteScript('return arguments[0].value;',
+                                             element)
+          self.assertEquals('send_this_valuehello', value)
+
+  def testSendKeysToEditableElement(self):
+      self._driver.Load(self.GetHttpUrlForFile(
+          '/chromedriver/empty.html'))
       element = self._driver.ExecuteScript(
           'document.body.innerHTML = '
-          '\'<input type="text" value="send_this_value">\';'
-          'var input = document.getElementsByTagName("input")[0];'
+          '\'<p contentEditable="true"> <i>hello-></i> '
+          '<b>send_this_value </b> </p>\';'
+          'var input = document.getElementsByTagName("i")[0];'
           'input.focus();'
-          'input.setSelectionRange(0,0);'
           'return input;')
       element.SendKeys('hello')
-      value = self._driver.ExecuteScript('return arguments[0].value;', element)
-      self.assertEquals('send_this_valuehello', value)
+      self.assertEquals(u'hello->hello', element.GetText())
+
+      self._driver.Load(self.GetHttpUrlForFile(
+          '/chromedriver/empty.html'))
+      element = self._driver.ExecuteScript(
+          'document.body.innerHTML = '
+          '\'<p contentEditable="true"> <i>hello</i> '
+          '<b>-></b> </p>\';'
+          'var input = document.getElementsByTagName("p")[0];'
+          'input.focus();'
+          'return input;')
+      element.SendKeys('hello')
+      self.assertEquals(u'hello ->hello', element.GetText())
 
   def testUnexpectedAlertOpenExceptionMessage(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
diff --git a/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml b/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml
index 32070d0c..181b43ac 100644
--- a/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml
+++ b/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml
@@ -9,7 +9,6 @@
     package="org.chromium.chromedriver_webview_shell" android:versionCode="1"
     android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
diff --git a/chrome/test/data/webui/chromeos/fake_network_config_mojom.js b/chrome/test/data/webui/chromeos/fake_network_config_mojom.js
index 13cfbde..a71ab23 100644
--- a/chrome/test/data/webui/chromeos/fake_network_config_mojom.js
+++ b/chrome/test/data/webui/chromeos/fake_network_config_mojom.js
@@ -14,6 +14,28 @@
   /** @param {!NetworkingPrivate} extensionApi */
   constructor(extensionApi) {
     this.extensionApi_ = extensionApi;
+
+    this.observers_ = [];
+    extensionApi.onNetworkListChanged.addListener(
+        this.onNetworkListChanged.bind(this));
+    extensionApi.onDeviceStateListChanged.addListener(
+        this.onDeviceStateListChanged.bind(this));
+  }
+
+  onNetworkListChanged(networks) {
+    this.observers_.forEach(o => o.onNetworkStateListChanged());
+  }
+
+  onDeviceStateListChanged() {
+    this.observers_.forEach(o => o.onDeviceStateListChanged());
+  }
+
+  /**
+   * @param { !chromeos.networkConfig.mojom.CrosNetworkConfigObserverProxy }
+   *     observer
+   */
+  addObserver(observer) {
+    this.observers_.push(observer);
   }
 
   /**
diff --git a/chrome/test/data/webui/print_preview/header_new_test.js b/chrome/test/data/webui/print_preview/header_new_test.js
index 71c9e5a..20424d2e 100644
--- a/chrome/test/data/webui/print_preview/header_new_test.js
+++ b/chrome/test/data/webui/print_preview/header_new_test.js
@@ -64,6 +64,10 @@
       assertEquals('3 pages', summary.textContent.trim());
       header.setSetting('pages', [1]);
       assertEquals('1 page', summary.textContent.trim());
+      // Verify the chrome://print case of a zero length document does not show
+      // the summary.
+      header.setSetting('pages', []);
+      assertEquals('', summary.textContent);
     });
 
     // Tests that the message is correctly adjusted with a duplex printer.
diff --git a/chrome/test/data/webui/print_preview/header_test.js b/chrome/test/data/webui/print_preview/header_test.js
index 15d818b..200afc7 100644
--- a/chrome/test/data/webui/print_preview/header_test.js
+++ b/chrome/test/data/webui/print_preview/header_test.js
@@ -65,6 +65,10 @@
       assertEquals('Total: 3 pages', summary.textContent);
       header.setSetting('pages', [1]);
       assertEquals('Total: 1 page', summary.textContent);
+      // Verify the chrome://print case of a zero length document does not show
+      // the summary.
+      header.setSetting('pages', []);
+      assertEquals('', summary.textContent);
     });
 
     // Tests that the message is correctly adjusted with a duplex printer.
diff --git a/chrome/test/data/webui/settings/internet_page_tests.js b/chrome/test/data/webui/settings/internet_page_tests.js
index 760c68f..8d5d433 100644
--- a/chrome/test/data/webui/settings/internet_page_tests.js
+++ b/chrome/test/data/webui/settings/internet_page_tests.js
@@ -56,9 +56,8 @@
 
   function flushAsync() {
     Polymer.dom.flush();
-    return new Promise(resolve => {
-      internetPage.async(resolve);
-    });
+    // Use setTimeout to wait for the next macrotask.
+    return new Promise(resolve => setTimeout(resolve));
   }
 
   function setNetworksForTest(networks) {
@@ -88,6 +87,14 @@
   });
 
   teardown(function() {
+    const subPage = internetPage.$$('settings-internet-subpage');
+    if (subPage) {
+      subPage.remove();
+    }
+    const detailPage = internetPage.$$('settings-internet-detail-page');
+    if (detailPage) {
+      detailPage.remove();
+    }
     internetPage.remove();
     internetPage = null;
     // Navigating to the details page changes the Route state.
@@ -112,32 +119,35 @@
         {GUID: 'wifi12_guid', Name: 'wifi2', Type: 'WiFi'},
       ]);
       api_.enableNetworkType('WiFi');
-      Polymer.dom.flush();
-      const wifi = networkSummary_.$$('#WiFi');
-      assertTrue(!!wifi);
-      assertEquals(2, wifi.networkStateList.length);
+      return flushAsync().then(() => {
+        const wifi = networkSummary_.$$('#WiFi');
+        assertTrue(!!wifi);
+        assertEquals(2, wifi.networkStateList.length);
+      });
     });
 
     test('WiFiToggle', function() {
       // Make WiFi an available but disabled technology.
       api_.disableNetworkType('WiFi');
-      Polymer.dom.flush();
-      const wifi = networkSummary_.$$('#WiFi');
-      assertTrue(!!wifi);
+      return flushAsync().then(() => {
+        const wifi = networkSummary_.$$('#WiFi');
+        assertTrue(!!wifi);
 
-      // Ensure that the initial state is disabled and the toggle is
-      // enabled but unchecked.
-      assertEquals('Disabled', api_.getDeviceStateForTest('WiFi').State);
-      const toggle = wifi.$$('#deviceEnabledButton');
-      assertTrue(!!toggle);
-      assertFalse(toggle.disabled);
-      assertFalse(toggle.checked);
+        // Ensure that the initial state is disabled and the toggle is
+        // enabled but unchecked.
+        assertEquals('Disabled', api_.getDeviceStateForTest('WiFi').State);
+        const toggle = wifi.$$('#deviceEnabledButton');
+        assertTrue(!!toggle);
+        assertFalse(toggle.disabled);
+        assertFalse(toggle.checked);
 
-      // Tap the enable toggle button and ensure the state becomes enabled.
-      toggle.click();
-      Polymer.dom.flush();
-      assertTrue(toggle.checked);
-      assertEquals('Enabled', api_.getDeviceStateForTest('WiFi').State);
+        // Tap the enable toggle button and ensure the state becomes enabled.
+        toggle.click();
+        return flushAsync().then(() => {
+          assertTrue(toggle.checked);
+          assertEquals('Enabled', api_.getDeviceStateForTest('WiFi').State);
+        });
+      });
     });
   });
 
@@ -148,20 +158,21 @@
         {GUID: 'wifi12_guid', Name: 'wifi2', Type: 'WiFi'},
       ]);
       api_.enableNetworkType('WiFi');
-      Polymer.dom.flush();
-      const wifi = networkSummary_.$$('#WiFi');
-      assertTrue(!!wifi);
-      wifi.$$('.subpage-arrow').click();
       return flushAsync().then(() => {
-        const subpage = internetPage.$$('settings-internet-subpage');
-        assertTrue(!!subpage);
-        assertEquals(2, subpage.networkStateList_.length);
-        const toggle = wifi.$$('#deviceEnabledButton');
-        assertTrue(!!toggle);
-        assertFalse(toggle.disabled);
-        const networkList = subpage.$$('#networkList');
-        assertTrue(!!networkList);
-        assertEquals(2, networkList.networks.length);
+        const wifi = networkSummary_.$$('#WiFi');
+        assertTrue(!!wifi);
+        wifi.$$('.subpage-arrow').click();
+        return flushAsync().then(() => {
+          const subpage = internetPage.$$('settings-internet-subpage');
+          assertTrue(!!subpage);
+          assertEquals(2, subpage.networkStateList_.length);
+          const toggle = wifi.$$('#deviceEnabledButton');
+          assertTrue(!!toggle);
+          assertFalse(toggle.disabled);
+          const networkList = subpage.$$('#networkList');
+          assertTrue(!!networkList);
+          assertEquals(2, networkList.networks.length);
+        });
       });
     });
 
@@ -170,25 +181,15 @@
         {GUID: 'cellular1_guid', Name: 'cellular1', Type: 'Cellular'},
       ]);
       api_.enableNetworkType('Cellular');
-      return flushAsync()
-          .then(() => {
-            return Promise.all([
-              api_.whenCalled('getNetworks'),
-              api_.whenCalled('getDeviceStates'),
-            ]);
-          })
-          .then(() => {
-            const mobile = networkSummary_.$$('#Cellular');
-            assertTrue(!!mobile);
-            mobile.$$('.subpage-arrow').click();
-            return Promise.all([
-              api_.whenCalled('getManagedProperties'),
-            ]);
-          })
-          .then(() => {
-            const detailPage = internetPage.$$('settings-internet-detail-page');
-            assertTrue(!!detailPage);
-          });
+      return flushAsync().then(() => {
+        const mobile = networkSummary_.$$('#Cellular');
+        assertTrue(!!mobile);
+        mobile.$$('.subpage-arrow').click();
+        return flushAsync().then(() => {
+          const detailPage = internetPage.$$('settings-internet-detail-page');
+          assertTrue(!!detailPage);
+        });
+      });
     });
 
     test('Tether', function() {
@@ -201,20 +202,21 @@
         const mobile = networkSummary_.$$('#Tether');
         assertTrue(!!mobile);
         mobile.$$('.subpage-arrow').click();
-        Polymer.dom.flush();
-        const subpage = internetPage.$$('settings-internet-subpage');
-        assertTrue(!!subpage);
-        assertEquals(2, subpage.networkStateList_.length);
-        const toggle = mobile.$$('#deviceEnabledButton');
-        assertTrue(!!toggle);
-        assertFalse(toggle.disabled);
-        const networkList = subpage.$$('#networkList');
-        assertTrue(!!networkList);
-        assertEquals(2, networkList.networks.length);
-        const tetherToggle = mobile.$$('#tetherEnabledButton');
-        // No separate tether toggle when Celular is not available; the
-        // primary toggle enables or disables Tether in that case.
-        assertFalse(!!tetherToggle);
+        return flushAsync().then(() => {
+          const subpage = internetPage.$$('settings-internet-subpage');
+          assertTrue(!!subpage);
+          assertEquals(2, subpage.networkStateList_.length);
+          const toggle = mobile.$$('#deviceEnabledButton');
+          assertTrue(!!toggle);
+          assertFalse(toggle.disabled);
+          const networkList = subpage.$$('#networkList');
+          assertTrue(!!networkList);
+          assertEquals(2, networkList.networks.length);
+          const tetherToggle = mobile.$$('#tetherEnabledButton');
+          // No separate tether toggle when Celular is not available; the
+          // primary toggle enables or disables Tether in that case.
+          assertFalse(!!tetherToggle);
+        });
       });
     });
 
@@ -229,20 +231,22 @@
       return flushAsync().then(() => {
         const mobile = networkSummary_.$$('#Cellular');
         assertTrue(!!mobile);
+        assertTrue(!!mobile.$$('.subpage-arrow'));
         mobile.$$('.subpage-arrow').click();
-        Polymer.dom.flush();
-        const subpage = internetPage.$$('settings-internet-subpage');
-        assertTrue(!!subpage);
-        assertEquals(3, subpage.networkStateList_.length);
-        const toggle = mobile.$$('#deviceEnabledButton');
-        assertTrue(!!toggle);
-        assertFalse(toggle.disabled);
-        const networkList = subpage.$$('#networkList');
-        assertTrue(!!networkList);
-        assertEquals(3, networkList.networks.length);
-        const tetherToggle = subpage.$$('#tetherEnabledButton');
-        assertTrue(!!tetherToggle);
-        assertFalse(tetherToggle.disabled);
+        return flushAsync().then(() => {
+          const subpage = internetPage.$$('settings-internet-subpage');
+          assertTrue(!!subpage);
+          assertEquals(3, subpage.networkStateList_.length);
+          const toggle = mobile.$$('#deviceEnabledButton');
+          assertTrue(!!toggle);
+          assertFalse(toggle.disabled);
+          const networkList = subpage.$$('#networkList');
+          assertTrue(!!networkList);
+          assertEquals(3, networkList.networks.length);
+          const tetherToggle = subpage.$$('#tetherEnabledButton');
+          assertTrue(!!tetherToggle);
+          assertFalse(tetherToggle.disabled);
+        });
       });
     });
 
@@ -283,15 +287,16 @@
         const vpn = networkSummary_.$$('#VPN');
         assertTrue(!!vpn);
         vpn.$$('.subpage-arrow').click();
-        Polymer.dom.flush();
-        const subpage = internetPage.$$('settings-internet-subpage');
-        assertTrue(!!subpage);
-        assertEquals(2, subpage.networkStateList_.length);
-        const networkList = subpage.$$('#networkList');
-        assertTrue(!!networkList);
-        assertEquals(2, networkList.networks.length);
-        // TODO(stevenjb): Implement fake management API and test third
-        // party provider sections.
+        return flushAsync().then(() => {
+          const subpage = internetPage.$$('settings-internet-subpage');
+          assertTrue(!!subpage);
+          assertEquals(2, subpage.networkStateList_.length);
+          const networkList = subpage.$$('#networkList');
+          assertTrue(!!networkList);
+          assertEquals(2, networkList.networks.length);
+          // TODO(stevenjb): Implement fake management API and test third
+          // party provider sections.
+        });
       });
     });
 
@@ -315,14 +320,16 @@
         assertTrue(!!expandAddConnections);
         assertTrue(!expandAddConnections.expanded);
         internetPage.addConnectionExpanded_ = true;
-        Polymer.dom.flush();
-        const addArcVpn = internetPage.$$('#addArcVpn');
-        assertTrue(!!addArcVpn);
-        addArcVpn.click();
-        Polymer.dom.flush();
-        const subpage = internetPage.$$('settings-internet-subpage');
-        assertTrue(!!subpage);
-        assertEquals(2, subpage.arcVpnProviders.length);
+        return flushAsync().then(() => {
+          const addArcVpn = internetPage.$$('#addArcVpn');
+          assertTrue(!!addArcVpn);
+          addArcVpn.click();
+          return flushAsync().then(() => {
+            const subpage = internetPage.$$('settings-internet-subpage');
+            assertTrue(!!subpage);
+            assertEquals(2, subpage.arcVpnProviders.length);
+          });
+        });
       });
     });
 
@@ -331,38 +338,24 @@
         {GUID: 'wifi1_guid', Name: 'wifi1', Type: 'WiFi'},
       ]);
       api_.enableNetworkType('WiFi');
-      return flushAsync()
-          .then(() => {
-            const wifi = networkSummary_.$$('#WiFi');
-            assertTrue(!!wifi);
-            wifi.$$('.subpage-arrow').click();
-            return flushAsync();
-          })
-          .then(() => {
-            // Call setTimeout to populate iron-list.
-            return new Promise((resolve) => {
-              setTimeout(function() {
-                Polymer.dom.flush();
-                resolve();
-              });
-            });
-          })
-          .then(() => {
-            const subpage = internetPage.$$('settings-internet-subpage');
-            assertTrue(!!subpage);
-            const networkList = subpage.$$('#networkList');
-            assertTrue(!!networkList);
-            assertEquals(1, networkList.networks.length);
-            assertEquals(1, networkList.listItems_.length);
-            const ironList = networkList.$$('iron-list');
-            assertTrue(!!ironList);
-            assertEquals(1, ironList.items.length);
-            const networkListItem = networkList.$$('cr-network-list-item');
-            assertTrue(!!networkListItem);
-            networkListItem.click();
-            return flushAsync();
-          })
-          .then(() => {
+      return flushAsync().then(() => {
+        const wifi = networkSummary_.$$('#WiFi');
+        assertTrue(!!wifi);
+        wifi.$$('.subpage-arrow').click();
+        return flushAsync().then(() => {
+          const subpage = internetPage.$$('settings-internet-subpage');
+          assertTrue(!!subpage);
+          const networkList = subpage.$$('#networkList');
+          assertTrue(!!networkList);
+          assertEquals(1, networkList.networks.length);
+          assertEquals(1, networkList.listItems_.length);
+          const ironList = networkList.$$('iron-list');
+          assertTrue(!!ironList);
+          assertEquals(1, ironList.items.length);
+          const networkListItem = networkList.$$('cr-network-list-item');
+          assertTrue(!!networkListItem);
+          networkListItem.click();
+          return flushAsync().then(() => {
             const detailPage = internetPage.$$('settings-internet-detail-page');
             assertTrue(!!detailPage);
             assertEquals('wifi1_guid', detailPage.guid);
@@ -370,6 +363,8 @@
               api_.whenCalled('getManagedProperties'),
             ]);
           });
+        });
+      });
     });
   });
 });
diff --git a/chromecast/browser/android/BUILD.gn b/chromecast/browser/android/BUILD.gn
index 2735d250f..2f2ddc3 100644
--- a/chromecast/browser/android/BUILD.gn
+++ b/chromecast/browser/android/BUILD.gn
@@ -126,6 +126,7 @@
   ]
 
   android_manifest_for_lint = cast_shell_android_manifest
+  min_sdk_version = 21
 
   srcjar_deps = [
     ":cast_shell_build_config_gen",
diff --git a/chromecast/browser/android/apk/AndroidManifest.xml.jinja2 b/chromecast/browser/android/apk/AndroidManifest.xml.jinja2
index 3b4a1d5..c857253 100644
--- a/chromecast/browser/android/apk/AndroidManifest.xml.jinja2
+++ b/chromecast/browser/android/apk/AndroidManifest.xml.jinja2
@@ -8,8 +8,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="org.chromium.chromecast.shell">
 
-    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="22" />
-
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
diff --git a/chromecast/media/cma/backend/audio_output_redirector.cc b/chromecast/media/cma/backend/audio_output_redirector.cc
index 85ab26f..3e91635 100644
--- a/chromecast/media/cma/backend/audio_output_redirector.cc
+++ b/chromecast/media/cma/backend/audio_output_redirector.cc
@@ -117,6 +117,8 @@
 
 void AudioOutputRedirector::AddInput(MixerInput* mixer_input) {
   if (ApplyToInput(mixer_input)) {
+    DCHECK_EQ(mixer_input->output_samples_per_second(),
+              output_samples_per_second_);
     inputs_[mixer_input] = std::make_unique<InputImpl>(this, mixer_input);
   } else {
     non_redirected_inputs_.insert(mixer_input);
@@ -171,6 +173,7 @@
 }
 
 void AudioOutputRedirector::Start(int output_samples_per_second) {
+  output_samples_per_second_ = output_samples_per_second;
   output_->Start(output_samples_per_second);
 }
 
diff --git a/chromecast/media/cma/backend/audio_output_redirector.h b/chromecast/media/cma/backend/audio_output_redirector.h
index c2ab65f..e997bdc 100644
--- a/chromecast/media/cma/backend/audio_output_redirector.h
+++ b/chromecast/media/cma/backend/audio_output_redirector.h
@@ -97,6 +97,7 @@
 
   AudioOutputRedirectionConfig config_;
   const std::unique_ptr<RedirectedAudioOutput> output_;
+  int output_samples_per_second_ = 0;
 
   int next_num_frames_ = 0;
   int64_t next_output_timestamp_ = INT64_MIN;
diff --git a/chromecast/media/cma/backend/stream_mixer.cc b/chromecast/media/cma/backend/stream_mixer.cc
index 58cdab3..d621ac2 100644
--- a/chromecast/media/cma/backend/stream_mixer.cc
+++ b/chromecast/media/cma/backend/stream_mixer.cc
@@ -407,8 +407,26 @@
   // Initialize filters.
   mixer_pipeline_->Initialize(output_samples_per_second_, frames_per_write_);
 
+  // Determine the appropriate sample rate for the redirector. If a product
+  // needs to have these be different and support redirecting, then we will
+  // need to add/update the per-input resamplers before redirecting.
+  redirector_samples_per_second_ = GetSampleRateForDeviceId(
+      ::media::AudioDeviceDescription::kDefaultDeviceId);
+
+  const std::vector<const char*> redirectable_device_ids = {
+      kPlatformAudioDeviceId, kAlarmAudioDeviceId, kTtsAudioDeviceId,
+      ::media::AudioDeviceDescription::kDefaultDeviceId,
+      ::media::AudioDeviceDescription::kCommunicationsDeviceId};
+
+  for (const char* device_id : redirectable_device_ids) {
+    DCHECK_EQ(redirector_samples_per_second_,
+              GetSampleRateForDeviceId(device_id));
+  }
+
+  redirector_frames_per_write_ = redirector_samples_per_second_ *
+                                 frames_per_write_ / output_samples_per_second_;
   for (auto& redirector : audio_output_redirectors_) {
-    redirector.second->Start(output_samples_per_second_);
+    redirector.second->Start(redirector_samples_per_second_);
   }
 
   state_ = kStateRunning;
@@ -620,7 +638,7 @@
 
 void StreamMixer::WriteOneBuffer() {
   for (auto& redirector : audio_output_redirectors_) {
-    redirector.second->PrepareNextBuffer(frames_per_write_);
+    redirector.second->PrepareNextBuffer(redirector_frames_per_write_);
   }
 
   // Recursively mix and filter each group.
@@ -745,12 +763,13 @@
   AudioOutputRedirector* key = redirector.get();
   audio_output_redirectors_[key] = std::move(redirector);
 
+  if (state_ == kStateRunning) {
+    key->Start(redirector_samples_per_second_);
+  }
+
   for (const auto& input : inputs_) {
     key->AddInput(input.second.get());
   }
-  if (state_ == kStateRunning) {
-    key->Start(output_samples_per_second_);
-  }
 }
 
 void StreamMixer::RemoveAudioOutputRedirector(
@@ -916,5 +935,10 @@
   return true;
 }
 
+int StreamMixer::GetSampleRateForDeviceId(const std::string& device) {
+  DCHECK(mixer_pipeline_);
+  return mixer_pipeline_->GetInputGroup(device)->GetInputSampleRate();
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/backend/stream_mixer.h b/chromecast/media/cma/backend/stream_mixer.h
index 720098a..d917684 100644
--- a/chromecast/media/cma/backend/stream_mixer.h
+++ b/chromecast/media/cma/backend/stream_mixer.h
@@ -182,6 +182,7 @@
                         int channels,
                         std::unique_ptr<uint8_t[]> data,
                         int length);
+  int GetSampleRateForDeviceId(const std::string& device);
 
   MediaPipelineBackend::AudioDecoder::RenderingDelay GetTotalRenderingDelay(
       FilterGroup* filter_group);
@@ -208,6 +209,8 @@
   int requested_output_samples_per_second_ = 0;
   int output_samples_per_second_ = 0;
   int frames_per_write_ = 0;
+  int redirector_samples_per_second_ = 0;
+  int redirector_frames_per_write_ = 0;
 
   State state_;
   base::TimeTicks close_timestamp_;
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 9cf8952..19a974b7 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -184,9 +184,6 @@
       <message name="IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE" desc="The title used for the Ash Launcher in the Shelf (not mentioning 'Apps' since this is a general launcher).">
         Launcher
       </message>
-      <message name="IDS_ASH_SHELF_APP_LIST_LAUNCHER_SYNCING_TITLE" desc="The title used for the Ash Launcher in the Shelf to indicate loading/syncinc apps.">
-        Launcher (syncing apps...)
-      </message>
 
       <!-- Password expiry notifications -->
       <message name="IDS_PASSWORD_EXPIRY_DAYS_BODY" desc="Message body for a notification that tells the user their password will expire in less than some number of days (where 0 days means it has expired).">
diff --git a/components/arc/rotation_lock/arc_rotation_lock_bridge.cc b/components/arc/rotation_lock/arc_rotation_lock_bridge.cc
index b1b5c0b..bd98198 100644
--- a/components/arc/rotation_lock/arc_rotation_lock_bridge.cc
+++ b/components/arc/rotation_lock/arc_rotation_lock_bridge.cc
@@ -98,9 +98,8 @@
     DCHECK(found);
   }
 
-  bool in_tablet_mode = ash::Shell::Get()
-                            ->tablet_mode_controller()
-                            ->IsTabletModeWindowManagerEnabled();
+  bool in_tablet_mode =
+      ash::Shell::Get()->tablet_mode_controller()->InTabletMode();
   bool accelerometer_active = in_tablet_mode
                                   ? !ash::Shell::Get()
                                          ->screen_orientation_controller()
diff --git a/components/autofill/core/common/autofill_regex_constants.cc b/components/autofill/core/common/autofill_regex_constants.cc
index 7443330..6af11a1 100644
--- a/components/autofill/core/common/autofill_regex_constants.cc
+++ b/components/autofill/core/common/autofill_regex_constants.cc
@@ -96,6 +96,7 @@
     "|郵便番号"                 // ja-JP
     "|codigo|codpos|\\bcep\\b"  // pt-BR, pt-PT
     "|Почтовый.?Индекс"         // ru
+    "|पिन.?कोड"                 // hi
     "|邮政编码|邮编"            // zh-CN
     "|郵遞區號"                 // zh-TW
     "|우편.?번호";              // ko-KR
@@ -115,6 +116,8 @@
     "|市"                                    // zh-CN
     "|分區"                                  // zh-TW
     "|شهر"                                   // fa
+    "|शहर"                                   // hi for city
+    "|ग्राम|गाँव"                              // hi for village
     "|^시[^도·・]|시[·・]?군[·・]?구";       // ko-KR
 const char kStateRe[] =
     "(?<!(united|hist|history).?)state|county|region|province"
@@ -125,6 +128,7 @@
     "|省"                   // zh-CN
     "|地區"                 // zh-TW
     "|استان"                // fa
+    "|राज्य"                 // hi
     "|^시[·・]?도";         // ko-KR
 
 /////////////////////////////////////////////////////////////////////////////
@@ -148,8 +152,8 @@
 /////////////////////////////////////////////////////////////////////////////
 const char kPriceRe[] =
     "\\bprice\\b|\\brate\\b|\\bcost\\b"
-    "قیمة‎|سعر‎"                           // ar
-    "قیمت"                                            // fa
+    "|قیمة‎|سعر‎"                          // ar
+    "|قیمت"                                           // fa
     "|\\bprix\\b|\\bcoût\\b|\\bcout\\b|\\btarif\\b";  // fr-CA
 
 /////////////////////////////////////////////////////////////////////////////
@@ -258,6 +262,7 @@
     "|邮件|邮箱"                                   // zh-CN
     "|電郵地址"                                    // zh-TW
     "|ایمیل|پست.*الکترونیک"                        // fa
+    "|ईमेल|इलॅक्ट्रॉनिक.?मेल"                           // hi
     "|(?:이메일|전자.?우편|[Ee]-?mail)(.?주소)?";  // ko-KR
 
 /////////////////////////////////////////////////////////////////////////////
@@ -291,7 +296,8 @@
     "|nome"                    // pt-BR, pt-PT
     "|Имя"                     // ru
     "|نام"                     // fa
-    "|이름";                   // ko-KR
+    "|이름"                    // ko-KR
+    "|^नाम";                   // hi
 const char kMiddleInitialRe[] = "middle.*initial|m\\.i\\.|mi$|\\bmi\\b";
 const char kMiddleNameRe[] =
     "middle.*name|mname|middle$"
@@ -310,6 +316,7 @@
     "|morada|apelidos|surename|sobrenome"  // pt-BR, pt-PT
     "|Фамилия"                             // ru
     "|نام.*خانوادگی"                       // fa
+    "|उपनाम"                               // hi
     "|\\b성(?:[^명]|\\b)";                 // ko-KR
 
 /////////////////////////////////////////////////////////////////////////////
@@ -323,6 +330,7 @@
     "|電話"                                         // ja-JP
     "|telefone|telemovel"                           // pt-BR, pt-PT
     "|телефон"                                      // ru
+    "|मोबाइल"                                       // hi for mobile
     "|电话"                                         // zh-CN
     "|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?";  // ko-KR
 const char kCountryCodeRe[] =
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index b6073a3..14bbc793 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -19,6 +19,9 @@
 _jni_registration_header = "$target_gen_dir/cronet_jni_registration.h"
 _templates_dir = "$target_gen_dir/templates"
 
+# //components/cronet still needs to support Jelly Bean. See crbug.com/922656.
+_cronet_min_sdk_version = 16
+
 declare_args() {
   # In integrated mode, CronetEngine will use the shared network task runner by
   # other Chromium-based clients like webview without self-initialization.
@@ -427,6 +430,7 @@
 android_apk("cronet_sample_apk") {
   apk_name = "CronetSample"
   android_manifest = "sample/AndroidManifest.xml"
+  min_sdk_version = _cronet_min_sdk_version
   shared_libraries = [ ":cronet" ]
 
   deps = [
@@ -676,6 +680,7 @@
     apk_name = "CronetSampleTest"
     apk_under_test = ":cronet_sample_apk"
     android_manifest = "sample/javatests/AndroidManifest.xml"
+    min_sdk_version = _cronet_min_sdk_version
     java_files = [ "sample/javatests/src/org/chromium/cronet_sample_apk/CronetSampleTest.java" ]
     deps = [
       "//third_party/android_support_test_runner:rules_java",
@@ -876,6 +881,7 @@
   instrumentation_test_apk("cronet_test_instrumentation_apk") {
     apk_name = "CronetTestInstrumentation"
     android_manifest = "test/javatests/AndroidManifest.xml"
+    min_sdk_version = _cronet_min_sdk_version
 
     shared_libraries = [
       ":cronet",
@@ -933,6 +939,7 @@
       "cronet_smoketests_platform_only_instrumentation_apk") {
     apk_name = "PlatformOnlyEngineSmokeTestInstrumentation"
     android_manifest = "test/javatests/AndroidManifest.xml"
+    min_sdk_version = _cronet_min_sdk_version
 
     java_files = cronet_smoketests_platform_only_common_srcs + [
                    "test/src/org/chromium/net/CronetTestApplication.java",
@@ -996,6 +1003,7 @@
     testonly = true
     apk_name = "CronetPerfTest"
     android_manifest = "test/javaperftests/AndroidManifest.xml"
+    min_sdk_version = _cronet_min_sdk_version
     shared_libraries = [
       ":cronet",
       ":cronet_tests",
@@ -1161,6 +1169,14 @@
     outputs = [
       _zip_file,
     ]
+    _annotations_jar = "$root_out_dir/lib.java/third_party/android_deps/com_android_support_support_annotations.jar"
+    _src_jar = "$_package_dir/cronet_api-src.jar"
+    inputs = [
+      _annotations_jar,
+      _src_jar,
+      android_sdk_jar,
+    ]
+
     args = [
       "--output-dir",
       rebase_path(_package_dir, root_build_dir),
@@ -1174,16 +1190,18 @@
       rebase_path(depfile, root_build_dir),
       "--zip-file",
       rebase_path(_zip_file, root_build_dir),
-
       "--android-sdk-jar",
       rebase_path(android_sdk_jar, root_build_dir),
+      "--support-annotations-jar",
+      rebase_path(_annotations_jar, root_build_dir),
 
       # JavaDoc is generated from Cronet's API source jar.
       "--input-src-jar",
-      rebase_path("$_package_dir/cronet_api-src.jar", root_build_dir),
+      rebase_path(_src_jar, root_build_dir),
     ]
     deps = [
       ":jar_cronet_api_source",
+      "//third_party/android_deps:com_android_support_support_annotations_java",
     ]
   }
 
diff --git a/components/cronet/android/sample/AndroidManifest.xml b/components/cronet/android/sample/AndroidManifest.xml
index d1dd142..26d99b0 100644
--- a/components/cronet/android/sample/AndroidManifest.xml
+++ b/components/cronet/android/sample/AndroidManifest.xml
@@ -9,8 +9,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.cronet_sample_apk">
 
-    <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 -->
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <application android:name="CronetSampleApplication"
diff --git a/components/cronet/android/sample/javatests/AndroidManifest.xml b/components/cronet/android/sample/javatests/AndroidManifest.xml
index 5d3ad5e3..505e8d19 100644
--- a/components/cronet/android/sample/javatests/AndroidManifest.xml
+++ b/components/cronet/android/sample/javatests/AndroidManifest.xml
@@ -8,8 +8,6 @@
        doesn't ignore this. -->
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.chromium.cronet_sample_apk.tests">
-    <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 -->
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
     <!-- We add an application tag here just so that we can indicate that this
          package needs to link against the android.test library, which is
diff --git a/components/cronet/android/test/javaperftests/AndroidManifest.xml b/components/cronet/android/test/javaperftests/AndroidManifest.xml
index c7cd37c..27090dd 100644
--- a/components/cronet/android/test/javaperftests/AndroidManifest.xml
+++ b/components/cronet/android/test/javaperftests/AndroidManifest.xml
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.chromium.net">
-    <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 -->
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
diff --git a/components/cronet/android/test/javatests/AndroidManifest.xml b/components/cronet/android/test/javatests/AndroidManifest.xml
index af6ac00..f107248 100644
--- a/components/cronet/android/test/javatests/AndroidManifest.xml
+++ b/components/cronet/android/test/javatests/AndroidManifest.xml
@@ -6,8 +6,6 @@
    -->
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.chromium.net.tests">
-    <!-- //components/cronet still needs to support Jelly Bean. See crbug.com/922656 -->
-    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="24" />
     <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/components/cronet/tools/generate_javadoc.py b/components/cronet/tools/generate_javadoc.py
index 406500ac..7c3f33bd 100755
--- a/components/cronet/tools/generate_javadoc.py
+++ b/components/cronet/tools/generate_javadoc.py
@@ -38,7 +38,7 @@
   working_dir = os.path.join(options.input_dir, 'android', 'api')
   overview_file = os.path.abspath(options.overview_file)
 
-  android_sdk_jar = os.path.abspath(options.android_sdk_jar)
+  android_sdk_jar = options.android_sdk_jar
   if not android_sdk_jar:
     android_sdk_jar = os.path.join(
         SDK_DIR, 'platforms', 'android-27', 'android.jar')
@@ -57,9 +57,8 @@
     '-federate', 'Android', 'https://developer.android.com/',
     '-federationapi', 'Android', os.path.join(DOCLAVA_DIR, 'current.txt'),
     '-bootclasspath',
-    '%s:%s' % (android_sdk_jar,
-               os.path.join(SDK_DIR, 'extras', 'android', 'support',
-                            'annotations', 'android-support-annotations.jar')),
+    '%s:%s' % (os.path.abspath(android_sdk_jar),
+               os.path.abspath(options.support_annotations_jar)),
   ]
   for subdir, _, files in os.walk(src_dir):
     for filename in files:
@@ -91,6 +90,8 @@
   parser.add_option('--readme-file', help='Path of the README.md')
   parser.add_option('--zip-file', help='Path to ZIP archive of javadocs.')
   parser.add_option('--android-sdk-jar', help='Path to android.jar')
+  parser.add_option('--support-annotations-jar',
+                    help='Path to support-annotations-$VERSION.jar')
 
   options, _ = parser.parse_args()
   # A temporary directory to put the output of cronet api source jar files.
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 825b9ba3..aa248eed 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -595,8 +595,7 @@
     const bool becoming_snapped =
         requested_state == ash::WindowStateType::kLeftSnapped ||
         requested_state == ash::WindowStateType::kRightSnapped;
-    const bool is_tablet_mode =
-        WMHelper::GetInstance()->IsTabletModeWindowManagerEnabled();
+    const bool is_tablet_mode = WMHelper::GetInstance()->InTabletMode();
     gfx::Rect client_bounds =
         becoming_snapped && is_tablet_mode
             ? window_bounds
@@ -767,7 +766,7 @@
     const display::Display& new_display,
     uint32_t changed_metrics) {
   if (!widget_ || !widget_->IsActive() ||
-      !WMHelper::GetInstance()->IsTabletModeWindowManagerEnabled()) {
+      !WMHelper::GetInstance()->InTabletMode()) {
     return;
   }
 
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index addece11..506d246 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -81,8 +81,7 @@
 }
 
 void EnableTabletMode(bool enable) {
-  ash::Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
-      enable);
+  ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
 }
 
 // A canvas that just logs when a text blob is drawn.
@@ -632,7 +631,7 @@
   auto shell_surface =
       exo_test_helper()->CreateClientControlledShellSurface(surface.get());
   ash::Shell* shell = ash::Shell::Get();
-  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  shell->tablet_mode_controller()->SetEnabledForTest(true);
 
   // Start in maximized.
   shell_surface->SetMaximized();
@@ -994,7 +993,7 @@
 TEST_F(ClientControlledShellSurfaceTest, SnapWindowInSplitViewModeTest) {
   UpdateDisplay("807x607");
   ash::Shell* shell = ash::Shell::Get();
-  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  shell->tablet_mode_controller()->SetEnabledForTest(true);
 
   const gfx::Size buffer_size(800, 600);
   std::unique_ptr<Buffer> buffer1(
@@ -1200,7 +1199,7 @@
 TEST_F(ClientControlledShellSurfaceDragTest, DragWindowFromTopInTabletMode) {
   UpdateDisplay("800x600");
   ash::Shell* shell = ash::Shell::Get();
-  shell->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  shell->tablet_mode_controller()->SetEnabledForTest(true);
   std::unique_ptr<Surface> surface(new Surface());
   const gfx::Size window_size(800, 552);
   std::unique_ptr<Buffer> buffer(
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc
index e479821..205a01d 100644
--- a/components/exo/keyboard_unittest.cc
+++ b/components/exo/keyboard_unittest.cc
@@ -318,7 +318,7 @@
 
   ash::TabletModeController* tablet_mode_controller =
       ash::Shell::Get()->tablet_mode_controller();
-  tablet_mode_controller->EnableTabletModeWindowManager(true);
+  tablet_mode_controller->SetEnabledForTest(true);
 
   MockKeyboardDelegate delegate;
   Seat seat;
@@ -341,7 +341,7 @@
 
   keyboard.reset();
 
-  tablet_mode_controller->EnableTabletModeWindowManager(false);
+  tablet_mode_controller->SetEnabledForTest(false);
 }
 
 TEST_F(KeyboardTest, OnKeyboardTypeChanged_AccessibilityKeyboard) {
diff --git a/components/exo/test/exo_test_base_views.cc b/components/exo/test/exo_test_base_views.cc
index 368a2ae5..4612ec4 100644
--- a/components/exo/test/exo_test_base_views.cc
+++ b/components/exo/test/exo_test_base_views.cc
@@ -62,7 +62,7 @@
   void RemovePreTargetHandler(ui::EventHandler* handler) override {}
   void AddPostTargetHandler(ui::EventHandler* handler) override {}
   void RemovePostTargetHandler(ui::EventHandler* handler) override {}
-  bool IsTabletModeWindowManagerEnabled() const override { return false; }
+  bool InTabletMode() const override { return false; }
   double GetDefaultDeviceScaleFactor() const override { return 1.0; }
   void SetImeBlocked(aura::Window* window, bool ime_blocked) override {}
   bool IsImeBlocked(aura::Window* window) const override { return false; }
diff --git a/components/exo/wayland/zcr_remote_shell.cc b/components/exo/wayland/zcr_remote_shell.cc
index 82155b52..07c7ef8c 100644
--- a/components/exo/wayland/zcr_remote_shell.cc
+++ b/components/exo/wayland/zcr_remote_shell.cc
@@ -639,7 +639,7 @@
     helper->AddActivationObserver(this);
     display::Screen::GetScreen()->AddObserver(this);
 
-    layout_mode_ = helper->IsTabletModeWindowManagerEnabled()
+    layout_mode_ = helper->InTabletMode()
                        ? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
                        : ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED;
 
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index ab96ad2..baf1b24 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -117,7 +117,7 @@
   virtual void RemovePreTargetHandler(ui::EventHandler* handler) = 0;
   virtual void AddPostTargetHandler(ui::EventHandler* handler) = 0;
   virtual void RemovePostTargetHandler(ui::EventHandler* handler) = 0;
-  virtual bool IsTabletModeWindowManagerEnabled() const = 0;
+  virtual bool InTabletMode() const = 0;
   virtual double GetDefaultDeviceScaleFactor() const = 0;
   virtual void SetImeBlocked(aura::Window* window, bool ime_blocked) = 0;
   virtual bool IsImeBlocked(aura::Window* window) const = 0;
diff --git a/components/exo/wm_helper_chromeos.cc b/components/exo/wm_helper_chromeos.cc
index c79e89a..aa0d4322 100644
--- a/components/exo/wm_helper_chromeos.cc
+++ b/components/exo/wm_helper_chromeos.cc
@@ -194,10 +194,8 @@
   ash::Shell::Get()->RemovePostTargetHandler(handler);
 }
 
-bool WMHelperChromeOS::IsTabletModeWindowManagerEnabled() const {
-  return ash::Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+bool WMHelperChromeOS::InTabletMode() const {
+  return ash::Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
 double WMHelperChromeOS::GetDefaultDeviceScaleFactor() const {
diff --git a/components/exo/wm_helper_chromeos.h b/components/exo/wm_helper_chromeos.h
index 45338cb..854630cf 100644
--- a/components/exo/wm_helper_chromeos.h
+++ b/components/exo/wm_helper_chromeos.h
@@ -88,7 +88,7 @@
   void RemovePreTargetHandler(ui::EventHandler* handler) override;
   void AddPostTargetHandler(ui::EventHandler* handler) override;
   void RemovePostTargetHandler(ui::EventHandler* handler) override;
-  bool IsTabletModeWindowManagerEnabled() const override;
+  bool InTabletMode() const override;
   double GetDefaultDeviceScaleFactor() const override;
   void SetImeBlocked(aura::Window* window, bool ime_blocked) override;
   bool IsImeBlocked(aura::Window* window) const override;
diff --git a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java
index c87f1d36..d01bc2c 100644
--- a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java
+++ b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java
@@ -40,6 +40,7 @@
 
     /** Needs to be called before trying to access a module. */
     public static void init() {
+        if (sSplitCompatted) return;
         // SplitCompat.install may copy modules into Chrome's internal folder or clean them up.
         try (StrictModeContext unused = StrictModeContext.allowDiskWrites()) {
             SplitCompat.install(ContextUtils.getApplicationContext());
diff --git a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
index 13ba7c7..828c74c 100644
--- a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
+++ b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
@@ -91,6 +91,8 @@
 
     /** Records via UMA all modules that have been requested and are currently installed. */
     public static void recordModuleAvailability() {
+        // MUST call init before creating a SplitInstallManager.
+        ModuleInstaller.init();
         SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         Set<String> requestedModules = new HashSet<>();
         requestedModules.addAll(
@@ -124,6 +126,8 @@
 
     public PlayCoreModuleInstallerBackend(OnFinishedListener listener) {
         super(listener);
+        // MUST call init before creating a SplitInstallManager.
+        ModuleInstaller.init();
         mManager = SplitInstallManagerFactory.create(ContextUtils.getApplicationContext());
         mManager.registerListener(this);
     }
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index eadd21e9..799efab 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -492,6 +492,8 @@
 
 #if defined(OS_LINUX)
   int flags = ChildProcessHost::CHILD_ALLOW_SELF;
+#elif defined(OS_MACOSX)
+  int flags = ChildProcessHost::CHILD_PLUGIN;
 #else
   int flags = ChildProcessHost::CHILD_NORMAL;
 #endif
diff --git a/components/omnibox/browser/remote_suggestions_service.cc b/components/omnibox/browser/remote_suggestions_service.cc
index 46324b2..8c5ec1e 100644
--- a/components/omnibox/browser/remote_suggestions_service.cc
+++ b/components/omnibox/browser/remote_suggestions_service.cc
@@ -140,8 +140,7 @@
       search_engine->suggestions_url_ref();
   const SearchTermsData& search_terms_data =
       template_url_service->search_terms_data();
-  base::string16 prefix;
-  TemplateURLRef::SearchTermsArgs search_term_args(prefix);
+  TemplateURLRef::SearchTermsArgs search_term_args;
   if (!current_url.empty()) {
     search_term_args.current_page_url = current_url;
   }
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc
index a3b1c660..488187f 100644
--- a/components/omnibox/browser/search_provider.cc
+++ b/components/omnibox/browser/search_provider.cc
@@ -905,7 +905,7 @@
   // If the request is from omnibox focus, send empty search term args. The
   // purpose of such a request is to signal the server to warm up; no info
   // is required.
-  TemplateURLRef::SearchTermsArgs empty_search_term_args((base::string16()));
+  TemplateURLRef::SearchTermsArgs empty_search_term_args;
   BaseSearchProvider::AppendSuggestClientToAdditionalQueryParams(
       template_url, search_terms_data, input.current_page_classification(),
       &empty_search_term_args);
diff --git a/components/optimization_guide/test_hints_component_creator.cc b/components/optimization_guide/test_hints_component_creator.cc
index 40c66b78..aef242d3 100644
--- a/components/optimization_guide/test_hints_component_creator.cc
+++ b/components/optimization_guide/test_hints_component_creator.cc
@@ -26,6 +26,7 @@
 TestHintsComponentCreator::CreateHintsComponentInfoWithPageHints(
     optimization_guide::proto::OptimizationType optimization_type,
     const std::vector<std::string>& page_hint_host_suffixes,
+    const std::string& page_pattern,
     const std::vector<std::string>& resource_blocking_patterns) {
   optimization_guide::proto::Configuration config;
   for (const auto& page_hint_site : page_hint_host_suffixes) {
@@ -34,7 +35,7 @@
     hint->set_key_representation(optimization_guide::proto::HOST_SUFFIX);
 
     optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
-    page_hint->set_page_pattern("*");
+    page_hint->set_page_pattern(page_pattern);
 
     optimization_guide::proto::Optimization* optimization =
         page_hint->add_whitelisted_optimizations();
diff --git a/components/optimization_guide/test_hints_component_creator.h b/components/optimization_guide/test_hints_component_creator.h
index bbb6b7b..c95396e 100644
--- a/components/optimization_guide/test_hints_component_creator.h
+++ b/components/optimization_guide/test_hints_component_creator.h
@@ -29,12 +29,14 @@
   TestHintsComponentCreator();
   ~TestHintsComponentCreator();
 
-  // Creates component data based on |whitelisted_host_suffixes| with page hints
-  // for type |optimization_type| blocking resources specified by
-  // |resource_patterns|, and returns the HintsComponentInfo for it.
+  // Creates component data based on |whitelisted_host_suffixes| and
+  // |page_pattern| with page hints for type |optimization_type| blocking
+  // resources specified by |resource_patterns|, and returns the
+  // HintsComponentInfo for it.
   optimization_guide::HintsComponentInfo CreateHintsComponentInfoWithPageHints(
       optimization_guide::proto::OptimizationType optimization_type,
       const std::vector<std::string>& whitelisted_host_suffixes,
+      const std::string& page_pattern,
       const std::vector<std::string>& resource_patterns);
 
   // Creates component data based on |whitelisted_host_suffixes| with page hints
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index dec2f05c..477ccec 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -213,6 +213,7 @@
     "//components/sync",
   ]
   deps = [
+    ":csv",
     ":hash_password_manager",
     ":password_generator",
     ":password_hash_data",
@@ -275,6 +276,34 @@
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
+# TODO(crbug.com/974822): Ideally, all of the "import/" subdirectory would be
+# in a separate BUILD.gn file inside that subdirectory. However, this requires
+# the big "browser" target here to be split in multiple sub-targets to avoid
+# circular dependencies. For now, at least the files from "import" which can be
+# separated are made so, to limit the growth of this technical debt.
+static_library("csv") {
+  sources = [
+    "import/csv_field_parser.cc",
+    "import/csv_field_parser.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+source_set("csv_unittests") {
+  testonly = true
+  sources = [
+    "import/csv_field_parser_unittest.cc",
+  ]
+  deps = [
+    ":csv",
+    "//base",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
 static_library("password_generator") {
   sources = [
     "generation/password_generator.cc",
@@ -368,6 +397,7 @@
     "//url:url",
   ]
   deps = [
+    ":csv_unittests",
     "//base",
     "//components/autofill/core/common",
     "//net:net",
diff --git a/components/password_manager/core/browser/import/csv_field_parser.cc b/components/password_manager/core/browser/import/csv_field_parser.cc
new file mode 100644
index 0000000..ae1b70a
--- /dev/null
+++ b/components/password_manager/core/browser/import/csv_field_parser.cc
@@ -0,0 +1,118 @@
+// 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/password_manager/core/browser/import/csv_field_parser.h"
+
+#include "base/logging.h"
+
+namespace password_manager {
+
+CSVFieldParser::CSVFieldParser(base::StringPiece row) : row_(row) {}
+
+CSVFieldParser::~CSVFieldParser() = default;
+
+bool CSVFieldParser::NextField(base::StringPiece* field_contents) {
+  DCHECK(HasMoreFields());
+  if (fields_returned_ >= kMaxFields)
+    return false;
+
+  if (state_ != State::kInit) {
+    state_ = State::kError;
+    return false;
+  }
+
+  const size_t start = position_;
+  do {
+    UpdateState();
+  } while (state_ != State::kInit && state_ != State::kError);
+
+  if (state_ != State::kError) {
+    DCHECK_GT(position_, start);  // There must have been at least the ','.
+    *field_contents =
+        base::StringPiece(row_.data() + start, position_ - start - 1);
+
+    if (field_contents->starts_with("\"")) {
+      DCHECK(field_contents->ends_with("\"")) << *field_contents;
+      DCHECK_GE(field_contents->size(), 2u);
+      field_contents->remove_prefix(1);
+      field_contents->remove_suffix(1);
+    }
+    ++fields_returned_;
+    return true;
+  }
+  return false;
+}
+
+char CSVFieldParser::ConsumeChar() {
+  DCHECK_LE(position_, row_.size());
+  // The default character to return once all from |row_| are consumed and
+  // |position_| == |row_.size()|.
+  char ret = ',';
+  if (position_ < row_.size())
+    ret = row_[position_];
+  ++position_;
+  return ret;
+}
+
+void CSVFieldParser::UpdateState() {
+  if (position_ > row_.size()) {
+    // If in state |kInit| then the program attempts to read one field too many.
+    DCHECK_NE(state_, State::kInit);
+    // Otherwise a quotation mark was not matched before the end of input.
+    state_ = State::kError;
+    return;
+  }
+
+  char read = ConsumeChar();
+  switch (state_) {
+    case State::kInit:
+      switch (read) {
+        case ',':
+          break;
+        case '"':
+          state_ = State::kQuoted;
+          break;
+        default:
+          state_ = State::kPlain;
+          break;
+      }
+      break;
+    case State::kPlain:
+      switch (read) {
+        case ',':
+          state_ = State::kInit;
+          break;
+        default:
+          break;
+      }
+      break;
+    case State::kQuoted:
+      switch (read) {
+        case '"':
+          state_ = State::kAfter;
+          break;
+        default:
+          break;
+      }
+      break;
+    case State::kAfter:
+      switch (read) {
+        case ',':
+          state_ = State::kInit;
+          break;
+        case '"':
+          state_ = State::kQuoted;
+          break;
+        default:
+          state_ = State::kError;
+          break;
+      }
+      break;
+    case State::kError:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/import/csv_field_parser.h b/components/password_manager/core/browser/import/csv_field_parser.h
new file mode 100644
index 0000000..b02dccecf
--- /dev/null
+++ b/components/password_manager/core/browser/import/csv_field_parser.h
@@ -0,0 +1,107 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_CSV_FIELD_PARSER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_CSV_FIELD_PARSER_H_
+
+#include <stddef.h>
+
+#include "base/strings/string_piece.h"
+
+namespace password_manager {
+
+// CSVFieldParser is created for a row (line) of comma-separated-values and
+// iteratively returns individual fields.
+class CSVFieldParser {
+ public:
+  // Maximum number of fields accepted.
+  constexpr static size_t kMaxFields = 100;
+
+  explicit CSVFieldParser(base::StringPiece row);
+  ~CSVFieldParser();
+
+  CSVFieldParser(const CSVFieldParser&) = delete;
+  CSVFieldParser& operator=(const CSVFieldParser&) = delete;
+
+  // Advances the parser over the next comma-separated field and writes its
+  // contents into |field_contents| (comma separator excluded, enclosing
+  // quotation marks excluded, if present). Returns true if there were no
+  // errors. The input must not be empty (check with HasMoreFields() before
+  // calling).
+  bool NextField(base::StringPiece* field_contents);
+
+  bool HasMoreFields() const {
+    return state_ != State::kError && position_ <= row_.size();
+  }
+
+ private:
+  enum class State {
+    // The state just before a new field begins.
+    kInit,
+    // The state after parsing a syntax error.
+    kError,
+    // When inside a non-escaped block.
+    kPlain,
+    // When inside a quotation-mark-escaped block.
+    kQuoted,
+    // When after reading a block starting and ending with quotation marks. For
+    // the following input, the state would be visited after reading characters
+    // 4 and 7:
+    // a,"b""c",d
+    // 0123456789
+    kAfter,
+  };
+
+  // Returns the next character to be read and updates |position_|.
+  char ConsumeChar();
+
+  // Updates |state_| based on the next character to be read, according to this
+  // diagram (made with help of asciiflow.com):
+  //
+  //   ,
+  //  +--+  +--------------------------+
+  //  |  |  |                          |
+  // +V--+--V+all but " or , +--------+|
+  // |       +--------------->        ||
+  // | kInit |               | kPlain ||
+  // |       <---------------+        ||
+  // ++------+      ,        +^------++|
+  //  |                       |      | |
+  // "|                       +------+ |
+  //  |                    all but ,   |,
+  //  |                                |
+  //  |                                |
+  //  |   +---------+    "     +-------++
+  //  |   |         +---------->        |
+  //  +---> kQuoted |          | kAfter |
+  //      |         <----------+        |
+  //      +---------+    "     +-----+--+
+  //                                |
+  //      +--------+                |
+  //      |        |                |
+  //      | kError <----------------+
+  //      |        |   all but " or ,
+  //      +--------+
+  //
+  // The state kError has no outgoing transitions and so UpdateState should not
+  // be called when this state has been entered.
+  void UpdateState();
+
+  // State of the parser.
+  State state_ = State::kInit;
+  // The input.
+  const base::StringPiece row_;
+  // If |position_| is >=0 and < |row_.size()|, then it points at the character
+  // to be read next from |row_|. If it is equal to |row_.size()|, then it means
+  // a fake trailing "," will be read next. If it is |row_.size() + 1|, then
+  // reading is done.
+  size_t position_ = 0;
+
+  // The number of successful past invocations of NextField().
+  size_t fields_returned_ = 0;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_CSV_FIELD_PARSER_H_
diff --git a/components/password_manager/core/browser/import/csv_field_parser_unittest.cc b/components/password_manager/core/browser/import/csv_field_parser_unittest.cc
new file mode 100644
index 0000000..e717db2f
--- /dev/null
+++ b/components/password_manager/core/browser/import/csv_field_parser_unittest.cc
@@ -0,0 +1,141 @@
+// 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/password_manager/core/browser/import/csv_field_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+TEST(CSVFieldParser, Positive) {
+  struct TestCase {
+    const char* name;
+    const std::string input;
+    std::vector<std::string> expected_fields;
+  };
+  const TestCase kCases[] = {
+      {
+          "empty CSV",
+          "",
+          {""},
+      },
+      {
+          "single field",
+          "foo",
+          {"foo"},
+      },
+      {
+          "two fields",
+          "foo,bar",
+          {"foo", "bar"},
+      },
+      {
+          "empty string",
+          "foo,,bar",
+          {"foo", "", "bar"},
+      },
+      {
+          "extra spaces",
+          " alpha  beta ,  ",
+          {" alpha  beta ", "  "},
+      },
+      {
+          "no ASCII printable",
+          "\x07\t\x0B\x1F,$\xc2\xa2\xe2\x98\x83\xf0\xa4\xad\xa2",
+          {// Characters below 0x20: bell, horizontal + vertical tab, unit
+           // separator.
+           "\x07\t\x0B\x1F",
+           // Unicode code points having 1..4 byte UTF-8 representation: dollar
+           // sign (U+0024), cent sign (U+00A2), snowman (U+2603), Han
+           // character U+24B62.
+           "$\xc2\xa2\xe2\x98\x83\xf0\xa4\xad\xa2"},
+      },
+      {
+          "escaping",
+          "\"A\",\"B\"",
+          {"A", "B"},
+      },
+      {
+          "escaped separators",
+          "\"A\rB\",\"B\nC\",\"C\r\nD\",\"D\n\",\",\",\",,\",\"\"\"\"",
+          {"A\rB", "B\nC", "C\r\nD", "D\n", ",", ",,", "\"\""},
+      },
+      {
+          "empty fields",
+          ",,gamma",
+          {"", "", "gamma"},
+      },
+      {
+          "just enough fields",
+          std::string(CSVFieldParser::kMaxFields - 1, ','),
+          std::vector<std::string>(CSVFieldParser::kMaxFields),
+      },
+  };
+
+  for (const TestCase& test_case : kCases) {
+    SCOPED_TRACE(test_case.name);
+    CSVFieldParser field_parser(test_case.input);
+
+    for (const std::string& field : test_case.expected_fields) {
+      ASSERT_TRUE(field_parser.HasMoreFields());
+      base::StringPiece parsed;
+      EXPECT_TRUE(field_parser.NextField(&parsed));
+      EXPECT_EQ(field, parsed);
+    }
+  }
+}
+
+TEST(CSVFieldParser, Negative) {
+  struct TestCase {
+    const char* name;
+    const std::string input;
+    size_t index_of_first_failure;
+  };
+  const TestCase kCases[] = {
+      {
+          "unmatched quote, no text",
+          "\"",
+          0,
+      },
+      {
+          "unmatched quote, comma",
+          "j,\",",
+          1,
+      },
+      {
+          "unmatched quotes",
+          "\"alpha\",\"unmatched",
+          1,
+      },
+      {
+          "wrong quotes",
+          "\"a\"b\"c\",right",
+          0,
+      },
+      {
+          "too many fields",
+          std::string(CSVFieldParser::kMaxFields, ','),
+          CSVFieldParser::kMaxFields,
+      },
+  };
+
+  for (const TestCase& test_case : kCases) {
+    SCOPED_TRACE(test_case.name);
+    CSVFieldParser field_parser(test_case.input);
+
+    base::StringPiece parsed;
+    for (size_t i = 0; i < test_case.index_of_first_failure; ++i) {
+      ASSERT_TRUE(field_parser.HasMoreFields());
+      EXPECT_TRUE(field_parser.NextField(&parsed));
+    }
+    ASSERT_TRUE(field_parser.HasMoreFields());
+    EXPECT_FALSE(field_parser.NextField(&parsed));
+  }
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/import/csv_reader.cc b/components/password_manager/core/browser/import/csv_reader.cc
index 0e92f52..8d322f26 100644
--- a/components/password_manager/core/browser/import/csv_reader.cc
+++ b/components/password_manager/core/browser/import/csv_reader.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string_util.h"
+#include "components/password_manager/core/browser/import/csv_field_parser.h"
 
 namespace password_manager {
 
@@ -58,201 +59,6 @@
   return ret;
 }
 
-// Created for a row (line) of comma-separated-values, iteratively returns
-// individual fields.
-class FieldParser {
- public:
-  explicit FieldParser(base::StringPiece row);
-  ~FieldParser();
-
-  // Advances the parser over the next comma-separated field and writes its
-  // contents into |field_contents| (comma separator excluded, enclosing
-  // quotation marks excluded, if present). Returns true if there were no
-  // errors. The input must not be empty (check with HasMoreFields() before
-  // calling).
-  // TODO(crbug.com/918530): Also unescape the field contents.
-  bool NextField(base::StringPiece* field_contents);
-
-  bool HasMoreFields() const {
-    return state_ != State::kError && position_ <= row_.size();
-  }
-
- private:
-  enum class State {
-    // The state just before a new field begins.
-    kInit,
-    // The state after parsing a syntax error.
-    kError,
-    // When inside a non-escaped block.
-    kPlain,
-    // When inside a quotation-mark-escaped block.
-    kQuoted,
-    // When after reading a block starting and ending with quotation marks. For
-    // the following input, the state would be visited after reading characters
-    // 4 and 7:
-    // a,"b""c",d
-    // 0123456789
-    kAfter,
-  };
-
-  // Returns the next character to be read and updates |position_|.
-  char ConsumeChar();
-
-  // Updates |state_| based on the next character to be read, according to this
-  // diagram (made with help of asciiflow.com):
-  //
-  //   ,
-  //  +--+  +--------------------------+
-  //  |  |  |                          |
-  // +V--+--V+all but " or , +--------+|
-  // |       +--------------->        ||
-  // | kInit |               | kPlain ||
-  // |       <---------------+        ||
-  // ++------+      ,        +^------++|
-  //  |                       |      | |
-  // "|                       +------+ |
-  //  |                    all but ,   |,
-  //  |                                |
-  //  |                                |
-  //  |   +---------+    "     +-------++
-  //  |   |         +---------->        |
-  //  +---> kQuoted |          | kAfter |
-  //      |         <----------+        |
-  //      +---------+    "     +-----+--+
-  //                                |
-  //      +--------+                |
-  //      |        |                |
-  //      | kError <----------------+
-  //      |        |   all but " or ,
-  //      +--------+
-  //
-  // The state kError has no outgoing transitions and so UpdateState should not
-  // be called when this state has been entered.
-  void UpdateState();
-
-  // State of the parser.
-  State state_ = State::kInit;
-  // The input.
-  const base::StringPiece row_;
-  // If |position_| is >=0 and < |row_.size()|, then it points at the character
-  // to be read next from |row_|. If it is equal to |row_.size()|, then it means
-  // a fake trailing "," will be read next. If it is |row_.size() + 1|, then
-  // reading is done.
-  size_t position_ = 0;
-
-  // The number of successful past invocations of NextField().
-  size_t fields_returned_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(FieldParser);
-};
-
-FieldParser::FieldParser(base::StringPiece row) : row_(row) {}
-
-FieldParser::~FieldParser() = default;
-
-bool FieldParser::NextField(base::StringPiece* field_contents) {
-  DCHECK(HasMoreFields());
-  if (fields_returned_ >= CSVTable::kMaxColumns)
-    return false;
-
-  if (state_ != State::kInit) {
-    state_ = State::kError;
-    return false;
-  }
-
-  const size_t start = position_;
-  do {
-    UpdateState();
-  } while (state_ != State::kInit && state_ != State::kError);
-
-  if (state_ != State::kError) {
-    DCHECK_GT(position_, start);  // There must have been at least the ','.
-    *field_contents =
-        base::StringPiece(row_.data() + start, position_ - start - 1);
-
-    if (field_contents->starts_with("\"")) {
-      DCHECK(field_contents->ends_with("\"")) << *field_contents;
-      DCHECK_GE(field_contents->size(), 2u);
-      field_contents->remove_prefix(1);
-      field_contents->remove_suffix(1);
-    }
-    ++fields_returned_;
-    return true;
-  }
-  return false;
-}
-
-char FieldParser::ConsumeChar() {
-  DCHECK_LE(position_, row_.size());
-  // The default character to return once all from |row_| are consumed and
-  // |position_| == |row_.size()|.
-  char ret = ',';
-  if (position_ < row_.size())
-    ret = row_[position_];
-  ++position_;
-  return ret;
-}
-
-void FieldParser::UpdateState() {
-  if (position_ > row_.size()) {
-    // If in state |kInit| then the program attempts to read one field too many.
-    DCHECK_NE(state_, State::kInit);
-    // Otherwise a quotation mark was not matched before the end of input.
-    state_ = State::kError;
-    return;
-  }
-
-  char read = ConsumeChar();
-  switch (state_) {
-    case State::kInit:
-      switch (read) {
-        case ',':
-          break;
-        case '"':
-          state_ = State::kQuoted;
-          break;
-        default:
-          state_ = State::kPlain;
-          break;
-      }
-      break;
-    case State::kPlain:
-      switch (read) {
-        case ',':
-          state_ = State::kInit;
-          break;
-        default:
-          break;
-      }
-      break;
-    case State::kQuoted:
-      switch (read) {
-        case '"':
-          state_ = State::kAfter;
-          break;
-        default:
-          break;
-      }
-      break;
-    case State::kAfter:
-      switch (read) {
-        case ',':
-          state_ = State::kInit;
-          break;
-        case '"':
-          state_ = State::kQuoted;
-          break;
-        default:
-          state_ = State::kError;
-          break;
-      }
-      break;
-    case State::kError:
-      NOTREACHED();
-      break;
-  }
-}
-
 // Created for a string with potentially multiple rows of
 // comma-separated-values, iteratively returns individual fields from row after
 // row.
@@ -282,7 +88,7 @@
   fields->clear();
 
   DCHECK(HasMoreRows());
-  FieldParser parser(ConsumeLine(&remaining_csv_piece_));
+  CSVFieldParser parser(ConsumeLine(&remaining_csv_piece_));
   base::StringPiece current_field;
   while (parser.HasMoreFields()) {
     if (!parser.NextField(&current_field))
diff --git a/components/password_manager/core/browser/import/csv_reader.h b/components/password_manager/core/browser/import/csv_reader.h
index 978685a1..0670bd86 100644
--- a/components/password_manager/core/browser/import/csv_reader.h
+++ b/components/password_manager/core/browser/import/csv_reader.h
@@ -17,10 +17,6 @@
 // Parsed representation of tabular CSV data.
 class CSVTable {
  public:
-  // Maximum number of columns accepted. If any row has more than |kMaxColumns|
-  // cells, the parsing fails.
-  constexpr static size_t kMaxColumns = 100;
-
   CSVTable();
   ~CSVTable();
 
@@ -33,7 +29,8 @@
   //   * Inconsistent number of fields within records is handled gracefully.
   //     Extra fields are ignored. Missing fields will have no corresponding
   //     key-value pair in the record.
-  //   * Seeing a row with more than |kMaxColumns| cells is a syntax error.
+  //   * Seeing a row with too many cells is a syntax error (see CSVFieldParser
+  //     for the actual limit).
   //   * Repeated columns of the same name are not supported (the last value
   //     will be preserved).
   // Returns false if parsing failed due to a syntax error.
diff --git a/components/password_manager/core/browser/import/csv_reader_unittest.cc b/components/password_manager/core/browser/import/csv_reader_unittest.cc
index 78d1942..738d8b0 100644
--- a/components/password_manager/core/browser/import/csv_reader_unittest.cc
+++ b/components/password_manager/core/browser/import/csv_reader_unittest.cc
@@ -185,12 +185,6 @@
               {{"bar", "f"}, {"foo", "e"}},
           },
       },
-      {
-          "JustEnoughColumns",
-          std::string(CSVTable::kMaxColumns - 1, ','),
-          std::vector<const char*>{CSVTable::kMaxColumns, ""},
-          {},
-      },
   };
 
   for (const TestCase& test_case : kCases) {
@@ -238,10 +232,6 @@
           "FailureWhenJustOneQuoteAndComma",
           "\",",
       },
-      {
-          "TooManyColumns",
-          std::string(CSVTable::kMaxColumns, ','),
-      },
   };
 
   for (const TestCase& test_case : kCases) {
diff --git a/components/policy/core/common/policy_loader_mac.mm b/components/policy/core/common/policy_loader_mac.mm
index 55c756c..990f980 100644
--- a/components/policy/core/common/policy_loader_mac.mm
+++ b/components/policy/core/common/policy_loader_mac.mm
@@ -9,9 +9,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/enterprise_util.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/mac/foundation_util.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
@@ -58,6 +60,11 @@
         managed_policy_path_, false,
         base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this)));
   }
+
+  base::UmaHistogramBoolean("EnterpriseCheck.IsManaged",
+                            !managed_policy_path_.empty());
+  base::UmaHistogramBoolean("EnterpriseCheck.IsEnterpriseUser",
+                            base::IsMachineExternallyManaged());
 }
 
 std::unique_ptr<PolicyBundle> PolicyLoaderMac::Load() {
diff --git a/components/previews/README b/components/previews/README
index f7f0e5f..223128c 100644
--- a/components/previews/README
+++ b/components/previews/README
@@ -1,2 +1,29 @@
-The Previews component contains code for changing the format and content of
-web pages to improve data savings and/or performance.
\ No newline at end of file
+The Lite pages component contains code for changing the format and content of
+web pages to improve data savings and/or performance.
+
+## Manual Testing
+
+To manually evaluate the effect of Lite Pages on a webpage, start Chrome on
+Android with version equal to or greater than 77.0.3830.0, with the following
+command line flags:
+
+```
+chrome \
+  --force-enable-lite-pages \
+  --force-effective-connection-type=Slow-2G
+```
+
+And then enable "Lite Mode" from the Chrome Settings Menu (Android only).
+
+## Explanation
+
+The above flags will put Chrome into a state matching that of the target user
+population of lite pages.
+
+When a lite page is shown, the "Lite Badge" will be displayed in the Omnibox.
+
+Please note that since the lite pages component is still in active development
+and relies heavily on server interactions, the transformation(s) applied to any
+single page may change over time. However, the transformation(s) applied to a
+page are very like to be the same for all clients requesting that page at the
+same time from the same geography.
diff --git a/components/previews/core/previews_switches.cc b/components/previews/core/previews_switches.cc
index d6db718..c61559ba 100644
--- a/components/previews/core/previews_switches.cc
+++ b/components/previews/core/previews_switches.cc
@@ -25,7 +25,7 @@
 const char kIgnorePreviewsBlacklist[] = "ignore-previews-blacklist";
 
 // Force enable all available previews on every page load.
-const char kForceEnablePreviews[] = "force-enable-previews";
+const char kForceEnablePreviews[] = "force-enable-lite-pages";
 
 // Override the Lite Page Preview Host.
 const char kLitePageServerPreviewHost[] = "litepage-server-previews-host";
diff --git a/components/profile_metrics/BUILD.gn b/components/profile_metrics/BUILD.gn
index fe85cf6..6f4666d8 100644
--- a/components/profile_metrics/BUILD.gn
+++ b/components/profile_metrics/BUILD.gn
@@ -4,6 +4,7 @@
 
 static_library("profile_metrics") {
   sources = [
+    "browser_profile_type.h",
     "counts.cc",
     "counts.h",
   ]
diff --git a/components/profile_metrics/browser_profile_type.h b/components/profile_metrics/browser_profile_type.h
new file mode 100644
index 0000000..916972c
--- /dev/null
+++ b/components/profile_metrics/browser_profile_type.h
@@ -0,0 +1,23 @@
+// 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_PROFILE_METRICS_BROWSER_PROFILE_TYPE_H_
+#define COMPONENTS_PROFILE_METRICS_BROWSER_PROFILE_TYPE_H_
+
+namespace profile_metrics {
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class BrowserProfileType {
+  kRegular = 0,
+  kIncognito = 1,
+  kGuest = 2,
+  kSystem = 3,
+  kIndependentIncognitoProfile = 4,
+  kMaxValue = kIndependentIncognitoProfile,
+};
+
+}  // namespace profile_metrics
+
+#endif  // COMPONENTS_PROFILE_METRICS_BROWSER_PROFILE_TYPE_H_
\ No newline at end of file
diff --git a/components/safe_browsing/proto/csd.proto b/components/safe_browsing/proto/csd.proto
index 8904bf7..1dfe8e2 100644
--- a/components/safe_browsing/proto/csd.proto
+++ b/components/safe_browsing/proto/csd.proto
@@ -1325,6 +1325,8 @@
     optional string value = 2;
   }
   repeated Attribute attribute = 6;
+
+  optional bytes inner_html = 7;
 }
 
 // Protobuf for Chrome extension webstore install request.
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 2bb6ed0a..678510b 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -185,16 +185,11 @@
 
 // TemplateURLRef::SearchTermsArgs --------------------------------------------
 
+TemplateURLRef::SearchTermsArgs::SearchTermsArgs() = default;
+
 TemplateURLRef::SearchTermsArgs::SearchTermsArgs(
     const base::string16& search_terms)
-    : search_terms(search_terms),
-      input_type(metrics::OmniboxInputType::INVALID),
-      accepted_suggestion(NO_SUGGESTIONS_AVAILABLE),
-      cursor_position(base::string16::npos),
-      page_classification(metrics::OmniboxEventProto::INVALID_SPEC),
-      append_extra_query_params_from_command_line(false),
-      from_app_list(false),
-      contextual_search_params(ContextualSearchParams()) {}
+    : search_terms(search_terms) {}
 
 TemplateURLRef::SearchTermsArgs::SearchTermsArgs(const SearchTermsArgs& other) =
     default;
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h
index 21c68f02..5aa6ffc 100644
--- a/components/search_engines/template_url.h
+++ b/components/search_engines/template_url.h
@@ -71,6 +71,7 @@
   // TemplateURLRef::ReplaceSearchTerms methods.  By default, only search_terms
   // is required and is passed in the constructor.
   struct SearchTermsArgs {
+    SearchTermsArgs();
     explicit SearchTermsArgs(const base::string16& search_terms);
     SearchTermsArgs(const SearchTermsArgs& other);
     ~SearchTermsArgs();
@@ -135,7 +136,7 @@
     base::string16 original_query;
 
     // The type the original input query was identified as.
-    metrics::OmniboxInputType input_type;
+    metrics::OmniboxInputType input_type = metrics::OmniboxInputType::INVALID;
 
     // The optional assisted query stats, aka AQS, used for logging purposes.
     // This string contains impressions of all autocomplete matches shown
@@ -146,18 +147,19 @@
     std::string assisted_query_stats;
 
     // TODO: Remove along with "aq" CGI param.
-    int accepted_suggestion;
+    int accepted_suggestion = NO_SUGGESTIONS_AVAILABLE;
 
     // The 0-based position of the cursor within the query string at the time
     // the request was issued.  Set to base::string16::npos if not used.
-    size_t cursor_position;
+    size_t cursor_position = base::string16::npos;
 
     // The URL of the current webpage to be used for experimental zero-prefix
     // suggestions.
     std::string current_page_url;
 
     // Which omnibox the user used to type the prefix.
-    metrics::OmniboxEventProto::PageClassification page_classification;
+    metrics::OmniboxEventProto::PageClassification page_classification =
+        metrics::OmniboxEventProto::INVALID_SPEC;
 
     // Optional session token.
     std::string session_token;
@@ -176,7 +178,7 @@
     // about the query portion of the URL.  Since neither TemplateURLRef nor
     // indeed TemplateURL know whether a TemplateURL is the default search
     // engine, callers instead must set this manually.
-    bool append_extra_query_params_from_command_line;
+    bool append_extra_query_params_from_command_line = false;
 
     // The raw content of an image thumbnail that will be used as a query for
     // search-by-image frontend.
@@ -191,7 +193,7 @@
 
     // True if the search was made using the app list search box. Otherwise, the
     // search was made using the omnibox.
-    bool from_app_list;
+    bool from_app_list = false;
 
     ContextualSearchParams contextual_search_params;
   };
diff --git a/components/send_tab_to_self/BUILD.gn b/components/send_tab_to_self/BUILD.gn
index 907f11d..1450990 100644
--- a/components/send_tab_to_self/BUILD.gn
+++ b/components/send_tab_to_self/BUILD.gn
@@ -73,7 +73,7 @@
     "//components/history/core/browser",
     "//components/send_tab_to_self/proto:send_tab_to_self_proto",
     "//components/sync:test_support",
-    "//components/sync_device_info",
+    "//components/sync_device_info:test_support",
     "//testing/gtest",
     "//url",
   ]
diff --git a/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc b/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
index 38d69e213..111d4156 100644
--- a/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
+++ b/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
@@ -26,7 +26,7 @@
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "components/sync/test/test_matchers.h"
 #include "components/sync_device_info/device_info.h"
-#include "components/sync_device_info/device_info_tracker.h"
+#include "components/sync_device_info/fake_device_info_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -89,52 +89,6 @@
   return testing::ExplainMatchResult(e, arg->GetGUID(), result_listener);
 }
 
-// TODO(crbug.com/958016): Extract into its own file.
-// Mock DeviceInfoTracker class for setting device info.
-class TestDeviceInfoTracker : public syncer::DeviceInfoTracker {
- public:
-  TestDeviceInfoTracker() = default;
-  ~TestDeviceInfoTracker() override = default;
-
-  static std::unique_ptr<syncer::DeviceInfo> CloneDeviceInfo(
-      const syncer::DeviceInfo& device_info) {
-    return std::make_unique<syncer::DeviceInfo>(
-        device_info.guid(), device_info.client_name(),
-        device_info.chrome_version(), device_info.sync_user_agent(),
-        device_info.device_type(), device_info.signin_scoped_device_id(),
-        device_info.last_updated_timestamp(),
-        device_info.send_tab_to_self_receiving_enabled());
-  }
-
-  void Add(const syncer::DeviceInfo* device) { devices_.push_back(device); }
-
-  // DeviceInfoTracker implementation.
-  bool IsSyncing() const override { return false; }
-  std::unique_ptr<syncer::DeviceInfo> GetDeviceInfo(
-      const std::string& client_id) const override {
-    NOTIMPLEMENTED();
-    return std::unique_ptr<syncer::DeviceInfo>();
-  }
-  std::vector<std::unique_ptr<syncer::DeviceInfo>> GetAllDeviceInfo()
-      const override {
-    std::vector<std::unique_ptr<syncer::DeviceInfo>> devices;
-    for (const syncer::DeviceInfo* device : devices_) {
-      devices.push_back(CloneDeviceInfo(*device));
-    }
-    return devices;
-  }
-  int CountActiveDevices() const override { return devices_.size(); }
-  void AddObserver(Observer* observer) override { NOTIMPLEMENTED(); }
-  void RemoveObserver(Observer* observer) override { NOTIMPLEMENTED(); }
-  void ForcePulseForTest() override { NOTIMPLEMENTED(); }
-
- private:
-  // DeviceInfo stored here are not owned.
-  std::vector<const syncer::DeviceInfo*> devices_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestDeviceInfoTracker);
-};
-
 class SendTabToSelfBridgeTest : public testing::Test {
  protected:
   SendTabToSelfBridgeTest()
@@ -242,7 +196,7 @@
 
   testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_;
 
-  TestDeviceInfoTracker device_info_tracker_;
+  syncer::FakeDeviceInfoTracker device_info_tracker_;
 
   std::unique_ptr<SendTabToSelfBridge> bridge_;
 
diff --git a/components/sync_device_info/BUILD.gn b/components/sync_device_info/BUILD.gn
index 04dc5e4..d50134fb 100644
--- a/components/sync_device_info/BUILD.gn
+++ b/components/sync_device_info/BUILD.gn
@@ -62,6 +62,18 @@
   }
 }
 
+static_library("test_support") {
+  testonly = true
+  sources = [
+    "fake_device_info_tracker.cc",
+    "fake_device_info_tracker.h",
+  ]
+
+  public_deps = [
+    ":sync_device_info",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
@@ -76,6 +88,7 @@
 
   deps = [
     ":sync_device_info",
+    ":test_support",
     "//base",
     "//base/test:test_support",
     "//components/sync:test_support",
diff --git a/components/sync_device_info/device_count_metrics_provider_unittest.cc b/components/sync_device_info/device_count_metrics_provider_unittest.cc
index 6de7eda..29c07aa31 100644
--- a/components/sync_device_info/device_count_metrics_provider_unittest.cc
+++ b/components/sync_device_info/device_count_metrics_provider_unittest.cc
@@ -9,37 +9,11 @@
 #include "base/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "components/sync_device_info/device_info.h"
-#include "components/sync_device_info/device_info_tracker.h"
+#include "components/sync_device_info/fake_device_info_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
 
-namespace {
-
-class FakeTracker : public DeviceInfoTracker {
- public:
-  explicit FakeTracker(const int count) : count_(count) {}
-
-  // DeviceInfoTracker
-  bool IsSyncing() const override { return false; }
-  std::unique_ptr<DeviceInfo> GetDeviceInfo(
-      const std::string& client_id) const override {
-    return std::unique_ptr<DeviceInfo>();
-  }
-  std::vector<std::unique_ptr<DeviceInfo>> GetAllDeviceInfo() const override {
-    return std::vector<std::unique_ptr<DeviceInfo>>();
-  }
-  void AddObserver(Observer* observer) override {}
-  void RemoveObserver(Observer* observer) override {}
-  int CountActiveDevices() const override { return count_; }
-  void ForcePulseForTest() override {}
-
- private:
-  int count_;
-};
-
-}  // namespace
-
 class DeviceCountMetricsProviderTest : public testing::Test {
  public:
   DeviceCountMetricsProviderTest()
@@ -48,9 +22,11 @@
                                 base::Unretained(this))) {}
 
   void AddTracker(const int count) {
-    trackers_.push_back(
-        std::unique_ptr<DeviceInfoTracker>(new FakeTracker(count)));
+    auto tracker = std::make_unique<FakeDeviceInfoTracker>();
+    tracker->OverrideActiveDeviceCount(count);
+    trackers_.emplace_back(std::move(tracker));
   }
+
   void GetTrackers(std::vector<const DeviceInfoTracker*>* trackers) {
     for (const auto& tracker : trackers_) {
       trackers->push_back(tracker.get());
diff --git a/components/sync_device_info/fake_device_info_tracker.cc b/components/sync_device_info/fake_device_info_tracker.cc
new file mode 100644
index 0000000..4ce4251
--- /dev/null
+++ b/components/sync_device_info/fake_device_info_tracker.cc
@@ -0,0 +1,75 @@
+// 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/sync_device_info/fake_device_info_tracker.h"
+
+#include "base/logging.h"
+#include "components/sync_device_info/device_info.h"
+
+namespace {
+
+// static
+std::unique_ptr<syncer::DeviceInfo> CloneDeviceInfo(
+    const syncer::DeviceInfo& device_info) {
+  return std::make_unique<syncer::DeviceInfo>(
+      device_info.guid(), device_info.client_name(),
+      device_info.chrome_version(), device_info.sync_user_agent(),
+      device_info.device_type(), device_info.signin_scoped_device_id(),
+      device_info.last_updated_timestamp(),
+      device_info.send_tab_to_self_receiving_enabled());
+}
+
+}  // namespace
+
+namespace syncer {
+
+FakeDeviceInfoTracker::FakeDeviceInfoTracker() = default;
+
+FakeDeviceInfoTracker::~FakeDeviceInfoTracker() = default;
+
+bool FakeDeviceInfoTracker::IsSyncing() const {
+  return !devices_.empty();
+}
+
+std::unique_ptr<DeviceInfo> FakeDeviceInfoTracker::GetDeviceInfo(
+    const std::string& client_id) const {
+  NOTREACHED();
+  return nullptr;
+}
+
+std::vector<std::unique_ptr<DeviceInfo>>
+FakeDeviceInfoTracker::GetAllDeviceInfo() const {
+  std::vector<std::unique_ptr<DeviceInfo>> list;
+
+  for (const DeviceInfo* device : devices_)
+    list.push_back(CloneDeviceInfo(*device));
+
+  return list;
+}
+
+void FakeDeviceInfoTracker::AddObserver(Observer* observer) {
+  NOTREACHED();
+}
+
+void FakeDeviceInfoTracker::RemoveObserver(Observer* observer) {
+  NOTREACHED();
+}
+
+int FakeDeviceInfoTracker::CountActiveDevices() const {
+  return active_device_count_.value_or(devices_.size());
+}
+
+void FakeDeviceInfoTracker::ForcePulseForTest() {
+  NOTREACHED();
+}
+
+void FakeDeviceInfoTracker::Add(const DeviceInfo* device) {
+  devices_.push_back(device);
+}
+
+void FakeDeviceInfoTracker::OverrideActiveDeviceCount(int count) {
+  active_device_count_ = count;
+}
+
+}  // namespace syncer
diff --git a/components/sync_device_info/fake_device_info_tracker.h b/components/sync_device_info/fake_device_info_tracker.h
new file mode 100644
index 0000000..933f875
--- /dev/null
+++ b/components/sync_device_info/fake_device_info_tracker.h
@@ -0,0 +1,53 @@
+// 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_SYNC_DEVICE_INFO_FAKE_DEVICE_INFO_TRACKER_H_
+#define COMPONENTS_SYNC_DEVICE_INFO_FAKE_DEVICE_INFO_TRACKER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "components/sync_device_info/device_info_tracker.h"
+
+namespace syncer {
+
+class DeviceInfo;
+
+// Fake DeviceInfoTracker to be used in tests.
+class FakeDeviceInfoTracker : public DeviceInfoTracker {
+ public:
+  FakeDeviceInfoTracker();
+  ~FakeDeviceInfoTracker() override;
+
+  // DeviceInfoTracker
+  bool IsSyncing() const override;
+  std::unique_ptr<DeviceInfo> GetDeviceInfo(
+      const std::string& client_id) const override;
+  std::vector<std::unique_ptr<DeviceInfo>> GetAllDeviceInfo() const override;
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  int CountActiveDevices() const override;
+  void ForcePulseForTest() override;
+
+  // Adds a new DeviceInfo entry to |devices_|.
+  void Add(const DeviceInfo* device);
+
+  // Overrides the result of CountActiveDevices() to |count| instead of the
+  // actual number of devices in |devices_|.
+  void OverrideActiveDeviceCount(int count);
+
+ private:
+  // DeviceInfo stored here are not owned.
+  std::vector<const DeviceInfo*> devices_;
+  base::Optional<int> active_device_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDeviceInfoTracker);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_DEVICE_INFO_FAKE_DEVICE_INFO_TRACKER_H_
diff --git a/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 b/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2
index 8fdd785..4e0f9f0 100644
--- a/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2
+++ b/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.components_browsertests_apk">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.CAMERA" />
diff --git a/components/test/data/autofill/heuristics/input/157_i18n_hi.html b/components/test/data/autofill/heuristics/input/157_i18n_hi.html
new file mode 100644
index 0000000..b1be9a6
--- /dev/null
+++ b/components/test/data/autofill/heuristics/input/157_i18n_hi.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title></title>
+  </head>
+  <body>
+    <form action="http://www.google.com/" method="post">
+      <label for="fn">नाम:</label> <input type="text" id="fn"><br>
+      <label for="ln">उपनाम:</label> <input type="text" id="ln"><br>
+      <label for="ct">शहर:</label> <input type="text" id="ct"><br>
+      <label for="st">राज्य:</label> <input type="text" id="st"><br>
+      <label for="zc">पिन कोड:</label> <input type="text" id="zc"><br>
+      <label for="em">ईमेल:</label> <input type="text" id="em"><br>
+      <label for="ph">मोबाइल:</label> <input type="text" id="ph"><br>
+    </form>
+  </body>
+</html>
diff --git a/components/test/data/autofill/heuristics/output/157_i18n_hi.out b/components/test/data/autofill/heuristics/output/157_i18n_hi.out
new file mode 100644
index 0000000..3aa91ac
--- /dev/null
+++ b/components/test/data/autofill/heuristics/output/157_i18n_hi.out
@@ -0,0 +1,7 @@
+NAME_FIRST | fn | नाम: |  | fn_1-default
+NAME_LAST | ln | उपनाम: |  | fn_1-default
+ADDRESS_HOME_CITY | ct | शहर: |  | fn_1-default
+ADDRESS_HOME_STATE | st | राज्य: |  | fn_1-default
+ADDRESS_HOME_ZIP | zc | पिन कोड: |  | fn_1-default
+EMAIL_ADDRESS | em | ईमेल: |  | fn_1-default
+PHONE_HOME_WHOLE_NUMBER | ph | मोबाइल: |  | fn_1-default
diff --git a/components/variations/variations_crash_keys_unittest.cc b/components/variations/variations_crash_keys_unittest.cc
index a28cc5a0..633f2cd 100644
--- a/components/variations/variations_crash_keys_unittest.cc
+++ b/components/variations/variations_crash_keys_unittest.cc
@@ -32,7 +32,7 @@
  public:
   VariationsCrashKeysTest() : field_trial_list_(nullptr) {
     crash_reporter::ResetCrashKeysForTesting();
-    crash_reporter::InitializeCrashKeys();
+    crash_reporter::InitializeCrashKeysForTesting();
   }
 
   ~VariationsCrashKeysTest() override {
@@ -51,13 +51,7 @@
 
 }  // namespace
 
-// TODO(crbug.com/821162): Test fails on iOS. Re-enable after fixing.
-#if defined(OS_IOS)
-#define MAYBE_BasicFunctionality DISABLED_BasicFunctionality
-#else
-#define MAYBE_BasicFunctionality BasicFunctionality
-#endif
-TEST_F(VariationsCrashKeysTest, MAYBE_BasicFunctionality) {
+TEST_F(VariationsCrashKeysTest, BasicFunctionality) {
   SyntheticTrialRegistry registry;
   registry.AddSyntheticTrialObserver(
       SyntheticTrialsActiveGroupIdProvider::GetInstance());
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index d51b7cf..24b829372 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -238,8 +238,6 @@
 
   if (is_mac) {
     sources += [
-      "display_embedder/gl_output_surface_mac.cc",
-      "display_embedder/gl_output_surface_mac.h",
       "display_embedder/overlay_candidate_validator_mac.cc",
       "display_embedder/overlay_candidate_validator_mac.h",
       "display_embedder/software_output_device_mac.cc",
@@ -254,8 +252,6 @@
     sources += [
       "display_embedder/gl_output_surface_android.cc",
       "display_embedder/gl_output_surface_android.h",
-      "display_embedder/gl_output_surface_buffer_queue_android.cc",
-      "display_embedder/gl_output_surface_buffer_queue_android.h",
       "display_embedder/overlay_candidate_validator_android.cc",
       "display_embedder/overlay_candidate_validator_android.h",
       "display_embedder/overlay_candidate_validator_surface_control.cc",
@@ -271,8 +267,6 @@
 
   if (use_ozone) {
     sources += [
-      "display_embedder/gl_output_surface_ozone.cc",
-      "display_embedder/gl_output_surface_ozone.h",
       "display_embedder/overlay_candidate_validator_ozone.cc",
       "display_embedder/overlay_candidate_validator_ozone.h",
       "display_embedder/software_output_device_ozone.cc",
@@ -284,8 +278,6 @@
 
   if (is_win) {
     sources += [
-      "display_embedder/gl_output_surface_win.cc",
-      "display_embedder/gl_output_surface_win.h",
       "display_embedder/output_device_backing.cc",
       "display_embedder/output_device_backing.h",
       "display_embedder/overlay_candidate_validator_win.cc",
diff --git a/components/viz/service/DEPS b/components/viz/service/DEPS
index e546344..01b30d6 100644
--- a/components/viz/service/DEPS
+++ b/components/viz/service/DEPS
@@ -6,6 +6,8 @@
   "-components/viz/common/switches.h",
   "-components/viz/service",
   "+components/viz/service/viz_service_export.h",
+  "+gpu/config/gpu_feature_info.h",
+  "+gpu/ipc/common/surface_handle.h",
   "+services/viz/privileged/interfaces",
   "+services/viz/public/interfaces",
   "+third_party/skia",
diff --git a/components/viz/service/display/DEPS b/components/viz/service/display/DEPS
index 52f78f6..46f956add 100644
--- a/components/viz/service/display/DEPS
+++ b/components/viz/service/display/DEPS
@@ -8,6 +8,11 @@
   "+cc/resources",
   "+cc/scheduler",
   "+components/viz/service/surfaces",
+  "+components/viz/service/display_embedder/overlay_candidate_validator_android.h",
+  "+components/viz/service/display_embedder/overlay_candidate_validator_mac.h",
+  "+components/viz/service/display_embedder/overlay_candidate_validator_ozone.h",
+  "+components/viz/service/display_embedder/overlay_candidate_validator_surface_control.h",
+  "+components/viz/service/display_embedder/overlay_candidate_validator_win.h",
   "+gpu/command_buffer/client",
   "+gpu/command_buffer/common",
   "+gpu/GLES2",
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 5f6f05e..00a188f2 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -25,6 +25,7 @@
 #include "components/viz/service/display/bsp_tree.h"
 #include "components/viz/service/display/bsp_walk_action.h"
 #include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/display/overlay_candidate_validator.h"
 #include "ui/gfx/geometry/quad_f.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/transform.h"
@@ -115,8 +116,12 @@
 DirectRenderer::~DirectRenderer() = default;
 
 void DirectRenderer::Initialize() {
+  // Create overlay validator and set it. This would initialize the strategies
+  // on the validator as well.
+  gpu::SurfaceHandle surface_handle = output_surface_->GetSurfaceHandle();
   overlay_processor_->SetOverlayCandidateValidator(
-      output_surface_->TakeOverlayCandidateValidator());
+      OverlayCandidateValidator::Create(
+          surface_handle, output_surface_->context_provider(), *settings_));
 
   auto* context_provider = output_surface_->context_provider();
 
@@ -364,6 +369,10 @@
   overlay_processor_->SetDisplayTransformHint(
       output_surface_->GetDisplayTransform());
 
+  // Only used for pre-OOP-D code path.
+  // TODO(weiliangc): Remove once reflector code is removed.
+  overlay_processor_->SetSoftwareMirrorMode(
+      output_surface_->IsSoftwareMirrorMode());
   // Create the overlay candidate for the output surface, and mark it as
   // always handled.
   if (output_surface_->IsDisplayedAsOverlayPlane()) {
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 2b03c7f6..50d2cf2 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -2042,8 +2042,6 @@
   MOCK_METHOD0(GetFramebufferCopyTextureFormat, GLenum());
   MOCK_METHOD1(SwapBuffers_, void(OutputSurfaceFrame& frame));  // NOLINT
   void SwapBuffers(OutputSurfaceFrame frame) override { SwapBuffers_(frame); }
-  MOCK_METHOD0(TakeOverlayCandidateValidator,
-               std::unique_ptr<OverlayCandidateValidator>());
   MOCK_CONST_METHOD0(IsDisplayedAsOverlayPlane, bool());
   MOCK_CONST_METHOD0(GetOverlayTextureId, unsigned());
   MOCK_CONST_METHOD0(GetOverlayBufferFormat, gfx::BufferFormat());
@@ -2077,7 +2075,6 @@
         DisplayResourceProvider::kGpu, output_surface_->context_provider(),
         shared_bitmap_manager_.get());
 
-    EXPECT_CALL(*output_surface_, TakeOverlayCandidateValidator()).Times(1);
     renderer_.reset(new FakeRendererGL(&settings_, output_surface_.get(),
                                        resource_provider_.get()));
     renderer_->Initialize();
diff --git a/components/viz/service/display/output_surface.cc b/components/viz/service/display/output_surface.cc
index 8d11b16..6e51005e 100644
--- a/components/viz/service/display/output_surface.cc
+++ b/components/viz/service/display/output_surface.cc
@@ -39,6 +39,10 @@
   return nullptr;
 }
 
+gpu::SurfaceHandle OutputSurface::GetSurfaceHandle() const {
+  return gpu::kNullSurfaceHandle;
+}
+
 void OutputSurface::UpdateLatencyInfoOnSwap(
     const gfx::SwapResponse& response,
     std::vector<ui::LatencyInfo>* latency_info) {
@@ -69,4 +73,8 @@
   NOTREACHED();
 }
 
+// Only needs implementation for BrowserCompositorOutputSurface.
+bool OutputSurface::IsSoftwareMirrorMode() const {
+  return false;
+}
 }  // namespace viz
diff --git a/components/viz/service/display/output_surface.h b/components/viz/service/display/output_surface.h
index 8650a9f..1a42f8b 100644
--- a/components/viz/service/display/output_surface.h
+++ b/components/viz/service/display/output_surface.h
@@ -20,6 +20,7 @@
 #include "components/viz/service/display/software_output_device.h"
 #include "components/viz/service/viz_service_export.h"
 #include "gpu/command_buffer/common/texture_in_use_response.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "ui/gfx/color_space.h"
 #include "ui/latency/latency_info.h"
 
@@ -86,6 +87,9 @@
   }
   const SkMatrix44& color_matrix() const { return color_matrix_; }
 
+  // Only useful for GPU backend.
+  virtual gpu::SurfaceHandle GetSurfaceHandle() const;
+
   virtual void BindToClient(OutputSurfaceClient* client) = 0;
 
   virtual void EnsureBackbuffer() = 0;
@@ -99,10 +103,6 @@
   // framebuffer.
   virtual void SetDrawRectangle(const gfx::Rect& rect) = 0;
 
-  // Get the class capable of informing cc of hardware overlay capability.
-  virtual std::unique_ptr<OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() = 0;
-
   // Returns true if a main image overlay plane should be scheduled.
   virtual bool IsDisplayedAsOverlayPlane() const = 0;
 
@@ -170,6 +170,10 @@
 
   virtual base::ScopedClosureRunner GetCacheBackBufferCb();
 
+  // Only used for pre-OOP-D code path of BrowserCompositorOutputSurface.
+  // TODO(weiliangc): Remove it when reflector code is removed.
+  virtual bool IsSoftwareMirrorMode() const;
+
   // If set to true, the OutputSurface must deliver
   // OutputSurfaceclient::DidSwapWithSize notifications to its client.
   // OutputSurfaces which support delivering swap size notifications should
diff --git a/components/viz/service/display/overlay_candidate_validator.cc b/components/viz/service/display/overlay_candidate_validator.cc
index 179ba55..32ea7a7 100644
--- a/components/viz/service/display/overlay_candidate_validator.cc
+++ b/components/viz/service/display/overlay_candidate_validator.cc
@@ -5,8 +5,134 @@
 #include "components/viz/service/display/overlay_candidate_validator.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
+#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/gpu/context_provider.h"
+
+#if defined(OS_ANDROID)
+#include "components/viz/service/display_embedder/overlay_candidate_validator_android.h"
+#include "components/viz/service/display_embedder/overlay_candidate_validator_surface_control.h"
+#include "gpu/config/gpu_feature_info.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "components/viz/service/display_embedder/overlay_candidate_validator_mac.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/feature_list.h"
+#include "components/viz/service/display_embedder/overlay_candidate_validator_win.h"
+#include "gpu/config/gpu_finch_features.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "components/viz/service/display_embedder/overlay_candidate_validator_ozone.h"
+#include "ui/ozone/public/overlay_manager_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
+#endif
 
 namespace viz {
+namespace {
+
+#if defined(USE_OZONE)
+std::unique_ptr<OverlayCandidateValidatorOzone>
+CreateOverlayCandidateValidatorOzone(
+    gpu::SurfaceHandle surface_handle,
+    const RendererSettings& renderer_settings) {
+  if (renderer_settings.overlay_strategies.empty())
+    return nullptr;
+
+  auto* overlay_manager = ui::OzonePlatform::GetInstance()->GetOverlayManager();
+  std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates =
+      overlay_manager->CreateOverlayCandidates(surface_handle);
+  return std::make_unique<OverlayCandidateValidatorOzone>(
+      std::move(overlay_candidates),
+      std::move(renderer_settings.overlay_strategies));
+}
+#endif
+
+#if defined(OS_WIN)
+std::unique_ptr<OverlayCandidateValidatorWin>
+CreateOverlayCandidateValidatorWin(const ContextProvider* context_provider) {
+  DCHECK(context_provider);
+
+  const auto& capabilities = context_provider->ContextCapabilities();
+  const bool use_overlays_for_sw_protected_video = base::FeatureList::IsEnabled(
+      features::kUseDCOverlaysForSoftwareProtectedVideo);
+  const bool use_overlays =
+      capabilities.dc_layers && (capabilities.use_dc_overlays_for_video ||
+                                 use_overlays_for_sw_protected_video);
+
+  if (use_overlays) {
+    return std::make_unique<OverlayCandidateValidatorWin>();
+  } else {
+    return nullptr;
+  }
+}
+#endif
+
+#if defined(OS_ANDROID)
+std::unique_ptr<OverlayCandidateValidatorAndroid>
+CreateOverlayCandidateValidatorAndroid(
+    const ContextProvider* context_provider) {
+  DCHECK(context_provider);
+  // When SurfaceControl is enabled, any resource backed by an
+  // AHardwareBuffer can be marked as an overlay candidate but it requires
+  // that we use a SurfaceControl backed GLSurface. If we're creating a
+  // native window backed GLSurface, the overlay processing code will
+  // incorrectly assume these resources can be overlaid. So we disable all
+  // overlay processing for this OutputSurface.
+  const auto& gpu_feature_info = context_provider->GetGpuFeatureInfo();
+  const bool allow_overlays =
+      gpu_feature_info
+          .status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] !=
+      gpu::kGpuFeatureStatusEnabled;
+
+  if (allow_overlays) {
+    return std::make_unique<OverlayCandidateValidatorAndroid>();
+  } else {
+    return nullptr;
+  }
+}
+#endif
+}  // namespace
+
+std::unique_ptr<OverlayCandidateValidator> OverlayCandidateValidator::Create(
+    gpu::SurfaceHandle surface_handle,
+    const ContextProvider* context_provider,
+    const RendererSettings& renderer_settings) {
+  if (surface_handle == gpu::kNullSurfaceHandle)
+    return nullptr;
+
+  // TODO(weiliangc): Pass in GpuFeatureInfo and ContextCapabilities directly so
+  // this class can be used with SkiaRenderer where there is no context
+  // provider.
+  if (!context_provider)
+    return nullptr;
+
+  if (context_provider->ContextCapabilities().surfaceless) {
+#if defined(USE_OZONE)
+    return CreateOverlayCandidateValidatorOzone(surface_handle,
+                                                renderer_settings);
+#elif defined(OS_MACOSX)
+    return std::make_unique<OverlayCandidateValidatorMac>(
+        !renderer_settings.allow_overlays);
+#elif defined(OS_ANDROID)
+    return std::make_unique<OverlayCandidateValidatorSurfaceControl>();
+#else
+    NOTREACHED();
+#endif
+  } else {
+#if defined(OS_WIN)
+    return CreateOverlayCandidateValidatorWin(context_provider);
+#elif defined(OS_ANDROID)
+    return CreateOverlayCandidateValidatorAndroid(context_provider);
+#else
+    return nullptr;
+#endif
+  }
+  return nullptr;
+}
 
 OverlayCandidateValidator::OverlayCandidateValidator() = default;
 OverlayCandidateValidator::~OverlayCandidateValidator() = default;
diff --git a/components/viz/service/display/overlay_candidate_validator.h b/components/viz/service/display/overlay_candidate_validator.h
index 4fb3719..daf72d5 100644
--- a/components/viz/service/display/overlay_candidate_validator.h
+++ b/components/viz/service/display/overlay_candidate_validator.h
@@ -10,14 +10,20 @@
 #include "components/viz/service/display/overlay_candidate.h"
 #include "components/viz/service/display/overlay_processor.h"
 #include "components/viz/service/viz_service_export.h"
+#include "gpu/ipc/common/surface_handle.h"
 
 namespace viz {
+class RendererSettings;
+class ContextProvider;
 
 // This class that can be used to answer questions about possible overlay
 // configurations for a particular output device.
 class VIZ_SERVICE_EXPORT OverlayCandidateValidator {
  public:
-  OverlayCandidateValidator();
+  static std::unique_ptr<OverlayCandidateValidator> Create(
+      gpu::SurfaceHandle surface_handle,
+      const ContextProvider* context_provider,
+      const RendererSettings& renderer_settings);
   virtual ~OverlayCandidateValidator();
 
   // Populates a list of strategies that may work with this validator. Should be
@@ -69,6 +75,8 @@
       std::vector<gfx::Rect>* content_bounds) const;
 
  protected:
+  OverlayCandidateValidator();
+
   OverlayProcessor::StrategyList strategies_;
 };
 
diff --git a/components/viz/service/display/overlay_processor.cc b/components/viz/service/display/overlay_processor.cc
index 53a5308..505d6938 100644
--- a/components/viz/service/display/overlay_processor.cc
+++ b/components/viz/service/display/overlay_processor.cc
@@ -343,4 +343,8 @@
     overlay_validator_->SetViewportSize(size);
 }
 
+void OverlayProcessor::SetSoftwareMirrorMode(bool software_mirror_mode) {
+  if (overlay_validator_)
+    overlay_validator_->SetSoftwareMirrorMode(software_mirror_mode);
+}
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_processor.h b/components/viz/service/display/overlay_processor.h
index f8879ed..3eac218 100644
--- a/components/viz/service/display/overlay_processor.h
+++ b/components/viz/service/display/overlay_processor.h
@@ -61,6 +61,7 @@
       std::unique_ptr<OverlayCandidateValidator> overlay_validator);
 
   gfx::Rect GetAndResetOverlayDamage();
+  void SetSoftwareMirrorMode(bool software_mirror_mode);
 
   const OverlayCandidateValidator* GetOverlayCandidateValidator() const {
     return overlay_validator_.get();
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index aa35c88..a24866d 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -229,12 +229,6 @@
   }
   bool HasExternalStencilTest() const override { return false; }
   void ApplyExternalStencil() override {}
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override {
-    // TODO(weiliangc): Use the validator passed in on Setter directly, don't go
-    // through output surface. Delete this soon.
-    return nullptr;
-  }
   bool IsDisplayedAsOverlayPlane() const override {
     return is_displayed_as_overlay_plane_;
   }
diff --git a/components/viz/service/display_embedder/gl_output_surface.cc b/components/viz/service/display_embedder/gl_output_surface.cc
index a2bb276..b5b356b 100644
--- a/components/viz/service/display_embedder/gl_output_surface.cc
+++ b/components/viz/service/display_embedder/gl_output_surface.cc
@@ -25,9 +25,11 @@
 namespace viz {
 
 GLOutputSurface::GLOutputSurface(
-    scoped_refptr<VizProcessContextProvider> context_provider)
+    scoped_refptr<VizProcessContextProvider> context_provider,
+    gpu::SurfaceHandle surface_handle)
     : OutputSurface(context_provider),
       viz_context_provider_(context_provider),
+      surface_handle_(surface_handle),
       use_gpu_fence_(
           context_provider->ContextCapabilities().chromium_gpu_fence &&
           context_provider->ContextCapabilities()
@@ -134,11 +136,6 @@
   return gl->GetCopyTextureInternalFormat();
 }
 
-std::unique_ptr<OverlayCandidateValidator>
-GLOutputSurface::TakeOverlayCandidateValidator() {
-  return nullptr;
-}
-
 bool GLOutputSurface::IsDisplayedAsOverlayPlane() const {
   return false;
 }
@@ -242,4 +239,7 @@
   return viz_context_provider_->GetCacheBackBufferCb();
 }
 
+gpu::SurfaceHandle GLOutputSurface::GetSurfaceHandle() const {
+  return surface_handle_;
+}
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface.h b/components/viz/service/display_embedder/gl_output_surface.h
index 91a58a68..e50654b 100644
--- a/components/viz/service/display_embedder/gl_output_surface.h
+++ b/components/viz/service/display_embedder/gl_output_surface.h
@@ -19,8 +19,8 @@
 // swaps to an actual GL surface.
 class GLOutputSurface : public OutputSurface {
  public:
-  explicit GLOutputSurface(
-      scoped_refptr<VizProcessContextProvider> context_provider);
+  GLOutputSurface(scoped_refptr<VizProcessContextProvider> context_provider,
+                  gpu::SurfaceHandle surface_handle);
   ~GLOutputSurface() override;
 
   // OutputSurface implementation
@@ -36,8 +36,6 @@
                bool use_stencil) override;
   void SwapBuffers(OutputSurfaceFrame frame) override;
   uint32_t GetFramebufferCopyTextureFormat() override;
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
   bool IsDisplayedAsOverlayPlane() const override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
@@ -54,6 +52,8 @@
   gfx::OverlayTransform GetDisplayTransform() override;
   base::ScopedClosureRunner GetCacheBackBufferCb() override;
 
+  gpu::SurfaceHandle GetSurfaceHandle() const override;
+
  protected:
   OutputSurfaceClient* client() const { return client_; }
   ui::LatencyTracker* latency_tracker() { return &latency_tracker_; }
@@ -84,6 +84,8 @@
   bool wants_vsync_parameter_updates_ = false;
   ui::LatencyTracker latency_tracker_;
 
+  const gpu::SurfaceHandle surface_handle_;
+
   bool set_draw_rectangle_for_frame_ = false;
   // True if the draw rectangle has been set at all since the last resize.
   bool has_set_draw_rectangle_since_last_resize_ = false;
diff --git a/components/viz/service/display_embedder/gl_output_surface_android.cc b/components/viz/service/display_embedder/gl_output_surface_android.cc
index 6d056bb2..a83db0a6 100644
--- a/components/viz/service/display_embedder/gl_output_surface_android.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_android.cc
@@ -10,13 +10,8 @@
 
 GLOutputSurfaceAndroid::GLOutputSurfaceAndroid(
     scoped_refptr<VizProcessContextProvider> context_provider,
-    bool allow_overlays)
-    : GLOutputSurface(context_provider) {
-  if (allow_overlays) {
-    overlay_candidate_validator_ =
-        std::make_unique<OverlayCandidateValidatorAndroid>();
-  }
-}
+    gpu::SurfaceHandle surface_handle)
+    : GLOutputSurface(context_provider, surface_handle) {}
 
 GLOutputSurfaceAndroid::~GLOutputSurfaceAndroid() = default;
 
@@ -30,9 +25,4 @@
       flags, std::move(swap_callback), std::move(presentation_callback));
 }
 
-std::unique_ptr<OverlayCandidateValidator>
-GLOutputSurfaceAndroid::TakeOverlayCandidateValidator() {
-  return std::move(overlay_candidate_validator_);
-}
-
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_android.h b/components/viz/service/display_embedder/gl_output_surface_android.h
index 619597a2a..ca64829 100644
--- a/components/viz/service/display_embedder/gl_output_surface_android.h
+++ b/components/viz/service/display_embedder/gl_output_surface_android.h
@@ -10,13 +10,11 @@
 #include "components/viz/service/display_embedder/gl_output_surface.h"
 
 namespace viz {
-class OverlayCandidateValidator;
-
 class GLOutputSurfaceAndroid : public GLOutputSurface {
  public:
   GLOutputSurfaceAndroid(
       scoped_refptr<VizProcessContextProvider> context_provider,
-      bool allow_overlays);
+      gpu::SurfaceHandle surface_handle);
   ~GLOutputSurfaceAndroid() override;
 
   // GLOutputSurface implementation:
@@ -25,11 +23,6 @@
       uint32_t flags,
       gpu::ContextSupport::SwapCompletedCallback swap_callback,
       gpu::ContextSupport::PresentationCallback presentation_callback) override;
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
-
- private:
-  std::unique_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
 
   DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceAndroid);
 };
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
index 6f21e7ea..f03d47cb 100644
--- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
@@ -22,7 +22,7 @@
     gpu::SurfaceHandle surface_handle,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     gfx::BufferFormat buffer_format)
-    : GLOutputSurface(context_provider) {
+    : GLOutputSurface(context_provider, surface_handle) {
   capabilities_.uses_default_gl_framebuffer = false;
   capabilities_.flipped_output_surface = true;
   // Set |max_frames_pending| to 2 for buffer_queue, which aligns scheduling
@@ -122,6 +122,9 @@
 void GLOutputSurfaceBufferQueue::SetDisplayTransformHint(
     gfx::OverlayTransform transform) {
   display_transform_ = transform;
+
+  if (context_provider_)
+    context_provider_->ContextSupport()->SetDisplayTransform(transform);
 }
 
 gfx::OverlayTransform GLOutputSurfaceBufferQueue::GetDisplayTransform() {
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
deleted file mode 100644
index 35b48e88..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h"
-
-#include "components/viz/service/display/renderer_utils.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "ui/gl/color_space_utils.h"
-
-namespace viz {
-
-GLOutputSurfaceBufferQueueAndroid::GLOutputSurfaceBufferQueueAndroid(
-    scoped_refptr<VizProcessContextProvider> context_provider,
-    gpu::SurfaceHandle surface_handle,
-    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    gfx::BufferFormat buffer_format)
-    : GLOutputSurfaceBufferQueue(context_provider,
-                                 surface_handle,
-                                 gpu_memory_buffer_manager,
-                                 buffer_format) {
-  overlay_candidate_validator_ =
-      std::make_unique<OverlayCandidateValidatorSurfaceControl>();
-}
-
-GLOutputSurfaceBufferQueueAndroid::~GLOutputSurfaceBufferQueueAndroid() =
-    default;
-
-std::unique_ptr<OverlayCandidateValidator>
-GLOutputSurfaceBufferQueueAndroid::TakeOverlayCandidateValidator() {
-  return std::move(overlay_candidate_validator_);
-}
-
-void GLOutputSurfaceBufferQueueAndroid::SetDisplayTransformHint(
-    gfx::OverlayTransform transform) {
-  context_provider()->ContextSupport()->SetDisplayTransform(transform);
-  GLOutputSurfaceBufferQueue::SetDisplayTransformHint(transform);
-}
-
-void GLOutputSurfaceBufferQueueAndroid::Reshape(
-    const gfx::Size& size,
-    float device_scale_factor,
-    const gfx::ColorSpace& color_space,
-    bool has_alpha,
-    bool use_stencil) {
-  GLOutputSurfaceBufferQueue::Reshape(size, device_scale_factor, color_space,
-                                      has_alpha, use_stencil);
-}
-
-}  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h
deleted file mode 100644
index b624f0e4..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_ANDROID_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_ANDROID_H_
-
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
-#include "components/viz/service/display_embedder/overlay_candidate_validator_surface_control.h"
-#include "ui/gfx/buffer_types.h"
-
-namespace viz {
-
-class GLOutputSurfaceBufferQueueAndroid : public GLOutputSurfaceBufferQueue {
- public:
-  GLOutputSurfaceBufferQueueAndroid(
-      scoped_refptr<VizProcessContextProvider> context_provider,
-      gpu::SurfaceHandle surface_handle,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      gfx::BufferFormat buffer_format);
-  ~GLOutputSurfaceBufferQueueAndroid() override;
-
-  // OutputSurface implementation
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
-  void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
-  void Reshape(const gfx::Size& size,
-               float device_scale_factor,
-               const gfx::ColorSpace& color_space,
-               bool has_alpha,
-               bool use_stencil) override;
-
- private:
-  std::unique_ptr<OverlayCandidateValidatorSurfaceControl>
-      overlay_candidate_validator_;
-
-  DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceBufferQueueAndroid);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_ANDROID_H_
diff --git a/components/viz/service/display_embedder/gl_output_surface_mac.cc b/components/viz/service/display_embedder/gl_output_surface_mac.cc
deleted file mode 100644
index 3468474..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_mac.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2017 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/viz/service/display_embedder/gl_output_surface_mac.h"
-
-#include "gpu/GLES2/gl2extchromium.h"
-
-namespace viz {
-
-GLOutputSurfaceMac::GLOutputSurfaceMac(
-    scoped_refptr<VizProcessContextProvider> context_provider,
-    gpu::SurfaceHandle surface_handle,
-    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    bool allow_overlays)
-    : GLOutputSurfaceBufferQueue(context_provider,
-                                 surface_handle,
-                                 gpu_memory_buffer_manager,
-                                 gfx::BufferFormat::RGBA_8888),
-      overlay_validator_(new OverlayCandidateValidatorMac(!allow_overlays)) {}
-
-GLOutputSurfaceMac::~GLOutputSurfaceMac() {}
-
-std::unique_ptr<OverlayCandidateValidator>
-GLOutputSurfaceMac::TakeOverlayCandidateValidator() {
-  return std::move(overlay_validator_);
-}
-
-}  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_mac.h b/components/viz/service/display_embedder/gl_output_surface_mac.h
deleted file mode 100644
index f407c73..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_mac.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 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_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_MAC_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_MAC_H_
-
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
-#include "components/viz/service/display_embedder/overlay_candidate_validator_mac.h"
-
-namespace viz {
-
-class GLOutputSurfaceMac : public GLOutputSurfaceBufferQueue {
- public:
-  GLOutputSurfaceMac(scoped_refptr<VizProcessContextProvider> context_provider,
-                     gpu::SurfaceHandle surface_handle,
-                     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-                     bool allow_overlays);
-  ~GLOutputSurfaceMac() override;
-
- private:
-  // GLOutputSurface implementation:
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
-
-  std::unique_ptr<OverlayCandidateValidatorMac> overlay_validator_;
-
-  DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceMac);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_MAC_H_
diff --git a/components/viz/service/display_embedder/gl_output_surface_offscreen.cc b/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
index 8f4a44cf..6fe0bf1 100644
--- a/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
@@ -27,7 +27,7 @@
 
 GLOutputSurfaceOffscreen::GLOutputSurfaceOffscreen(
     scoped_refptr<VizProcessContextProvider> context_provider)
-    : GLOutputSurface(context_provider) {}
+    : GLOutputSurface(context_provider, gpu::kNullSurfaceHandle) {}
 
 GLOutputSurfaceOffscreen::~GLOutputSurfaceOffscreen() {
   DiscardBackbuffer();
diff --git a/components/viz/service/display_embedder/gl_output_surface_ozone.cc b/components/viz/service/display_embedder/gl_output_surface_ozone.cc
deleted file mode 100644
index 50d1a9b..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_ozone.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 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/viz/service/display_embedder/gl_output_surface_ozone.h"
-
-#include <utility>
-
-#include "components/viz/service/display_embedder/overlay_candidate_validator_ozone.h"
-#include "ui/display/types/display_snapshot.h"
-#include "ui/ozone/public/overlay_candidates_ozone.h"
-#include "ui/ozone/public/overlay_manager_ozone.h"
-#include "ui/ozone/public/ozone_platform.h"
-
-namespace viz {
-
-GLOutputSurfaceOzone::GLOutputSurfaceOzone(
-    scoped_refptr<VizProcessContextProvider> context_provider,
-    gpu::SurfaceHandle surface_handle,
-    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    std::vector<OverlayStrategy> strategies)
-    : GLOutputSurfaceBufferQueue(context_provider,
-                                 surface_handle,
-                                 gpu_memory_buffer_manager,
-                                 display::DisplaySnapshot::PrimaryFormat()) {
-  if (!strategies.empty()) {
-    auto* overlay_manager =
-        ui::OzonePlatform::GetInstance()->GetOverlayManager();
-    std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates =
-        overlay_manager->CreateOverlayCandidates(surface_handle);
-    overlay_candidate_validator_ =
-        std::make_unique<OverlayCandidateValidatorOzone>(
-            std::move(overlay_candidates), std::move(strategies));
-  }
-}
-
-GLOutputSurfaceOzone::~GLOutputSurfaceOzone() = default;
-
-std::unique_ptr<OverlayCandidateValidator>
-GLOutputSurfaceOzone::TakeOverlayCandidateValidator() {
-  return std::move(overlay_candidate_validator_);
-}
-
-}  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_ozone.h b/components/viz/service/display_embedder/gl_output_surface_ozone.h
deleted file mode 100644
index 4d75607..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_ozone.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 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_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OZONE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OZONE_H_
-
-#include <memory>
-#include <vector>
-
-#include "components/viz/common/display/overlay_strategy.h"
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
-
-namespace viz {
-
-class GLOutputSurfaceOzone : public GLOutputSurfaceBufferQueue {
- public:
-  // |strategies| is a list of overlay strategies that will be attempted. If the
-  // list is empty then there is no overlay support on this platform.
-  GLOutputSurfaceOzone(
-      scoped_refptr<VizProcessContextProvider> context_provider,
-      gpu::SurfaceHandle surface_handle,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      std::vector<OverlayStrategy> strategies);
-  ~GLOutputSurfaceOzone() override;
-
-  // OutputSurface implementation.
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
-
- private:
-  std::unique_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
-
-  DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceOzone);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OZONE_H_
diff --git a/components/viz/service/display_embedder/gl_output_surface_win.cc b/components/viz/service/display_embedder/gl_output_surface_win.cc
deleted file mode 100644
index 0e7b87b..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_win.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_win.h"
-
-#include "components/viz/service/display_embedder/overlay_candidate_validator_win.h"
-
-namespace viz {
-
-GLOutputSurfaceWin::GLOutputSurfaceWin(
-    scoped_refptr<VizProcessContextProvider> context_provider,
-    bool use_overlays)
-    : GLOutputSurface(context_provider) {
-  if (use_overlays) {
-    overlay_validator_ = std::make_unique<OverlayCandidateValidatorWin>();
-  }
-}
-
-GLOutputSurfaceWin::~GLOutputSurfaceWin() = default;
-
-std::unique_ptr<OverlayCandidateValidator>
-GLOutputSurfaceWin::TakeOverlayCandidateValidator() {
-  return std::move(overlay_validator_);
-}
-
-}  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_win.h b/components/viz/service/display_embedder/gl_output_surface_win.h
deleted file mode 100644
index 75391d1..0000000
--- a/components/viz/service/display_embedder/gl_output_surface_win.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_WIN_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_WIN_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-
-namespace viz {
-
-class OverlayCandidateValidatorWin;
-
-class GLOutputSurfaceWin : public GLOutputSurface {
- public:
-  GLOutputSurfaceWin(scoped_refptr<VizProcessContextProvider> context_provider,
-                     bool use_overlays);
-  ~GLOutputSurfaceWin() override;
-
-  // GLOutputSurface implementation:
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
-
- private:
-  std::unique_ptr<OverlayCandidateValidatorWin> overlay_validator_;
-
-  DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceWin);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_WIN_H_
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc
index c01f3bc..a7915a85 100644
--- a/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -15,6 +15,7 @@
 #include "components/viz/common/display/renderer_settings.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/service/display_embedder/gl_output_surface.h"
+#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
 #include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
@@ -37,17 +38,14 @@
 #include "ui/gl/init/gl_factory.h"
 
 #if defined(OS_WIN)
-#include "components/viz/service/display_embedder/gl_output_surface_win.h"
 #include "components/viz/service/display_embedder/software_output_device_win.h"
 #endif
 
 #if defined(OS_ANDROID)
 #include "components/viz/service/display_embedder/gl_output_surface_android.h"
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h"
 #endif
 
 #if defined(OS_MACOSX)
-#include "components/viz/service/display_embedder/gl_output_surface_mac.h"
 #include "components/viz/service/display_embedder/software_output_device_mac.h"
 #include "ui/base/cocoa/remote_layer_api.h"
 #endif
@@ -57,8 +55,8 @@
 #endif
 
 #if defined(USE_OZONE)
-#include "components/viz/service/display_embedder/gl_output_surface_ozone.h"
 #include "components/viz/service/display_embedder/software_output_device_ozone.h"
+#include "ui/display/types/display_snapshot.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/platform_window_surface.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
@@ -189,19 +187,19 @@
           std::move(context_provider));
     } else if (context_provider->ContextCapabilities().surfaceless) {
 #if defined(USE_OZONE)
-      output_surface = std::make_unique<GLOutputSurfaceOzone>(
+      output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
           std::move(context_provider), surface_handle,
           gpu_memory_buffer_manager_.get(),
-          renderer_settings.overlay_strategies);
+          display::DisplaySnapshot::PrimaryFormat());
 #elif defined(OS_MACOSX)
-      output_surface = std::make_unique<GLOutputSurfaceMac>(
+      output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
           std::move(context_provider), surface_handle,
-          gpu_memory_buffer_manager_.get(), renderer_settings.allow_overlays);
+          gpu_memory_buffer_manager_.get(), gfx::BufferFormat::RGBA_8888);
 #elif defined(OS_ANDROID)
       auto buffer_format = context_provider->UseRGB565PixelFormat()
                                ? gfx::BufferFormat::BGR_565
                                : gfx::BufferFormat::RGBA_8888;
-      output_surface = std::make_unique<GLOutputSurfaceBufferQueueAndroid>(
+      output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
           std::move(context_provider), surface_handle,
           gpu_memory_buffer_manager_.get(), buffer_format);
 #else
@@ -209,32 +207,14 @@
 #endif
     } else {
 #if defined(OS_WIN)
-      const auto& capabilities = context_provider->ContextCapabilities();
-      const bool use_overlays_for_sw_protected_video =
-          base::FeatureList::IsEnabled(
-              features::kUseDCOverlaysForSoftwareProtectedVideo);
-      const bool use_overlays =
-          capabilities.dc_layers && (capabilities.use_dc_overlays_for_video ||
-                                     use_overlays_for_sw_protected_video);
-      output_surface = std::make_unique<GLOutputSurfaceWin>(
-          std::move(context_provider), use_overlays);
+      output_surface = std::make_unique<GLOutputSurface>(
+          std::move(context_provider), surface_handle);
 #elif defined(OS_ANDROID)
-      // When SurfaceControl is enabled, any resource backed by an
-      // AHardwareBuffer can be marked as an overlay candidate but it requires
-      // that we use a SurfaceControl backed GLSurface. If we're creating a
-      // native window backed GLSurface, the overlay processing code will
-      // incorrectly assume these resources can be overlayed. So we disable all
-      // overlay processing for this OutputSurface.
-      const bool allow_overlays =
-          task_executor_->gpu_feature_info()
-              .status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] !=
-          gpu::kGpuFeatureStatusEnabled;
-
       output_surface = std::make_unique<GLOutputSurfaceAndroid>(
-          std::move(context_provider), allow_overlays);
+          std::move(context_provider), surface_handle);
 #else
-      output_surface =
-          std::make_unique<GLOutputSurface>(std::move(context_provider));
+      output_surface = std::make_unique<GLOutputSurface>(
+          std::move(context_provider), surface_handle);
 #endif
     }
   }
diff --git a/components/viz/service/display_embedder/overlay_candidate_validator_ozone.cc b/components/viz/service/display_embedder/overlay_candidate_validator_ozone.cc
index dd771bf..53870e28 100644
--- a/components/viz/service/display_embedder/overlay_candidate_validator_ozone.cc
+++ b/components/viz/service/display_embedder/overlay_candidate_validator_ozone.cc
@@ -12,7 +12,6 @@
 #include "components/viz/service/display/overlay_strategy_single_on_top.h"
 #include "components/viz/service/display/overlay_strategy_underlay.h"
 #include "components/viz/service/display/overlay_strategy_underlay_cast.h"
-#include "ui/ozone/public/overlay_candidates_ozone.h"
 
 namespace viz {
 
diff --git a/components/viz/service/display_embedder/overlay_candidate_validator_ozone.h b/components/viz/service/display_embedder/overlay_candidate_validator_ozone.h
index 929e8bc8..31567d4 100644
--- a/components/viz/service/display_embedder/overlay_candidate_validator_ozone.h
+++ b/components/viz/service/display_embedder/overlay_candidate_validator_ozone.h
@@ -13,10 +13,7 @@
 #include "components/viz/service/display/overlay_candidate_validator.h"
 #include "components/viz/service/viz_service_export.h"
 #include "ui/gfx/native_widget_types.h"
-
-namespace ui {
-class OverlayCandidatesOzone;
-}
+#include "ui/ozone/public/overlay_candidates_ozone.h"
 
 namespace viz {
 
diff --git a/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index 3cde312..403f3ca 100644
--- a/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -9,6 +9,7 @@
 #include "build/build_config.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "gpu/ipc/common/gpu_surface_lookup.h"
+#include "gpu/vulkan/vulkan_fence_helper.h"
 #include "gpu/vulkan/vulkan_implementation.h"
 #include "gpu/vulkan/vulkan_surface.h"
 #include "third_party/skia/include/core/SkSurface.h"
@@ -32,8 +33,11 @@
 
 SkiaOutputDeviceVulkan::~SkiaOutputDeviceVulkan() {
   scoped_write_.reset();
-  if (vulkan_surface_)
-    vulkan_surface_->Destroy();
+  if (vulkan_surface_) {
+    auto* fence_helper = context_provider_->GetDeviceQueue()->GetFenceHelper();
+    fence_helper->EnqueueVulkanObjectCleanupForSubmittedWork(
+        std::move(vulkan_surface_));
+  }
 }
 
 void SkiaOutputDeviceVulkan::Reshape(const gfx::Size& size,
diff --git a/components/viz/service/display_embedder/skia_output_surface_base.cc b/components/viz/service/display_embedder/skia_output_surface_base.cc
index 572c740a..dbf9b88 100644
--- a/components/viz/service/display_embedder/skia_output_surface_base.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_base.cc
@@ -52,12 +52,6 @@
   return GL_RGB;
 }
 
-std::unique_ptr<OverlayCandidateValidator>
-SkiaOutputSurfaceBase::TakeOverlayCandidateValidator() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return nullptr;
-}
-
 bool SkiaOutputSurfaceBase::IsDisplayedAsOverlayPlane() const {
   return false;
 }
diff --git a/components/viz/service/display_embedder/skia_output_surface_base.h b/components/viz/service/display_embedder/skia_output_surface_base.h
index 2f56ccce..9d08380 100644
--- a/components/viz/service/display_embedder/skia_output_surface_base.h
+++ b/components/viz/service/display_embedder/skia_output_surface_base.h
@@ -26,8 +26,6 @@
   void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
   void SwapBuffers(OutputSurfaceFrame frame) override;
   uint32_t GetFramebufferCopyTextureFormat() override;
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
   bool IsDisplayedAsOverlayPlane() const override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
diff --git a/components/viz/service/display_embedder/software_output_surface.cc b/components/viz/service/display_embedder/software_output_surface.cc
index 32da6ac6..31f360b 100644
--- a/components/viz/service/display_embedder/software_output_surface.cc
+++ b/components/viz/service/display_embedder/software_output_surface.cc
@@ -86,12 +86,6 @@
   return false;
 }
 
-std::unique_ptr<OverlayCandidateValidator>
-SoftwareOutputSurface::TakeOverlayCandidateValidator() {
-  // No overlay support in software compositing.
-  return nullptr;
-}
-
 unsigned SoftwareOutputSurface::GetOverlayTextureId() const {
   return 0;
 }
diff --git a/components/viz/service/display_embedder/software_output_surface.h b/components/viz/service/display_embedder/software_output_surface.h
index 8443642f..2fec3a2 100644
--- a/components/viz/service/display_embedder/software_output_surface.h
+++ b/components/viz/service/display_embedder/software_output_surface.h
@@ -37,8 +37,6 @@
                bool use_stencil) override;
   void SwapBuffers(OutputSurfaceFrame frame) override;
   bool IsDisplayedAsOverlayPlane() const override;
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
   bool HasExternalStencilTest() const override;
diff --git a/components/viz/test/fake_output_surface.cc b/components/viz/test/fake_output_surface.cc
index 2314d56..c924f0a 100644
--- a/components/viz/test/fake_output_surface.cc
+++ b/components/viz/test/fake_output_surface.cc
@@ -84,13 +84,6 @@
   return has_external_stencil_test_;
 }
 
-std::unique_ptr<OverlayCandidateValidator>
-FakeOutputSurface::TakeOverlayCandidateValidator() {
-  // TODO(weiliangc): Validators are set on tests explicitly. Use the validator
-  // where they are created. Don't pass it in. This should be removed soon.
-  return nullptr;
-}
-
 gfx::BufferFormat FakeOutputSurface::GetOverlayBufferFormat() const {
   return gfx::BufferFormat::RGBX_8888;
 }
diff --git a/components/viz/test/fake_output_surface.h b/components/viz/test/fake_output_surface.h
index 83611d3f..caa2799 100644
--- a/components/viz/test/fake_output_surface.h
+++ b/components/viz/test/fake_output_surface.h
@@ -70,8 +70,6 @@
   uint32_t GetFramebufferCopyTextureFormat() override;
   bool HasExternalStencilTest() const override;
   void ApplyExternalStencil() override {}
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
   bool IsDisplayedAsOverlayPlane() const override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
diff --git a/components/viz/test/fake_skia_output_surface.cc b/components/viz/test/fake_skia_output_surface.cc
index 9076ad7..29a18daf 100644
--- a/components/viz/test/fake_skia_output_surface.cc
+++ b/components/viz/test/fake_skia_output_surface.cc
@@ -87,12 +87,6 @@
   return GL_RGB;
 }
 
-std::unique_ptr<OverlayCandidateValidator>
-FakeSkiaOutputSurface::TakeOverlayCandidateValidator() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return nullptr;
-}
-
 bool FakeSkiaOutputSurface::IsDisplayedAsOverlayPlane() const {
   return false;
 }
diff --git a/components/viz/test/fake_skia_output_surface.h b/components/viz/test/fake_skia_output_surface.h
index 0ea18c6..b01aa3c 100644
--- a/components/viz/test/fake_skia_output_surface.h
+++ b/components/viz/test/fake_skia_output_surface.h
@@ -50,8 +50,6 @@
                bool use_stencil) override;
   void SwapBuffers(OutputSurfaceFrame frame) override;
   uint32_t GetFramebufferCopyTextureFormat() override;
-  std::unique_ptr<OverlayCandidateValidator> TakeOverlayCandidateValidator()
-      override;
   bool IsDisplayedAsOverlayPlane() const override;
   unsigned GetOverlayTextureId() const override;
   gfx::BufferFormat GetOverlayBufferFormat() const override;
diff --git a/components/wifi/OWNERS b/components/wifi/OWNERS
index db8bbdcdcf7..fb59c70 100644
--- a/components/wifi/OWNERS
+++ b/components/wifi/OWNERS
@@ -1 +1 @@
-mef@chromium.org
+file://net/OWNERS
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 275413c..fec6c78 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -755,7 +755,7 @@
 #endif
 
     RegisterPathProvider();
-    RegisterContentSchemes(true);
+    RegisterContentSchemes(delegate_->ShouldLockSchemeRegistry());
 
 #if defined(OS_ANDROID) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
     int icudata_fd = g_fds->MaybeGet(kAndroidICUDataDescriptor);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index e19a600..54df002 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1194,6 +1194,8 @@
     "loader/upload_data_stream_builder.h",
     "loader/url_loader_factory_impl.cc",
     "loader/url_loader_factory_impl.h",
+    "loader/webrtc_connections_observer.cc",
+    "loader/webrtc_connections_observer.h",
     "loader_delegate_impl.cc",
     "loader_delegate_impl.h",
     "locks/lock_manager.cc",
@@ -1959,6 +1961,7 @@
     "web_package/signed_exchange_validity_pinger.h",
     "webrtc/webrtc_internals.cc",
     "webrtc/webrtc_internals.h",
+    "webrtc/webrtc_internals_connections_observer.h",
     "webrtc/webrtc_internals_message_handler.cc",
     "webrtc/webrtc_internals_message_handler.h",
     "webrtc/webrtc_internals_ui.cc",
diff --git a/content/browser/compositor/browser_compositor_output_surface.cc b/content/browser/compositor/browser_compositor_output_surface.cc
index 0942954..5a373ac 100644
--- a/content/browser/compositor/browser_compositor_output_surface.cc
+++ b/content/browser/compositor/browser_compositor_output_surface.cc
@@ -12,18 +12,14 @@
 #include "base/strings/string_number_conversions.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/service/display/output_surface_client.h"
-#include "components/viz/service/display/overlay_candidate_validator.h"
 #include "content/browser/compositor/reflector_impl.h"
 #include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
 
 namespace content {
 
 BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
-    scoped_refptr<viz::ContextProvider> context_provider,
-    std::unique_ptr<viz::OverlayCandidateValidator> overlay_candidate_validator)
-    : OutputSurface(std::move(context_provider)) {
-  overlay_candidate_validator_ = std::move(overlay_candidate_validator);
-}
+    scoped_refptr<viz::ContextProvider> context_provider)
+    : OutputSurface(std::move(context_provider)) {}
 
 BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
     std::unique_ptr<viz::SoftwareOutputDevice> software_device)
@@ -44,11 +40,6 @@
 void BrowserCompositorOutputSurface::OnReflectorChanged() {
 }
 
-std::unique_ptr<viz::OverlayCandidateValidator>
-BrowserCompositorOutputSurface::TakeOverlayCandidateValidator() {
-  return std::move(overlay_candidate_validator_);
-}
-
 bool BrowserCompositorOutputSurface::HasExternalStencilTest() const {
   return false;
 }
@@ -64,4 +55,7 @@
   return gfx::OVERLAY_TRANSFORM_NONE;
 }
 
+bool BrowserCompositorOutputSurface::IsSoftwareMirrorMode() const {
+  return reflector_ != nullptr;
+}
 }  // namespace content
diff --git a/content/browser/compositor/browser_compositor_output_surface.h b/content/browser/compositor/browser_compositor_output_surface.h
index c91aedd..b8847a6 100644
--- a/content/browser/compositor/browser_compositor_output_surface.h
+++ b/content/browser/compositor/browser_compositor_output_surface.h
@@ -15,10 +15,6 @@
 class SoftwareOutputDevice;
 }
 
-namespace viz {
-class OverlayCandidateValidator;
-}
-
 namespace gfx {
 enum class SwapResult;
 }
@@ -32,8 +28,6 @@
   ~BrowserCompositorOutputSurface() override;
 
   // viz::OutputSurface implementation.
-  std::unique_ptr<viz::OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() override;
   bool HasExternalStencilTest() const override;
   void ApplyExternalStencil() override;
   void SetUpdateVSyncParametersCallback(
@@ -41,6 +35,7 @@
   void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
   gfx::OverlayTransform GetDisplayTransform() override;
 
+  bool IsSoftwareMirrorMode() const override;
   void SetReflector(ReflectorImpl* reflector);
 
   // Called when |reflector_| was updated.
@@ -48,9 +43,7 @@
 
  protected:
   // Constructor used by the accelerated implementation.
-  BrowserCompositorOutputSurface(scoped_refptr<viz::ContextProvider> context,
-                                 std::unique_ptr<viz::OverlayCandidateValidator>
-                                     overlay_candidate_validator);
+  BrowserCompositorOutputSurface(scoped_refptr<viz::ContextProvider> context);
 
   // Constructor used by the software implementation.
   explicit BrowserCompositorOutputSurface(
@@ -59,9 +52,6 @@
   viz::UpdateVSyncParametersCallback update_vsync_parameters_callback_;
   ReflectorImpl* reflector_ = nullptr;
 
- private:
-  std::unique_ptr<viz::OverlayCandidateValidator> overlay_candidate_validator_;
-
   DISALLOW_COPY_AND_ASSIGN(BrowserCompositorOutputSurface);
 };
 
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
index 15c1b4de..53ca7c36 100644
--- a/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -10,7 +10,6 @@
 #include "build/build_config.h"
 #include "components/viz/service/display/output_surface_client.h"
 #include "components/viz/service/display/output_surface_frame.h"
-#include "components/viz/service/display/overlay_candidate_validator.h"
 #include "content/browser/compositor/reflector_impl.h"
 #include "content/browser/compositor/reflector_texture.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -25,10 +24,8 @@
 namespace content {
 
 GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface(
-    scoped_refptr<viz::ContextProviderCommandBuffer> context,
-    std::unique_ptr<viz::OverlayCandidateValidator> overlay_candidate_validator)
-    : BrowserCompositorOutputSurface(std::move(context),
-                                     std::move(overlay_candidate_validator)),
+    scoped_refptr<viz::ContextProviderCommandBuffer> context)
+    : BrowserCompositorOutputSurface(std::move(context)),
       weak_ptr_factory_(this) {
   if (capabilities_.uses_default_gl_framebuffer) {
     capabilities_.flipped_output_surface =
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.h b/content/browser/compositor/gpu_browser_compositor_output_surface.h
index 76a22bc..ab5ffc7 100644
--- a/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -13,10 +13,6 @@
 #include "ui/gfx/swap_result.h"
 #include "ui/latency/latency_tracker.h"
 
-namespace viz {
-class OverlayCandidateValidator;
-}
-
 namespace gfx {
 struct PresentationFeedback;
 }
@@ -40,9 +36,7 @@
     : public BrowserCompositorOutputSurface {
  public:
   GpuBrowserCompositorOutputSurface(
-      scoped_refptr<viz::ContextProviderCommandBuffer> context,
-      std::unique_ptr<viz::OverlayCandidateValidator>
-          overlay_candidate_validator);
+      scoped_refptr<viz::ContextProviderCommandBuffer> context);
 
   ~GpuBrowserCompositorOutputSurface() override;
 
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 757011d..e379b84 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -33,7 +33,6 @@
 #include "components/viz/host/renderer_settings_creation.h"
 #include "components/viz/service/display/display.h"
 #include "components/viz/service/display/display_scheduler.h"
-#include "components/viz/service/display/overlay_candidate_validator.h"
 #include "components/viz/service/display_embedder/compositing_mode_reporter_impl.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/display_embedder/vsync_parameter_listener.h"
@@ -77,7 +76,6 @@
 #include "ui/gl/gl_switches.h"
 
 #if defined(USE_OZONE)
-#include "components/viz/service/display_embedder/overlay_candidate_validator_ozone.h"
 #include "components/viz/service/display_embedder/software_output_device_ozone.h"
 #include "ui/ozone/public/overlay_candidates_ozone.h"
 #include "ui/ozone/public/overlay_manager_ozone.h"
@@ -149,12 +147,6 @@
 struct GpuProcessTransportFactory::PerCompositorData {
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   BrowserCompositorOutputSurface* display_output_surface = nullptr;
-  // The |overlay_validator| pointer is used to pass settings for software
-  // mirror mode. The lifetime of the validator is the same as the
-  // |display_output_surface|.
-  // TODO(weiliangc): Remove this once software mirroring code path does not
-  // have to go though validator.
-  viz::OverlayCandidateValidator* overlay_validator = nullptr;
   // Exactly one of |synthetic_begin_frame_source| and
   // |external_begin_frame_source| is valid at the same time.
   std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source;
@@ -243,34 +235,6 @@
 #endif
 }
 
-std::unique_ptr<viz::OverlayCandidateValidator> CreateOverlayCandidateValidator(
-    gfx::AcceleratedWidget widget) {
-  std::unique_ptr<viz::OverlayCandidateValidator> validator;
-#if defined(USE_OZONE)
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
-  std::string enable_overlay_flag =
-      command_line->GetSwitchValueASCII(switches::kEnableHardwareOverlays);
-
-  ui::OzonePlatform* ozone_platform = ui::OzonePlatform::GetInstance();
-  DCHECK(ozone_platform);
-  auto& host_properties = ozone_platform->GetInitializedHostProperties();
-  if (!command_line->HasSwitch(switches::kEnableHardwareOverlays) &&
-      host_properties.supports_overlays) {
-    enable_overlay_flag = "single-fullscreen,single-on-top,underlay";
-  }
-  if (!enable_overlay_flag.empty()) {
-    std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates =
-        ozone_platform->GetOverlayManager()->CreateOverlayCandidates(widget);
-    validator.reset(new viz::OverlayCandidateValidatorOzone(
-        std::move(overlay_candidates),
-        viz::ParseOverlayStategies(enable_overlay_flag)));
-  }
-#endif
-
-  return validator;
-}
-
 void GpuProcessTransportFactory::CreateLayerTreeFrameSink(
     base::WeakPtr<ui::Compositor> compositor) {
   DCHECK(!!compositor);
@@ -282,7 +246,6 @@
     // |data->begin_frame_source| here when the compositor destroys its
     // LayerTreeFrameSink before calling back here.
     data->display_output_surface = nullptr;
-    data->overlay_validator = nullptr;
   }
 
   const bool use_gpu_compositing =
@@ -408,7 +371,6 @@
   }
 
   std::unique_ptr<BrowserCompositorOutputSurface> display_output_surface;
-  viz::OverlayCandidateValidator* overlay_validator = nullptr;
   if (!use_gpu_compositing) {
     if (!is_gpu_compositing_disabled_ &&
         !compositor->force_software_compositor()) {
@@ -429,39 +391,29 @@
     if (data->surface_handle == gpu::kNullSurfaceHandle) {
       display_output_surface =
           std::make_unique<OffscreenBrowserCompositorOutputSurface>(
-              context_provider,
-              std::unique_ptr<viz::OverlayCandidateValidator>());
+              context_provider);
     } else if (capabilities.surfaceless) {
       DCHECK(capabilities.texture_format_bgra8888);
-      auto validator = CreateOverlayCandidateValidator(compositor->widget());
-      overlay_validator = validator.get();
       auto gpu_output_surface =
           std::make_unique<GpuSurfacelessBrowserCompositorOutputSurface>(
-              context_provider, data->surface_handle, std::move(validator),
+              context_provider, data->surface_handle,
               display::DisplaySnapshot::PrimaryFormat(),
               GetGpuMemoryBufferManager());
       display_output_surface = std::move(gpu_output_surface);
     } else {
-      std::unique_ptr<viz::OverlayCandidateValidator> validator =
-          CreateOverlayCandidateValidator(compositor->widget());
-      overlay_validator = validator.get();
       auto gpu_output_surface =
-          std::make_unique<GpuBrowserCompositorOutputSurface>(
-              context_provider, std::move(validator));
+          std::make_unique<GpuBrowserCompositorOutputSurface>(context_provider);
       display_output_surface = std::move(gpu_output_surface);
     }
   }
 
-  data->overlay_validator = overlay_validator;
-
   auto vsync_callback = base::BindRepeating(
       &ui::Compositor::SetDisplayVSyncParameters, compositor);
   display_output_surface->SetUpdateVSyncParametersCallback(vsync_callback);
 
   data->display_output_surface = display_output_surface.get();
   if (data->reflector) {
-    data->reflector->OnSourceSurfaceReady(data->display_output_surface,
-                                          data->overlay_validator);
+    data->reflector->OnSourceSurfaceReady(data->display_output_surface);
   }
 
   std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_begin_frame_source;
@@ -607,8 +559,7 @@
       new ReflectorImpl(source_compositor, target_layer));
   source_data->reflector = reflector.get();
   if (auto* source_surface = source_data->display_output_surface) {
-    reflector->OnSourceSurfaceReady(source_surface,
-                                    source_data->overlay_validator);
+    reflector->OnSourceSurfaceReady(source_surface);
   }
   return std::move(reflector);
 }
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
index 69464e15..f38ece2 100644
--- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -22,18 +22,16 @@
     GpuSurfacelessBrowserCompositorOutputSurface(
         scoped_refptr<viz::ContextProviderCommandBuffer> context,
         gpu::SurfaceHandle surface_handle,
-        std::unique_ptr<viz::OverlayCandidateValidator>
-            overlay_candidate_validator,
         gfx::BufferFormat format,
         gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
-    : GpuBrowserCompositorOutputSurface(std::move(context),
-                                        std::move(overlay_candidate_validator)),
+    : GpuBrowserCompositorOutputSurface(std::move(context)),
       use_gpu_fence_(
           context_provider_->ContextCapabilities().chromium_gpu_fence &&
           context_provider_->ContextCapabilities()
               .use_gpu_fences_for_overlay_planes),
       gpu_fence_id_(0),
-      gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {
+      gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+      surface_handle_(surface_handle) {
   capabilities_.uses_default_gl_framebuffer = false;
   capabilities_.flipped_output_surface = true;
   // Set |max_frames_pending| to 2 for surfaceless, which aligns scheduling
@@ -149,4 +147,8 @@
   buffer_queue_->CopyDamageForCurrentSurface(damage);
 }
 
+gpu::SurfaceHandle
+GpuSurfacelessBrowserCompositorOutputSurface::GetSurfaceHandle() const {
+  return surface_handle_;
+}
 }  // namespace content
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
index 639d10e7..d7bc2e04 100644
--- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
+++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -27,8 +27,6 @@
   GpuSurfacelessBrowserCompositorOutputSurface(
       scoped_refptr<viz::ContextProviderCommandBuffer> context,
       gpu::SurfaceHandle surface_handle,
-      std::unique_ptr<viz::OverlayCandidateValidator>
-          overlay_candidate_validator,
       gfx::BufferFormat format,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
   ~GpuSurfacelessBrowserCompositorOutputSurface() override;
@@ -47,6 +45,7 @@
   gfx::BufferFormat GetOverlayBufferFormat() const override;
   unsigned UpdateGpuFence() override;
   void SetDrawRectangle(const gfx::Rect& damage) override;
+  gpu::SurfaceHandle GetSurfaceHandle() const override;
 
   // BrowserCompositorOutputSurface implementation.
   void OnGpuSwapBuffersCompleted(
@@ -61,6 +60,7 @@
 
   std::unique_ptr<viz::BufferQueue> buffer_queue_;
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+  gpu::SurfaceHandle surface_handle_;
 };
 
 }  // namespace content
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
index befb6bd..84e6d6f 100644
--- a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -31,11 +31,8 @@
 
 OffscreenBrowserCompositorOutputSurface::
     OffscreenBrowserCompositorOutputSurface(
-        scoped_refptr<viz::ContextProviderCommandBuffer> context,
-        std::unique_ptr<viz::OverlayCandidateValidator>
-            overlay_candidate_validator)
-    : BrowserCompositorOutputSurface(std::move(context),
-                                     std::move(overlay_candidate_validator)),
+        scoped_refptr<viz::ContextProviderCommandBuffer> context)
+    : BrowserCompositorOutputSurface(std::move(context)),
       weak_ptr_factory_(this) {
   capabilities_.uses_default_gl_framebuffer = false;
 }
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.h b/content/browser/compositor/offscreen_browser_compositor_output_surface.h
index 29fdcaa..4a96855d 100644
--- a/content/browser/compositor/offscreen_browser_compositor_output_surface.h
+++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.h
@@ -28,9 +28,7 @@
     : public BrowserCompositorOutputSurface {
  public:
   OffscreenBrowserCompositorOutputSurface(
-      scoped_refptr<viz::ContextProviderCommandBuffer> context,
-      std::unique_ptr<viz::OverlayCandidateValidator>
-          overlay_candidate_validator);
+      scoped_refptr<viz::ContextProviderCommandBuffer> context);
 
   ~OffscreenBrowserCompositorOutputSurface() override;
 
diff --git a/content/browser/compositor/reflector_impl.cc b/content/browser/compositor/reflector_impl.cc
index a74a3d7b..873f229 100644
--- a/content/browser/compositor/reflector_impl.cc
+++ b/content/browser/compositor/reflector_impl.cc
@@ -6,7 +6,6 @@
 
 #include "base/location.h"
 #include "components/viz/common/resources/transferable_resource.h"
-#include "components/viz/service/display/overlay_candidate_validator.h"
 #include "content/browser/compositor/browser_compositor_output_surface.h"
 #include "content/browser/compositor/owned_mailbox.h"
 #include "third_party/khronos/GLES2/gl2.h"
@@ -25,7 +24,6 @@
                              ui::Layer* mirroring_layer)
     : mirrored_compositor_(mirrored_compositor),
       flip_texture_(false),
-      overlay_validator_(nullptr),
       output_surface_(nullptr) {
   if (mirroring_layer)
     AddMirroringLayer(mirroring_layer);
@@ -43,19 +41,15 @@
 void ReflectorImpl::DetachFromOutputSurface() {
   DCHECK(output_surface_);
   output_surface_->SetReflector(nullptr);
-  if (overlay_validator_)
-    overlay_validator_->SetSoftwareMirrorMode(false);
   DCHECK(mailbox_);
   mailbox_.reset();
   output_surface_ = nullptr;
-  overlay_validator_ = nullptr;
   for (const auto& layer_data : mirroring_layers_)
     layer_data->layer->SetShowSolidColorContent();
 }
 
 void ReflectorImpl::OnSourceSurfaceReady(
-    BrowserCompositorOutputSurface* output_surface,
-    viz::OverlayCandidateValidator* overlay_validator) {
+    BrowserCompositorOutputSurface* output_surface) {
   if (mirroring_layers_.empty())
     return;  // Was already Shutdown().
   if (output_surface == output_surface_)
@@ -64,13 +58,10 @@
     DetachFromOutputSurface();
 
   output_surface_ = output_surface;
-  overlay_validator_ = overlay_validator;
 
   flip_texture_ = !output_surface->capabilities().flipped_output_surface;
 
   output_surface_->SetReflector(this);
-  if (overlay_validator_)
-    overlay_validator_->SetSoftwareMirrorMode(true);
 }
 
 void ReflectorImpl::OnMirroringCompositorResized() {
diff --git a/content/browser/compositor/reflector_impl.h b/content/browser/compositor/reflector_impl.h
index 4ba31e0f..a603b07 100644
--- a/content/browser/compositor/reflector_impl.h
+++ b/content/browser/compositor/reflector_impl.h
@@ -23,10 +23,6 @@
 class Layer;
 }
 
-namespace viz {
-class OverlayCandidateValidator;
-}
-
 namespace content {
 
 class OwnedMailbox;
@@ -61,8 +57,7 @@
                              const gfx::Size& surface_size);
 
   // Called when the source surface is bound and available.
-  void OnSourceSurfaceReady(BrowserCompositorOutputSurface* surface,
-                            viz::OverlayCandidateValidator* overlay_validator);
+  void OnSourceSurfaceReady(BrowserCompositorOutputSurface* surface);
 
   // Called when the mailbox which has the source surface's texture
   // is updated.
@@ -82,7 +77,6 @@
 
   scoped_refptr<OwnedMailbox> mailbox_;
   bool flip_texture_;
-  viz::OverlayCandidateValidator* overlay_validator_;
   BrowserCompositorOutputSurface* output_surface_;
 
   DISALLOW_COPY_AND_ASSIGN(ReflectorImpl);
diff --git a/content/browser/compositor/reflector_impl_unittest.cc b/content/browser/compositor/reflector_impl_unittest.cc
index 0892cf1..c5f9e48 100644
--- a/content/browser/compositor/reflector_impl_unittest.cc
+++ b/content/browser/compositor/reflector_impl_unittest.cc
@@ -78,7 +78,7 @@
 class TestOutputSurface : public BrowserCompositorOutputSurface {
  public:
   TestOutputSurface(scoped_refptr<viz::ContextProvider> context_provider)
-      : BrowserCompositorOutputSurface(std::move(context_provider), nullptr) {}
+      : BrowserCompositorOutputSurface(std::move(context_provider)) {}
 
   void SetFlip(bool flip) { capabilities_.flipped_output_surface = flip; }
 
@@ -146,7 +146,12 @@
     context_provider->BindToCurrentThread();
     output_surface_ =
         std::make_unique<TestOutputSurface>(std::move(context_provider));
-    overlay_validator_ = CreateTestValidatorOzone();
+    overlay_processor_ = std::make_unique<viz::OverlayProcessor>(
+        output_surface_->context_provider());
+    auto overlay_validator = CreateTestValidatorOzone();
+    overlay_validator_ = overlay_validator.get();
+    overlay_processor_->SetOverlayCandidateValidator(
+        std::move(overlay_validator));
 
     root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
     compositor_->SetRootLayer(root_layer_.get());
@@ -160,8 +165,7 @@
   void SetUpReflector() {
     reflector_ = std::make_unique<ReflectorImpl>(compositor_.get(),
                                                  mirroring_layer_.get());
-    reflector_->OnSourceSurfaceReady(output_surface_.get(),
-                                     overlay_validator_.get());
+    reflector_->OnSourceSurfaceReady(output_surface_.get());
   }
 
   void TearDown() override {
@@ -183,7 +187,9 @@
   }
 
 #if defined(USE_OZONE)
-  void CheckOverlaySupport(viz::OverlayCandidateList* surfaces) {
+  void ProcessForOverlays(viz::OverlayCandidateList* surfaces) {
+    overlay_processor_->SetSoftwareMirrorMode(
+        output_surface_->IsSoftwareMirrorMode());
     overlay_validator_->CheckOverlaySupport(surfaces);
   }
 #endif  // defined(USE_OZONE)
@@ -199,7 +205,8 @@
   std::unique_ptr<ui::Layer> mirroring_layer_;
   std::unique_ptr<ReflectorImpl> reflector_;
   std::unique_ptr<TestOutputSurface> output_surface_;
-  std::unique_ptr<viz::OverlayCandidateValidator> overlay_validator_;
+  std::unique_ptr<viz::OverlayProcessor> overlay_processor_;
+  viz::OverlayCandidateValidator* overlay_validator_;
 };
 
 namespace {
@@ -241,7 +248,7 @@
   plane_2.plane_z_order = 1;
   list.push_back(plane_1);
   list.push_back(plane_2);
-  CheckOverlaySupport(&list);
+  ProcessForOverlays(&list);
   EXPECT_TRUE(list[0].overlay_handled);
 }
 
@@ -257,7 +264,7 @@
   plane_2.plane_z_order = 1;
   list.push_back(plane_1);
   list.push_back(plane_2);
-  CheckOverlaySupport(&list);
+  ProcessForOverlays(&list);
   EXPECT_FALSE(list[0].overlay_handled);
 }
 #endif  // defined(USE_OZONE)
diff --git a/content/browser/devtools/protocol/webauthn_handler.cc b/content/browser/devtools/protocol/webauthn_handler.cc
index 1f800087..71ddde2 100644
--- a/content/browser/devtools/protocol/webauthn_handler.cc
+++ b/content/browser/devtools/protocol/webauthn_handler.cc
@@ -108,6 +108,8 @@
           ? device::AuthenticatorAttachment::kPlatform
           : device::AuthenticatorAttachment::kCrossPlatform,
       options->GetHasResidentKey(), options->GetHasUserVerification());
+  authenticator->SetUserPresence(
+      options->GetAutomaticPresenceSimulation(true /* default */));
 
   *out_authenticator_id = authenticator->unique_id();
   return Response::OK();
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 9738331..0594a4d 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -127,6 +127,9 @@
   // |connection| can be null if all connections were closed (see ForceClose).
   virtual void OnConnectionClosed(IndexedDBConnection* connection) = 0;
 
+  // Called when the transaction should be bound.
+  virtual void CreateAndBindTransaction() = 0;
+
   // Called when the upgrade transaction has started executing.
   virtual void UpgradeTransactionStarted(int64_t old_version) = 0;
 
@@ -307,8 +310,9 @@
         blink::mojom::IDBTransactionMode::VersionChange,
         new IndexedDBBackingStore::Transaction(db_->backing_store()));
 
-    std::move(pending_->create_transaction_callback)
-        .Run(transaction->AsWeakPtr());
+    // Save a WeakPtr<IndexedDBTransaction> for the CreateAndBindTransaction
+    // function to use later.
+    pending_->transaction = transaction->AsWeakPtr();
 
     transaction->ScheduleTask(BindWeakOperation(
         &IndexedDBDatabase::VersionChangeOperation, db_->AsWeakPtr(),
@@ -317,6 +321,13 @@
     transaction->Start();
   }
 
+  void CreateAndBindTransaction() override {
+    if (pending_->create_transaction_callback && pending_->transaction) {
+      std::move(pending_->create_transaction_callback)
+          .Run(std::move(pending_->transaction));
+    }
+  }
+
   // Called when the upgrade transaction has started executing.
   void UpgradeTransactionStarted(int64_t old_version) override {
     DCHECK(connection_);
@@ -426,6 +437,8 @@
     db_->RequestComplete(this);
   }
 
+  void CreateAndBindTransaction() override { NOTREACHED(); }
+
   void UpgradeTransactionStarted(int64_t old_version) override { NOTREACHED(); }
 
   void UpgradeTransactionFinished(bool committed) override { NOTREACHED(); }
@@ -2067,6 +2080,7 @@
       base::BindOnce(&IndexedDBDatabase::VersionChangeAbortOperation,
                      AsWeakPtr(), old_version));
 
+  active_request_->CreateAndBindTransaction();
   active_request_->UpgradeTransactionStarted(old_version);
   return Status::OK();
 }
diff --git a/content/browser/indexed_db/indexed_db_pending_connection.h b/content/browser/indexed_db/indexed_db_pending_connection.h
index 5d1b8946..fd61559 100644
--- a/content/browser/indexed_db/indexed_db_pending_connection.h
+++ b/content/browser/indexed_db/indexed_db_pending_connection.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "content/browser/indexed_db/indexed_db_callbacks.h"
 #include "content/browser/indexed_db/indexed_db_data_loss_info.h"
 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
@@ -37,6 +38,7 @@
   IndexedDBDataLossInfo data_loss_info;
   base::OnceCallback<void(base::WeakPtr<IndexedDBTransaction>)>
       create_transaction_callback;
+  base::WeakPtr<IndexedDBTransaction> transaction;
 };
 
 }  // namespace content
diff --git a/content/browser/loader/webrtc_connections_observer.cc b/content/browser/loader/webrtc_connections_observer.cc
new file mode 100644
index 0000000..8e81f0e
--- /dev/null
+++ b/content/browser/loader/webrtc_connections_observer.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/webrtc_connections_observer.h"
+
+#include "content/browser/webrtc/webrtc_internals.h"
+
+namespace content {
+
+WebRtcConnectionsObserver::WebRtcConnectionsObserver(
+    const ConnectionsCountChangedCallback& connections_count_changed_callback)
+    : connections_count_changed_callback_(connections_count_changed_callback) {
+  DCHECK(!connections_count_changed_callback_.is_null());
+
+  WebRTCInternals* webrtc_internals = WebRTCInternals::GetInstance();
+  if (!webrtc_internals)
+    return;
+  webrtc_internals->AddConnectionsObserver(this);
+}
+
+WebRtcConnectionsObserver::~WebRtcConnectionsObserver() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  WebRTCInternals* webrtc_internals = WebRTCInternals::GetInstance();
+  if (!webrtc_internals)
+    return;
+  webrtc_internals->RemoveConnectionsObserver(this);
+}
+
+void WebRtcConnectionsObserver::OnConnectionsCountChange(uint32_t count) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  connections_count_changed_callback_.Run(count);
+}
+
+}  // namespace content
diff --git a/content/browser/loader/webrtc_connections_observer.h b/content/browser/loader/webrtc_connections_observer.h
new file mode 100644
index 0000000..c4f57b9
--- /dev/null
+++ b/content/browser/loader/webrtc_connections_observer.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_LOADER_WEBRTC_CONNECTIONS_OBSERVER_H_
+#define CONTENT_BROWSER_LOADER_WEBRTC_CONNECTIONS_OBSERVER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "content/browser/webrtc/webrtc_internals_connections_observer.h"
+
+namespace content {
+
+class WebRtcConnectionsObserver : public WebRtcInternalsConnectionsObserver {
+ public:
+  typedef base::RepeatingCallback<void(uint32_t)>
+      ConnectionsCountChangedCallback;
+  // |webrtc_connections_count_changed_callback| is called every time there
+  // is a change in the count of active WebRTC connections.
+  explicit WebRtcConnectionsObserver(const ConnectionsCountChangedCallback&
+                                         connections_count_changed_callback);
+  ~WebRtcConnectionsObserver() override;
+
+ private:
+  // content::WebRtcInternalsConnectionsObserver:
+  void OnConnectionsCountChange(uint32_t count) override;
+
+  ConnectionsCountChangedCallback connections_count_changed_callback_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  DISALLOW_COPY_AND_ASSIGN(WebRtcConnectionsObserver);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_WEBRTC_CONNECTIONS_OBSERVER_H_
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc
index 488eea2..5ec9f0b 100644
--- a/content/browser/network_service_client.cc
+++ b/content/browser/network_service_client.cc
@@ -16,6 +16,7 @@
 #include "content/browser/devtools/devtools_url_loader_interceptor.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/webrtc_connections_observer.h"
 #include "content/browser/ssl/ssl_client_auth_handler.h"
 #include "content/browser/ssl/ssl_error_handler.h"
 #include "content/browser/ssl/ssl_manager.h"
@@ -558,6 +559,11 @@
     net::NetworkChangeNotifier::AddDNSObserver(this);
 #endif
   }
+
+  webrtc_connections_observer_ =
+      std::make_unique<content::WebRtcConnectionsObserver>(base::BindRepeating(
+          &NetworkServiceClient::OnPeerToPeerConnectionsCountChange,
+          base::Unretained(this)));
 }
 
 NetworkServiceClient::~NetworkServiceClient() {
@@ -692,6 +698,10 @@
   GetNetworkService()->OnMemoryPressure(memory_pressure_level);
 }
 
+void NetworkServiceClient::OnPeerToPeerConnectionsCountChange(uint32_t count) {
+  GetNetworkService()->OnPeerToPeerConnectionsCountChange(count);
+}
+
 #if defined(OS_ANDROID)
 void NetworkServiceClient::OnApplicationStateChange(
     base::android::ApplicationState state) {
diff --git a/content/browser/network_service_client.h b/content/browser/network_service_client.h
index cbd3f51..6466f30b 100644
--- a/content/browser/network_service_client.h
+++ b/content/browser/network_service_client.h
@@ -25,6 +25,8 @@
 
 namespace content {
 
+class WebRtcConnectionsObserver;
+
 class CONTENT_EXPORT NetworkServiceClient
     : public network::mojom::NetworkServiceClient,
 #if defined(OS_ANDROID)
@@ -98,6 +100,10 @@
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_presure_level);
 
+  // Called when there is a change in the count of media connections that
+  // require low network latency.
+  void OnPeerToPeerConnectionsCountChange(uint32_t count);
+
 #if defined(OS_ANDROID)
   void OnApplicationStateChange(base::android::ApplicationState state);
 
@@ -123,6 +129,8 @@
 
   std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
 
+  std::unique_ptr<WebRtcConnectionsObserver> webrtc_connections_observer_;
+
 #if defined(OS_ANDROID)
   std::unique_ptr<base::android::ApplicationStatusListener>
       app_status_listener_;
diff --git a/content/browser/notifications/platform_notification_context_trigger_unittest.cc b/content/browser/notifications/platform_notification_context_trigger_unittest.cc
index de2d611..4fcd8d7 100644
--- a/content/browser/notifications/platform_notification_context_trigger_unittest.cc
+++ b/content/browser/notifications/platform_notification_context_trigger_unittest.cc
@@ -54,8 +54,11 @@
   PlatformNotificationContextTriggerTest()
       : thread_bundle_(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
-            base::test::ScopedTaskEnvironment::NowSource::
-                MAIN_THREAD_MOCK_TIME),
+            base::test::ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME,
+            // TODO(crbug.com/974365): The IO thread is only needed so
+            // MessagePumpFuchsia will create an async::Loop, which is needed
+            // for fidl.
+            content::TestBrowserThreadBundle::REAL_IO_THREAD),
         notification_browser_client_(&browser_context_),
         success_(false) {
     SetBrowserClientForTesting(&notification_browser_client_);
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc
index 88743034..ef04408 100644
--- a/content/browser/portal/portal_browsertest.cc
+++ b/content/browser/portal/portal_browsertest.cc
@@ -184,6 +184,50 @@
   Portal* portal_ = nullptr;
 };
 
+// The PortalAdoptionObserver observes calls to AdoptPortal on
+// RenderFrameHostImpl. This observer should be used to wait for a single
+// call to AdoptPortal.
+class PortalAdoptionObserver : public mojom::FrameHostInterceptorForTesting {
+ public:
+  explicit PortalAdoptionObserver(RenderFrameHostImpl* render_frame_host_impl)
+      : render_frame_host_impl_(render_frame_host_impl) {
+    render_frame_host_impl_->frame_host_binding_for_testing()
+        .SwapImplForTesting(this);
+  }
+
+  ~PortalAdoptionObserver() override {}
+
+  FrameHost* GetForwardingInterface() override {
+    return render_frame_host_impl_;
+  }
+
+  void AdoptPortal(const base::UnguessableToken& portal_token,
+                   AdoptPortalCallback callback) override {
+    Portal* portal = Portal::FromToken(portal_token);
+    DCHECK(portal);
+    RenderFrameProxyHost* proxy_host = portal->CreateProxyAndAttachPortal();
+    std::move(callback).Run(proxy_host->GetRoutingID(),
+                            portal->GetDevToolsFrameToken());
+    portal_adopted_ = true;
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  void WaitUntilPortalAdopted() {
+    if (portal_adopted_)
+      return;
+    base::RunLoop run_loop;
+    run_loop_ = &run_loop;
+    run_loop.Run();
+    run_loop_ = nullptr;
+  }
+
+ private:
+  RenderFrameHostImpl* render_frame_host_impl_;
+  base::RunLoop* run_loop_ = nullptr;
+  bool portal_adopted_ = false;
+};
+
 class PortalBrowserTest : public ContentBrowserTest {
  protected:
   PortalBrowserTest() {}
@@ -283,8 +327,8 @@
   }
 }
 
-// Tests that a portal can be activated in content_shell.
-IN_PROC_BROWSER_TEST_F(PortalBrowserTest, ActivatePortalInShell) {
+// Tests that a portal can be activated.
+IN_PROC_BROWSER_TEST_F(PortalBrowserTest, ActivatePortal) {
   EXPECT_TRUE(NavigateToURL(
       shell(), embedded_test_server()->GetURL("portal.test", "/title1.html")));
   WebContentsImpl* web_contents_impl =
@@ -320,6 +364,63 @@
   EXPECT_EQ(portal_contents, shell()->web_contents());
 }
 
+// Tests if a portal can be activated and the predecessor can be adopted.
+IN_PROC_BROWSER_TEST_F(PortalBrowserTest, ReactivatePredecessor) {
+  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();
+  }
+  PortalInterceptorForTesting* portal_interceptor =
+      PortalInterceptorForTesting::From(portal);
+
+  // Ensure that the portal WebContents exists and is different from the tab's
+  // WebContents.
+  WebContentsImpl* portal_contents = portal->GetPortalContents();
+  EXPECT_NE(nullptr, portal_contents);
+  EXPECT_NE(portal_contents, shell()->web_contents());
+
+  // The portal should not have navigated yet, so we can observe the Portal's
+  // first navigation.
+  TestNavigationObserver navigation_observer(portal_contents);
+  navigation_observer.Wait();
+
+  RenderFrameHostImpl* portal_frame = portal_contents->GetMainFrame();
+  EXPECT_TRUE(ExecJs(portal_frame,
+                     "window.addEventListener('portalactivate', e => { "
+                     "  var portal = e.adoptPredecessor(); "
+                     "  document.body.appendChild(portal); "
+                     "});"));
+
+  {
+    PortalAdoptionObserver adoption_observer(portal_frame);
+    EXPECT_TRUE(ExecJs(main_frame,
+                       "portal.activate().then(() => { "
+                       "  document.body.removeChild(portal); "
+                       "});"));
+    portal_interceptor->WaitForActivate();
+    adoption_observer.WaitUntilPortalAdopted();
+  }
+  // After activation, the shell's WebContents should be the previous portal's
+  // WebContents.
+  EXPECT_EQ(portal_contents, shell()->web_contents());
+  // The original predecessor WebContents should be adopted as a portal.
+  EXPECT_TRUE(web_contents_impl->IsPortal());
+  EXPECT_EQ(web_contents_impl->GetOuterWebContents(), portal_contents);
+}
+
 // Tests that the RenderFrameProxyHost is created and initialized when the
 // portal is initialized.
 IN_PROC_BROWSER_TEST_F(PortalBrowserTest, RenderFrameProxyHostCreated) {
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 3771315..56a1b68 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -364,6 +364,8 @@
 #if defined(OS_LINUX)
   int flags = plugin_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
                                         ChildProcessHost::CHILD_NORMAL;
+#elif defined(OS_MACOSX)
+  int flags = ChildProcessHost::CHILD_PLUGIN;
 #else
   int flags = ChildProcessHost::CHILD_NORMAL;
 #endif
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index b41678e..28294e34 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -50,7 +50,6 @@
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/service/display/output_surface_client.h"
 #include "components/viz/service/display/output_surface_frame.h"
-#include "components/viz/service/display_embedder/overlay_candidate_validator_android.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
@@ -225,8 +224,6 @@
       base::RepeatingCallback<void(const gfx::Size&)> swap_buffers_callback)
       : viz::OutputSurface(std::move(context_provider)),
         swap_buffers_callback_(std::move(swap_buffers_callback)),
-        overlay_candidate_validator_(
-            new viz::OverlayCandidateValidatorAndroid()),
         weak_ptr_factory_(this) {
     capabilities_.max_frames_pending = kMaxDisplaySwapBuffers;
   }
@@ -280,11 +277,6 @@
         gl::ColorSpaceUtils::GetGLColorSpace(color_space), has_alpha);
   }
 
-  std::unique_ptr<viz::OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() override {
-    return std::move(overlay_candidate_validator_);
-  }
-
   bool IsDisplayedAsOverlayPlane() const override { return false; }
   unsigned GetOverlayTextureId() const override { return 0; }
   gfx::BufferFormat GetOverlayBufferFormat() const override {
@@ -336,7 +328,6 @@
  private:
   viz::OutputSurfaceClient* client_ = nullptr;
   base::RepeatingCallback<void(const gfx::Size&)> swap_buffers_callback_;
-  std::unique_ptr<viz::OverlayCandidateValidator> overlay_candidate_validator_;
   ui::LatencyTracker latency_tracker_;
 
   base::WeakPtrFactory<AndroidOutputSurface> weak_ptr_factory_;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 574ba1a..b69a84e 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1637,6 +1637,8 @@
 #if defined(OS_LINUX)
   int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF
                                       : ChildProcessHost::CHILD_NORMAL;
+#elif defined(OS_MACOSX)
+  int flags = ChildProcessHost::CHILD_RENDERER;
 #else
   int flags = ChildProcessHost::CHILD_NORMAL;
 #endif
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index d508822..ef4c541 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -257,7 +257,6 @@
   void OnPasteFromSelectionClipboard();
   void OnTakeFocus(bool reverse);
   void OnClosePageACK();
-  void OnDidZoomURL(double zoom_level, const GURL& url);
   void OnFocus();
 
  private:
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index d2a1a5a3..d027d892 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -91,11 +91,9 @@
  public:
   using WorkerId = std::pair<int, int>;
   explicit DelegatingURLLoaderClient(network::mojom::URLLoaderClientPtr client,
-                                     base::OnceClosure on_response,
                                      const network::ResourceRequest& request)
       : binding_(this),
         client_(std::move(client)),
-        on_response_(std::move(on_response)),
         url_(request.url),
         devtools_enabled_(request.report_raw_headers) {
     if (!devtools_enabled_)
@@ -136,8 +134,6 @@
   }
   void OnReceiveResponse(const network::ResourceResponseHead& head) override {
     client_->OnReceiveResponse(head);
-    DCHECK(on_response_);
-    std::move(on_response_).Run();
     if (!devtools_enabled_)
       return;
     // Make a deep copy of ResourceResponseHead before passing it cross-thread.
@@ -206,7 +202,6 @@
 
   mojo::Binding<network::mojom::URLLoaderClient> binding_;
   network::mojom::URLLoaderClientPtr client_;
-  base::OnceClosure on_response_;
   bool completed_ = false;
   const GURL url_;
   const bool devtools_enabled_;
@@ -650,8 +645,7 @@
     const network::ResourceRequest& original_request,
     URLLoaderFactoryGetter* url_loader_factory_getter,
     scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
-    const WebContentsGetter& web_contents_getter,
-    base::OnceClosure on_response) {
+    const WebContentsGetter& web_contents_getter) {
   if (resource_type_ != ResourceType::kMainFrame &&
       resource_type_ != ResourceType::kSubFrame) {
     return false;
@@ -706,8 +700,7 @@
   preload_handle_->url_loader_client_request =
       mojo::MakeRequest(&inner_url_loader_client);
   auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>(
-      std::move(inner_url_loader_client), std::move(on_response),
-      resource_request);
+      std::move(inner_url_loader_client), resource_request);
 
   // Use NavigationURLLoaderImpl to get a unique request id across
   // browser-initiated navigations and navigation preloads.
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h
index f978d39..14222de 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -62,13 +62,11 @@
 
   // If appropriate, starts the navigation preload request and creates
   // |preload_handle_|. Returns true if it started navigation preload.
-  // |on_response| is invoked in OnReceiveResponse().
   bool MaybeStartNavigationPreload(
       const network::ResourceRequest& original_request,
       URLLoaderFactoryGetter* url_loader_factory_getter,
       scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
-      const WebContentsGetter& web_contents_getter,
-      base::OnceClosure on_response);
+      const WebContentsGetter& web_contents_getter);
 
   // Dispatches a fetch event to the |version| given in ctor, and fires
   // |fetch_callback_| (also given in ctor) once a response is received from the
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index c6421308..309c505e 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -369,15 +369,9 @@
                      url));
 }
 
-void ServiceWorkerMetrics::RecordStartWorkerStatus(
+void ServiceWorkerMetrics::RecordStartInstalledWorkerStatus(
     blink::ServiceWorkerStatusCode status,
-    EventType purpose,
-    bool is_installed) {
-  if (!is_installed) {
-    UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartNewWorker.Status", status);
-    return;
-  }
-
+    EventType purpose) {
   UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status);
   base::UmaHistogramEnumeration(
       base::StrCat({"ServiceWorker.StartWorker.StatusByPurpose",
@@ -740,68 +734,6 @@
                               size);
 }
 
-void ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-    base::TimeDelta worker_start,
-    base::TimeDelta response_start,
-    EmbeddedWorkerStatus initial_worker_status,
-    StartSituation start_situation,
-    ResourceType resource_type) {
-  DCHECK_GE(worker_start.ToInternalValue(), 0);
-  DCHECK_GE(response_start.ToInternalValue(), 0);
-  DCHECK(resource_type == ResourceType::kMainFrame ||
-         resource_type == ResourceType::kSubFrame);
-  const bool is_main_frame = (resource_type == ResourceType::kMainFrame);
-  // TODO(falken): Log sub-frame navigations also.
-  if (!is_main_frame) {
-    return;
-  }
-  const bool nav_preload_finished_first = response_start < worker_start;
-  const base::TimeDelta concurrent_time =
-      nav_preload_finished_first ? response_start : worker_start;
-  base::TimeDelta worker_wait_time;
-  if (nav_preload_finished_first) {
-    worker_wait_time = worker_start - response_start;
-  }
-  const bool worker_start_occurred =
-      initial_worker_status != EmbeddedWorkerStatus::RUNNING;
-  const WorkerPreparationType preparation =
-      GetWorkerPreparationType(initial_worker_status, start_situation);
-
-  UMA_HISTOGRAM_ENUMERATION(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame", preparation);
-  UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.NavPreload.ResponseTime_MainFrame",
-                             response_start);
-  UMA_HISTOGRAM_BOOLEAN("ServiceWorker.NavPreload.FinishedFirst_MainFrame",
-                        nav_preload_finished_first);
-  UMA_HISTOGRAM_MEDIUM_TIMES(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame", concurrent_time);
-  if (nav_preload_finished_first) {
-    UMA_HISTOGRAM_MEDIUM_TIMES(
-        "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame", worker_wait_time);
-  }
-
-  if (worker_start_occurred) {
-    UMA_HISTOGRAM_MEDIUM_TIMES(
-        "ServiceWorker.NavPreload.ResponseTime_MainFrame_"
-        "WorkerStartOccurred",
-        response_start);
-    UMA_HISTOGRAM_BOOLEAN(
-        "ServiceWorker.NavPreload.FinishedFirst_MainFrame_"
-        "WorkerStartOccurred",
-        nav_preload_finished_first);
-    UMA_HISTOGRAM_MEDIUM_TIMES(
-        "ServiceWorker.NavPreload.ConcurrentTime_MainFrame_"
-        "WorkerStartOccurred",
-        concurrent_time);
-    if (nav_preload_finished_first) {
-      UMA_HISTOGRAM_MEDIUM_TIMES(
-          "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame_"
-          "WorkerStartOccurred",
-          worker_wait_time);
-    }
-  }
-}
-
 void ServiceWorkerMetrics::RecordRuntime(base::TimeDelta time) {
   // Start at 1 second since we expect service worker to last at least this
   // long: the update timer and idle timeout timer run on the order of seconds.
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index e09b037..6fb9b4e 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -324,11 +324,10 @@
                                       const GURL& url,
                                       bool is_main_frame_load);
 
-  // Records the result of trying to start a worker. |is_installed| indicates
-  // whether the version has been installed.
-  static void RecordStartWorkerStatus(blink::ServiceWorkerStatusCode status,
-                                      EventType purpose,
-                                      bool is_installed);
+  // Records the result of trying to start an installed worker.
+  static void RecordStartInstalledWorkerStatus(
+      blink::ServiceWorkerStatusCode status,
+      EventType purpose);
 
   // Records the result of sending installed scripts to the renderer.
   static void RecordInstalledScriptsSenderStatus(
@@ -406,22 +405,6 @@
   // navigation preload request is to be sent.
   static void RecordNavigationPreloadRequestHeaderSize(size_t size);
 
-  // Records timings for the navigation preload response and how
-  // it compares to starting the worker.
-  // |worker_start| is the time it took to prepare an activated and running
-  // worker to receive the fetch event. |initial_worker_status| and
-  // |start_situation| describe the preparation needed.
-  // |response_start| is the time it took until the navigation preload response
-  // started.
-  // |resource_type| must be ResourceType::kMainFrame or
-  // ResourceType::kSubFrame.
-  CONTENT_EXPORT static void RecordNavigationPreloadResponse(
-      base::TimeDelta worker_start,
-      base::TimeDelta response_start,
-      EmbeddedWorkerStatus initial_worker_status,
-      StartSituation start_situation,
-      ResourceType resource_type);
-
   static void RecordRuntime(base::TimeDelta time);
 
   // Records the result of starting service worker for a navigation hint.
diff --git a/content/browser/service_worker/service_worker_metrics_unittest.cc b/content/browser/service_worker/service_worker_metrics_unittest.cc
index 39530b9..ed6a8db 100644
--- a/content/browser/service_worker/service_worker_metrics_unittest.cc
+++ b/content/browser/service_worker/service_worker_metrics_unittest.cc
@@ -17,54 +17,11 @@
 const std::string kWorkerStartOccurred = "_WorkerStartOccurred";
 const std::string kStartWorkerExistingReadyProcessSuffix =
     "_StartWorkerExistingReadyProcess";
-const std::string kPreparationTime =
-    "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time";
 const std::string kPreparationType =
     "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type";
 const std::string kPreparationTypeSearch =
     "ServiceWorker.ActivatedWorkerPreparationForMainFrame.Type.search";
 
-void ExpectNoNavPreloadMainFrameUMA(
-    const base::HistogramTester& histogram_tester) {
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame", 0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame", 0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame", 0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame", 0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame", 0);
-
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame_WorkerStartOccurred", 0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame_WorkerStartOccurred",
-      0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame_WorkerStartOccurred",
-      0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame_WorkerStartOccurred",
-      0);
-}
-
-void ExpectNoNavPreloadWorkerStartOccurredUMA(
-    const base::HistogramTester& histogram_tester) {
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame_WorkerStartOccurred", 0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame_WorkerStartOccurred",
-      0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame_WorkerStartOccurred",
-      0);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame_WorkerStartOccurred",
-      0);
-}
-
 base::TimeTicks AdvanceTime(base::TimeTicks* time, int milliseconds) {
   *time += base::TimeDelta::FromMilliseconds(milliseconds);
   return *time;
@@ -169,214 +126,6 @@
   SetBrowserClientForTesting(old_browser_client);
 }
 
-// ===========================================================================
-// Navigation preload tests
-// ===========================================================================
-// The worker was already running.
-TEST(ServiceWorkerMetricsTest,
-     NavigationPreloadResponse_WorkerAlreadyRunning_MainFrame) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(123);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(789);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::RUNNING;
-  StartSituation start_situation = StartSituation::EXISTING_READY_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kMainFrame);
-
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame",
-      static_cast<int>(WorkerPreparationType::RUNNING), 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame", response_start, 1);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame", false, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame", worker_start, 1);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame", 0);
-
-  ExpectNoNavPreloadWorkerStartOccurredUMA(histogram_tester);
-}
-
-// The worker was already running (subframe).
-TEST(ServiceWorkerMetricsTest,
-     NavigationPreloadResponse_WorkerAlreadyRunning_SubFrame) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(123);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(789);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::RUNNING;
-  StartSituation start_situation = StartSituation::EXISTING_READY_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kSubFrame);
-
-  ExpectNoNavPreloadMainFrameUMA(histogram_tester);
-}
-
-// The worker started up.
-TEST(ServiceWorkerMetricsTest,
-     NavigationPreloadResponse_WorkerStart_MainFrame) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(234);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(789);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::STOPPED;
-  StartSituation start_situation = StartSituation::NEW_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kMainFrame);
-
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame",
-      static_cast<int>(WorkerPreparationType::START_IN_NEW_PROCESS), 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame", response_start, 1);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame", false, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame", worker_start, 1);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame", 0);
-
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame_WorkerStartOccurred",
-      response_start, 1);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame_WorkerStartOccurred",
-      false, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame_WorkerStartOccurred",
-      worker_start, 1);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame_WorkerStartOccurred",
-      0);
-}
-
-// The worker started up (subframe).
-TEST(ServiceWorkerMetricsTest, NavigationPreloadResponse_WorkerStart_SubFrame) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(234);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(789);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::STOPPED;
-  StartSituation start_situation = StartSituation::EXISTING_READY_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kSubFrame);
-
-  ExpectNoNavPreloadMainFrameUMA(histogram_tester);
-}
-
-// The worker was already starting up (STARTING). This gets logged to the
-// _WorkerStartOccurred suffix as well.
-TEST(ServiceWorkerMetricsTest,
-     NavigationPreloadResponse_WorkerStart_WorkerStarting) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(234);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(789);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::STARTING;
-  StartSituation start_situation = StartSituation::NEW_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kMainFrame);
-
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame",
-      static_cast<int>(WorkerPreparationType::STARTING), 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame", response_start, 1);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame", false, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame", worker_start, 1);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame", 0);
-
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame_"
-      "WorkerStartOccurred",
-      response_start, 1);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame_"
-      "WorkerStartOccurred",
-      false, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame_"
-      "WorkerStartOccurred",
-      worker_start, 1);
-  histogram_tester.ExpectTotalCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame_"
-      "WorkerStartOccurred",
-      0);
-}
-
-// The worker started up, but navigation preload arrived first.
-TEST(ServiceWorkerMetricsTest,
-     NavigationPreloadResponse_NavPreloadFinishedFirst) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(2345);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(456);
-  base::TimeDelta wait_time = worker_start - response_start;
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::STOPPING;
-  StartSituation start_situation = StartSituation::NEW_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kMainFrame);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame",
-      static_cast<int>(WorkerPreparationType::STOPPING), 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ResponseTime_MainFrame", response_start, 1);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame", true, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame", response_start, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame", wait_time, 1);
-
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.FinishedFirst_MainFrame_"
-      "WorkerStartOccurred",
-      true, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.ConcurrentTime_MainFrame_"
-      "WorkerStartOccurred",
-      response_start, 1);
-  histogram_tester.ExpectTimeBucketCount(
-      "ServiceWorker.NavPreload.WorkerWaitTime_MainFrame_"
-      "WorkerStartOccurred",
-      wait_time, 1);
-}
-
-// The worker started up, but navigation preload arrived first (subframe).
-TEST(ServiceWorkerMetricsTest,
-     NavigationPreloadResponse_NavPreloadFinishedFirst_SubFrame) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(2345);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(456);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::STOPPED;
-  StartSituation start_situation = StartSituation::NEW_PROCESS;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kSubFrame);
-
-  ExpectNoNavPreloadMainFrameUMA(histogram_tester);
-}
-
-// The worker started up during browser startup.
-TEST(ServiceWorkerMetricsTest, NavigationPreloadResponse_BrowserStartup) {
-  base::TimeDelta worker_start = base::TimeDelta::FromMilliseconds(2345);
-  base::TimeDelta response_start = base::TimeDelta::FromMilliseconds(456);
-  EmbeddedWorkerStatus initial_worker_status = EmbeddedWorkerStatus::STOPPED;
-  StartSituation start_situation = StartSituation::DURING_STARTUP;
-  base::HistogramTester histogram_tester;
-  ServiceWorkerMetrics::RecordNavigationPreloadResponse(
-      worker_start, response_start, initial_worker_status, start_situation,
-      ResourceType::kMainFrame);
-  histogram_tester.ExpectUniqueSample(
-      "ServiceWorker.NavPreload.WorkerPreparationType_MainFrame",
-      static_cast<int>(WorkerPreparationType::START_DURING_STARTUP), 1);
-}
-
 TEST(ServiceWorkerMetricsTest, EmbeddedWorkerStartTiming) {
   ServiceWorkerMetrics::StartTimes times;
   auto current = base::TimeTicks::Now();
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc
index b7584fad..4fba757 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -226,8 +226,7 @@
                      weak_factory_.GetWeakPtr()));
   did_navigation_preload_ = fetch_dispatcher_->MaybeStartNavigationPreload(
       resource_request_, url_loader_factory_getter_.get(), std::move(context),
-      provider_host_->web_contents_getter(),
-      base::DoNothing(/* TODO(crbug/762357): metrics? */));
+      provider_host_->web_contents_getter());
 
   // Record worker start time here as |fetch_dispatcher_| will start a service
   // worker if there is no running service worker.
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index d2a01a2..d1a8e9c 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1823,8 +1823,9 @@
     ServiceWorkerMetrics::RecordInstalledScriptsSenderStatus(
         installed_scripts_sender_->last_finished_reason());
   }
-  ServiceWorkerMetrics::RecordStartWorkerStatus(status, purpose,
-                                                IsInstalled(prestart_status));
+
+  if (IsInstalled(prestart_status))
+    ServiceWorkerMetrics::RecordStartInstalledWorkerStatus(status, purpose);
 
   if (status == blink::ServiceWorkerStatusCode::kOk && !start_time.is_null() &&
       !skip_recording_startup_time_) {
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc
index ab8cd4b..2a05401 100644
--- a/content/browser/sms/sms_browsertest.cc
+++ b/content/browser/sms/sms_browsertest.cc
@@ -46,7 +46,7 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Start) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Receive) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
   NavigateToURL(shell(), url);
 
@@ -56,16 +56,11 @@
       shell()->web_contents()->GetBrowserContext()->GetSmsService());
   sms_service->SetSmsProviderForTest(base::WrapUnique(mock));
 
-  // Test that SMS content can be retrieved after SmsManager.start().
+  // Test that SMS content can be retrieved after navigator.sms.receive().
   std::string script = R"(
     (async () => {
-      let receiver = new SMSReceiver({timeout: 60});
-      await receiver.start();
-      return new Promise(function(resolve) {
-        receiver.addEventListener('change', e => {
-          resolve(receiver.sms.content);
-        })
-      });
+      let sms = await navigator.sms.receive({timeout: 60});
+      return sms.content;
     }) ();
   )";
 
@@ -76,4 +71,41 @@
   EXPECT_EQ("hello", EvalJs(shell(), script));
 }
 
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, ReceiveMultiple) {
+  GURL url = GetTestUrl(nullptr, "simple_page.html");
+  NavigateToURL(shell(), url);
+
+  auto* mock = new NiceMock<MockSmsProvider>();
+
+  auto* sms_service = static_cast<SmsServiceImpl*>(
+      shell()->web_contents()->GetBrowserContext()->GetSmsService());
+  sms_service->SetSmsProviderForTest(base::WrapUnique(mock));
+
+  // Test that SMS content can retrieve multiple messages.
+  std::string script = R"(
+    (async () => {
+      let sms1 = navigator.sms.receive();
+      let sms2 = navigator.sms.receive();
+
+      let msg1 = await sms1;
+      let msg2 = await sms2;
+
+      return [msg1.content, msg2.content];
+    }) ();
+  )";
+
+  EXPECT_CALL(*mock, Retrieve())
+      .WillOnce(Invoke([&mock, &url]() {
+        mock->NotifyReceive(url::Origin::Create(url), "hello1");
+      }))
+      .WillOnce(Invoke([&mock, &url]() {
+        mock->NotifyReceive(url::Origin::Create(url), "hello2");
+      }));
+
+  base::ListValue result = EvalJs(shell(), script).ExtractList();
+  ASSERT_EQ(2u, result.GetList().size());
+  EXPECT_EQ("hello1", result.GetList()[0].GetString());
+  EXPECT_EQ("hello2", result.GetList()[1].GetString());
+}
+
 }  // namespace content
diff --git a/content/browser/webauth/virtual_authenticator.cc b/content/browser/webauth/virtual_authenticator.cc
index 029d710..161c25a 100644
--- a/content/browser/webauth/virtual_authenticator.cc
+++ b/content/browser/webauth/virtual_authenticator.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "base/containers/span.h"
 #include "base/guid.h"
 #include "crypto/ec_private_key.h"
@@ -27,6 +28,7 @@
       unique_id_(base::GenerateGUID()),
       state_(base::MakeRefCounted<::device::VirtualFidoDevice::State>()) {
   state_->transport = transport;
+  SetUserPresence(true);
 }
 
 VirtualAuthenticator::~VirtualAuthenticator() = default;
@@ -62,6 +64,15 @@
   state_->registrations.clear();
 }
 
+void VirtualAuthenticator::SetUserPresence(bool is_user_present) {
+  is_user_present_ = is_user_present;
+  state_->simulate_press_callback = base::BindRepeating(
+      [](bool is_user_present, device::VirtualFidoDevice* device) {
+        return is_user_present;
+      },
+      is_user_present);
+}
+
 std::unique_ptr<::device::FidoDevice> VirtualAuthenticator::ConstructDevice() {
   switch (protocol_) {
     case ::device::ProtocolVersion::kU2f:
@@ -116,13 +127,12 @@
 
 void VirtualAuthenticator::SetUserPresence(bool present,
                                            SetUserPresenceCallback callback) {
-  // TODO(https://crbug.com/785955): Implement once VirtualFidoDevice supports
-  // this.
+  SetUserPresence(present);
   std::move(callback).Run();
 }
 
 void VirtualAuthenticator::GetUserPresence(GetUserPresenceCallback callback) {
-  std::move(callback).Run(false);
+  std::move(callback).Run(is_user_present_);
 }
 
 }  // namespace content
diff --git a/content/browser/webauth/virtual_authenticator.h b/content/browser/webauth/virtual_authenticator.h
index 38f6080e..3fb8f1f 100644
--- a/content/browser/webauth/virtual_authenticator.h
+++ b/content/browser/webauth/virtual_authenticator.h
@@ -51,6 +51,10 @@
   // Removes all the credentials.
   void ClearRegistrations();
 
+  // Sets whether tests of user presence succeed or not for new requests sent to
+  // this authenticator. The default is true.
+  void SetUserPresence(bool is_user_present);
+
   ::device::FidoTransportProtocol transport() const {
     return state_->transport;
   }
@@ -82,6 +86,7 @@
   const bool has_resident_key_;
   const bool has_user_verification_;
   const std::string unique_id_;
+  bool is_user_present_;
   scoped_refptr<::device::VirtualFidoDevice::State> state_;
   mojo::BindingSet<blink::test::mojom::VirtualAuthenticator> binding_set_;
 
diff --git a/content/browser/webrtc/webrtc_internals.cc b/content/browser/webrtc/webrtc_internals.cc
index 089eff19..eca0ad3 100644
--- a/content/browser/webrtc/webrtc_internals.cc
+++ b/content/browser/webrtc/webrtc_internals.cc
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
+#include "content/browser/webrtc/webrtc_internals_connections_observer.h"
 #include "content/browser/webrtc/webrtc_internals_ui_observer.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -337,6 +338,18 @@
     FreeLogList(&dictionary);
 }
 
+void WebRTCInternals::AddConnectionsObserver(
+    WebRtcInternalsConnectionsObserver* observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  connections_observers_.AddObserver(observer);
+}
+
+void WebRTCInternals::RemoveConnectionsObserver(
+    WebRtcInternalsConnectionsObserver* observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  connections_observers_.RemoveObserver(observer);
+}
+
 void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (peer_connection_data_.GetSize() > 0)
@@ -586,6 +599,8 @@
     ++num_connected_connections_;
     record->SetBoolean("connected", true);
     UpdateWakeLock();
+    for (auto& observer : connections_observers_)
+      observer.OnConnectionsCountChange(num_connected_connections_);
   }
 }
 
@@ -598,6 +613,8 @@
     --num_connected_connections_;
     DCHECK_GE(num_connected_connections_, 0);
     UpdateWakeLock();
+    for (auto& observer : connections_observers_)
+      observer.OnConnectionsCountChange(num_connected_connections_);
   }
 }
 
diff --git a/content/browser/webrtc/webrtc_internals.h b/content/browser/webrtc/webrtc_internals.h
index 3098a67..3070996 100644
--- a/content/browser/webrtc/webrtc_internals.h
+++ b/content/browser/webrtc/webrtc_internals.h
@@ -29,6 +29,7 @@
 namespace content {
 
 class WebContents;
+class WebRtcInternalsConnectionsObserver;
 class WebRTCInternalsUIObserver;
 
 // This is a singleton class running in the browser UI thread.
@@ -111,6 +112,12 @@
   void AddObserver(WebRTCInternalsUIObserver* observer);
   void RemoveObserver(WebRTCInternalsUIObserver* observer);
 
+  // Methods for adding or removing WebRtcInternalsConnectionsObserver.
+  // |observer| is notified when there is a change in the count of active WebRTC
+  // connections.
+  void AddConnectionsObserver(WebRtcInternalsConnectionsObserver* observer);
+  void RemoveConnectionsObserver(WebRtcInternalsConnectionsObserver* observer);
+
   // Sends all update data to |observer|.
   void UpdateObserver(WebRTCInternalsUIObserver* observer);
 
@@ -198,6 +205,8 @@
 
   base::ObserverList<WebRTCInternalsUIObserver>::Unchecked observers_;
 
+  base::ObserverList<WebRtcInternalsConnectionsObserver> connections_observers_;
+
   // |peer_connection_data_| is a list containing all the PeerConnection
   // updates.
   // Each item of the list represents the data for one PeerConnection, which
diff --git a/content/browser/webrtc/webrtc_internals_connections_observer.h b/content/browser/webrtc/webrtc_internals_connections_observer.h
new file mode 100644
index 0000000..609300886
--- /dev/null
+++ b/content/browser/webrtc/webrtc_internals_connections_observer.h
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_CONNECTIONS_OBSERVER_H_
+#define CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_CONNECTIONS_OBSERVER_H_
+
+#include "base/observer_list_types.h"
+
+namespace content {
+
+// Implement this interface to receive WebRTCInternals updates.
+class WebRtcInternalsConnectionsObserver : public base::CheckedObserver {
+ public:
+  ~WebRtcInternalsConnectionsObserver() override {}
+
+  // Called when there is a change in the count of active WebRTC connections.
+  virtual void OnConnectionsCountChange(uint32_t count) = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_CONNECTIONS_OBSERVER_H_
diff --git a/content/browser/webrtc/webrtc_internals_unittest.cc b/content/browser/webrtc/webrtc_internals_unittest.cc
index 6fb9ab0..7dc60bfc 100644
--- a/content/browser/webrtc/webrtc_internals_unittest.cc
+++ b/content/browser/webrtc/webrtc_internals_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/values.h"
+#include "content/browser/webrtc/webrtc_internals_connections_observer.h"
 #include "content/browser/webrtc/webrtc_internals_ui_observer.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/test_browser_thread.h"
@@ -76,6 +77,26 @@
   bool has_wakelock_;
 };
 
+class TestWebRtcConnectionsObserver
+    : public WebRtcInternalsConnectionsObserver {
+ public:
+  TestWebRtcConnectionsObserver() = default;
+
+  ~TestWebRtcConnectionsObserver() override = default;
+
+  uint32_t latest_connections_count() const {
+    return latest_connections_count_;
+  }
+
+ private:
+  // content::WebRtcInternalsConnectionsObserver:
+  void OnConnectionsCountChange(uint32_t count) override {
+    latest_connections_count_ = count;
+  }
+
+  uint32_t latest_connections_count_ = 0u;
+};
+
 }  // namespace
 
 // Derived class for testing only.  Allows the tests to have their own instance
@@ -728,6 +749,45 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(WebRtcInternalsTest, TestWebRtcConnectionsObserver) {
+  const int kRenderProcessId = 1;
+  const int kPid = 1;
+  const int kLid = 1;
+
+  TestWebRtcConnectionsObserver observer;
+
+  WebRTCInternalsForTest webrtc_internals;
+  webrtc_internals.AddConnectionsObserver(&observer);
+  EXPECT_EQ(0u, observer.latest_connections_count());
+  EXPECT_EQ(webrtc_internals.num_connected_connections(), 0);
+
+  webrtc_internals.OnAddPeerConnection(kRenderProcessId, kPid, kLid, kUrl,
+                                       kRtcConfiguration, kContraints);
+  EXPECT_EQ(webrtc_internals.num_connected_connections(), 0);
+  EXPECT_EQ(0u, observer.latest_connections_count());
+
+  webrtc_internals.OnUpdatePeerConnection(
+      kPid, kLid, "iceConnectionStateChange", "connected");
+  EXPECT_EQ(webrtc_internals.num_connected_connections(), 1);
+  EXPECT_EQ(1u, observer.latest_connections_count());
+
+  webrtc_internals.OnUpdatePeerConnection(
+      kPid, kLid, "iceConnectionStateChange", "disconnected");
+  EXPECT_EQ(webrtc_internals.num_connected_connections(), 0);
+  EXPECT_EQ(0u, observer.latest_connections_count());
+
+  webrtc_internals.OnUpdatePeerConnection(
+      kPid, kLid, "iceConnectionStateChange", "connected");
+  EXPECT_EQ(webrtc_internals.num_connected_connections(), 1);
+  EXPECT_EQ(1u, observer.latest_connections_count());
+
+  webrtc_internals.OnRemovePeerConnection(kPid, kLid);
+  EXPECT_EQ(webrtc_internals.num_connected_connections(), 0);
+  EXPECT_EQ(0u, observer.latest_connections_count());
+
+  base::RunLoop().RunUntilIdle();
+}
+
 // TODO(eladalon): Add tests that WebRtcEventLogger::Enable/Disable is
 // correctly called. https://crbug.com/775415
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 25d40e6..dde9fcb 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -13,6 +13,7 @@
 import("features.gni")
 if (is_mac) {
   import("//build/config/mac/mac_sdk.gni")
+  import("//content/public/app/mac_helpers.gni")
 }
 
 # For feature flags internal to content. See content/public/common:features
@@ -360,7 +361,10 @@
   }
 
   if (is_mac) {
-    deps += [ "//sandbox/mac:seatbelt" ]
+    deps += [
+      ":mac_helpers",
+      "//sandbox/mac:seatbelt",
+    ]
   }
 
   if (is_android) {
@@ -547,3 +551,35 @@
   export_define = "CONTENT_IMPLEMENTATION=1"
   export_header = "content/common/content_export.h"
 }
+
+if (is_mac) {
+  source_set("mac_helpers") {
+    _lines = [
+      "// This file is generated by " +
+          get_label_info(target_name, "label_no_toolchain"),
+      "",
+      "#ifndef GEN_CONTENT_COMMON_MAC_HELPERS_H_",
+      "#define GEN_CONTENT_COMMON_MAC_HELPERS_H_",
+      "",
+      "namespace content {",
+      "",
+    ]
+    foreach(helper_params, content_mac_helpers) {
+      _lines += [ "const char kMacHelperSuffix_${helper_params[0]}[] = \"${helper_params[2]}\";" ]
+    }
+    _lines += [
+      "",
+      "}  // namespace content",
+      "",
+      "#endif  // GEN_CONTENT_COMMON_MAC_HELPERS_H_",
+    ]
+
+    _file = "$target_gen_dir/mac_helpers.h"
+
+    write_file(_file, _lines)
+
+    sources = [
+      _file,
+    ]
+  }
+}
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc
index 160dd43..3c14eb0f 100644
--- a/content/common/child_process_host_impl.cc
+++ b/content/common/child_process_host_impl.cc
@@ -34,6 +34,9 @@
 
 #if defined(OS_LINUX)
 #include "base/linux_util.h"
+#elif defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#include "content/common/mac_helpers.h"
 #endif  // OS_LINUX
 
 namespace {
@@ -69,6 +72,32 @@
   // executable.
   if (child_path.empty())
     base::PathService::Get(CHILD_PROCESS_EXE, &child_path);
+
+#if defined(OS_MACOSX)
+  std::string child_base_name = child_path.BaseName().value();
+
+  if (flags != CHILD_NORMAL && base::mac::AmIBundled()) {
+    // This is a specialized helper, with the |child_path| at
+    // ../Framework.framework/Versions/X/Helpers/Chromium Helper.app/Contents/
+    // MacOS/Chromium Helper. Go back up to the "Helpers" directory to select
+    // a different variant.
+    child_path = child_path.DirName().DirName().DirName().DirName();
+
+    if (flags == CHILD_RENDERER) {
+      child_base_name += kMacHelperSuffix_renderer;
+    } else if (flags == CHILD_PLUGIN) {
+      child_base_name += kMacHelperSuffix_plugin;
+    } else {
+      NOTREACHED();
+    }
+
+    child_path = child_path.Append(child_base_name + ".app")
+                     .Append("Contents")
+                     .Append("MacOS")
+                     .Append(child_base_name);
+  }
+#endif
+
   return child_path;
 }
 
diff --git a/content/common/tab_switch_time_recorder.cc b/content/common/tab_switch_time_recorder.cc
index d188865..4360e1b 100644
--- a/content/common/tab_switch_time_recorder.cc
+++ b/content/common/tab_switch_time_recorder.cc
@@ -109,6 +109,14 @@
       tab_switch_duration.InMillisecondsF());
   ++g_num_trace_events_in_process;
 
+  // Each value recorded to a histogram with suffix .NoSavedFrames_Loaded_Frozen
+  // or .NoSavedFrames_Loaded_NotFrozen is also recorded to a histogram with
+  // suffix .NoSavedFrames_Loaded to facilitate assessing the impact of
+  // experiments that affect the number of frozen tab on tab switch time.
+  const bool is_no_saved_frames_loaded =
+      !has_saved_frames_ &&
+      tab_switch_start_state_.value().destination_is_loaded;
+
   // Record result histogram.
   base::UmaHistogramEnumeration(
       std::string("Browser.Tabs.TabSwitchResult.") +
@@ -116,6 +124,11 @@
                              tab_switch_start_state_.value()),
       tab_switch_result);
 
+  if (is_no_saved_frames_loaded) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Browser.Tabs.TabSwitchResult.NoSavedFrames_Loaded", tab_switch_result);
+  }
+
   // Record latency histogram.
   switch (tab_switch_result) {
     case TabSwitchResult::kSuccess: {
@@ -124,6 +137,12 @@
               GetHistogramSuffix(has_saved_frames_,
                                  tab_switch_start_state_.value()),
           tab_switch_duration);
+
+      if (is_no_saved_frames_loaded) {
+        UMA_HISTOGRAM_TIMES(
+            "Browser.Tabs.TotalSwitchDuration.NoSavedFrames_Loaded",
+            tab_switch_duration);
+      }
       break;
     }
     case TabSwitchResult::kIncomplete: {
@@ -132,6 +151,12 @@
               GetHistogramSuffix(has_saved_frames_,
                                  tab_switch_start_state_.value()),
           tab_switch_duration);
+
+      if (is_no_saved_frames_loaded) {
+        UMA_HISTOGRAM_TIMES(
+            "Browser.Tabs.TotalIncompleteSwitchDuration.NoSavedFrames_Loaded",
+            tab_switch_duration);
+      }
       break;
     }
     case TabSwitchResult::kPresentationFailure: {
diff --git a/content/common/tab_switch_time_recorder_unittest.cc b/content/common/tab_switch_time_recorder_unittest.cc
index 0002022..1476348f 100644
--- a/content/common/tab_switch_time_recorder_unittest.cc
+++ b/content/common/tab_switch_time_recorder_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <utility>
 
+#include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
 #include "content/common/tab_switch_time_recorder.h"
@@ -15,23 +16,36 @@
 constexpr char kDurationWithSavedFramesHistogram[] =
     "Browser.Tabs.TotalSwitchDuration.WithSavedFrames";
 constexpr char kDurationNoSavedFramesHistogram[] =
+    "Browser.Tabs.TotalSwitchDuration.NoSavedFrames_Loaded";
+constexpr char kDurationNoSavedFramesNotFrozenHistogram[] =
     "Browser.Tabs.TotalSwitchDuration.NoSavedFrames_Loaded_NotFrozen";
 constexpr char kDurationNoSavedFramesFrozenHistogram[] =
     "Browser.Tabs.TotalSwitchDuration.NoSavedFrames_Loaded_Frozen";
 constexpr char kDurationNoSavedFramesUnloadedHistogram[] =
     "Browser.Tabs.TotalSwitchDuration.NoSavedFrames_NotLoaded";
+
 constexpr char kIncompleteDurationWithSavedFramesHistogram[] =
     "Browser.Tabs.TotalIncompleteSwitchDuration.WithSavedFrames";
 constexpr char kIncompleteDurationNoSavedFramesHistogram[] =
+    "Browser.Tabs.TotalIncompleteSwitchDuration.NoSavedFrames_Loaded";
+constexpr char kIncompleteDurationNoSavedFramesNotFrozenHistogram[] =
     "Browser.Tabs.TotalIncompleteSwitchDuration.NoSavedFrames_Loaded_NotFrozen";
+constexpr char kIncompleteDurationNoSavedFramesFrozenHistogram[] =
+    "Browser.Tabs.TotalIncompleteSwitchDuration.NoSavedFrames_Loaded_Frozen";
+constexpr char kIncompleteDurationNoSavedFramesUnloadedHistogram[] =
+    "Browser.Tabs.TotalIncompleteSwitchDuration.NoSavedFrames_NotLoaded";
+
 constexpr char kResultWithSavedFramesHistogram[] =
     "Browser.Tabs.TabSwitchResult.WithSavedFrames";
 constexpr char kResultNoSavedFramesHistogram[] =
+    "Browser.Tabs.TabSwitchResult.NoSavedFrames_Loaded";
+constexpr char kResultNoSavedFramesNotFrozenHistogram[] =
     "Browser.Tabs.TabSwitchResult.NoSavedFrames_Loaded_NotFrozen";
 constexpr char kResultNoSavedFramesFrozenHistogram[] =
     "Browser.Tabs.TabSwitchResult.NoSavedFrames_Loaded_Frozen";
 constexpr char kResultNoSavedFramesUnloadedHistogram[] =
     "Browser.Tabs.TabSwitchResult.NoSavedFrames_NotLoaded";
+
 constexpr base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(42);
 constexpr base::TimeDelta kOtherDuration =
     base::TimeDelta::FromMilliseconds(4242);
@@ -42,13 +56,37 @@
     // Start with non-zero time.
     scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(123));
 
-    ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-    ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
-    ExpectTotalSamples(kDurationNoSavedFramesFrozenHistogram, 0);
-    ExpectTotalSamples(kDurationNoSavedFramesUnloadedHistogram, 0);
+    // Expect all histograms to be empty.
+    ExpectHistogramsEmptyExcept({});
+  }
+
+  void ExpectHistogramsEmptyExcept(
+      std::vector<const char*> histograms_with_values) {
+    constexpr const char* kAllHistograms[] = {
+        kDurationWithSavedFramesHistogram,
+        kDurationNoSavedFramesHistogram,
+        kDurationNoSavedFramesNotFrozenHistogram,
+        kDurationNoSavedFramesFrozenHistogram,
+        kDurationNoSavedFramesUnloadedHistogram,
+        kIncompleteDurationWithSavedFramesHistogram,
+        kIncompleteDurationNoSavedFramesHistogram,
+        kIncompleteDurationNoSavedFramesNotFrozenHistogram,
+        kIncompleteDurationNoSavedFramesFrozenHistogram,
+        kIncompleteDurationNoSavedFramesUnloadedHistogram,
+        kResultWithSavedFramesHistogram,
+        kResultNoSavedFramesHistogram,
+        kResultNoSavedFramesNotFrozenHistogram,
+        kResultNoSavedFramesFrozenHistogram,
+        kResultNoSavedFramesUnloadedHistogram};
+    for (const char* histogram : kAllHistograms) {
+      if (!base::Contains(histograms_with_values, histogram))
+        ExpectTotalSamples(histogram, 0);
+    }
   }
 
   void ExpectTotalSamples(const char* histogram_name, int expected_count) {
+    SCOPED_TRACE(base::StringPrintf("Expect %d samples in %s.", expected_count,
+                                    histogram_name));
     EXPECT_EQ(static_cast<int>(
                   histogram_tester_.GetAllSamples(histogram_name).size()),
               expected_count);
@@ -87,20 +125,22 @@
       end, end - start, gfx::PresentationFeedback::Flags::kHWCompletion);
   std::move(callback).Run(presentation_feedback);
 
+  ExpectHistogramsEmptyExcept(
+      {kDurationWithSavedFramesHistogram, kResultWithSavedFramesHistogram});
+
+  // Duration.
   ExpectTotalSamples(kDurationWithSavedFramesHistogram, 1);
   ExpectTimeBucketCount(kDurationWithSavedFramesHistogram, kDuration, 1);
+
+  // Result.
   ExpectTotalSamples(kResultWithSavedFramesHistogram, 1);
   ExpectResultBucketCount(kResultWithSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
-
-  ExpectTotalSamples(kResultNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
 }
 
 // Time is properly recorded to histogram when we have no saved frame and if we
 // have a proper matching TabWasShown and callback execution.
-TEST_F(TabSwitchTimeRecorderTest, TimeIsRecordedNoSavedFrame) {
+TEST_F(TabSwitchTimeRecorderTest, TimeIsRecordedNoSavedFrameNotFrozen) {
   const auto start = base::TimeTicks::Now();
   auto callback = tab_switch_time_recorder_.TabWasShown(
       false /* has_saved_frames */,
@@ -112,24 +152,28 @@
       end, end - start, gfx::PresentationFeedback::Flags::kHWCompletion);
   std::move(callback).Run(presentation_feedback);
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept({kDurationNoSavedFramesHistogram,
+                               kDurationNoSavedFramesNotFrozenHistogram,
+                               kResultNoSavedFramesHistogram,
+                               kResultNoSavedFramesNotFrozenHistogram});
 
+  // Duration.
   ExpectTotalSamples(kDurationNoSavedFramesHistogram, 1);
   ExpectTimeBucketCount(kDurationNoSavedFramesHistogram, kDuration, 1);
-  ExpectTotalSamples(kDurationNoSavedFramesFrozenHistogram, 0);
-  ExpectTotalSamples(kDurationNoSavedFramesUnloadedHistogram, 0);
+  ExpectTotalSamples(kDurationNoSavedFramesNotFrozenHistogram, 1);
+  ExpectTimeBucketCount(kDurationNoSavedFramesNotFrozenHistogram, kDuration, 1);
+
+  // Result.
   ExpectTotalSamples(kResultNoSavedFramesHistogram, 1);
   ExpectResultBucketCount(kResultNoSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
-  ExpectTotalSamples(kResultNoSavedFramesFrozenHistogram, 0);
-  ExpectTotalSamples(kResultNoSavedFramesUnloadedHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
+  ExpectTotalSamples(kResultNoSavedFramesNotFrozenHistogram, 1);
+  ExpectResultBucketCount(kResultNoSavedFramesNotFrozenHistogram,
+                          TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
 }
 
 // Same as TimeIsRecordedNoSavedFrame but with the destination frame frozen.
-TEST_F(TabSwitchTimeRecorderTest, TimeIsRecordedNoSavedFrameAndFrozen) {
+TEST_F(TabSwitchTimeRecorderTest, TimeIsRecordedNoSavedFrameFrozen) {
   const auto start = base::TimeTicks::Now();
   auto callback = tab_switch_time_recorder_.TabWasShown(
       false /* has_saved_frames */,
@@ -141,20 +185,23 @@
       end, end - start, gfx::PresentationFeedback::Flags::kHWCompletion);
   std::move(callback).Run(presentation_feedback);
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept(
+      {kDurationNoSavedFramesHistogram, kDurationNoSavedFramesFrozenHistogram,
+       kResultNoSavedFramesHistogram, kResultNoSavedFramesFrozenHistogram});
 
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
+  // Duration.
+  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 1);
+  ExpectTimeBucketCount(kDurationNoSavedFramesHistogram, kDuration, 1);
   ExpectTotalSamples(kDurationNoSavedFramesFrozenHistogram, 1);
   ExpectTimeBucketCount(kDurationNoSavedFramesFrozenHistogram, kDuration, 1);
-  ExpectTotalSamples(kDurationNoSavedFramesUnloadedHistogram, 0);
-  ExpectTotalSamples(kResultNoSavedFramesHistogram, 0);
+
+  // Result.
+  ExpectTotalSamples(kResultNoSavedFramesHistogram, 1);
+  ExpectResultBucketCount(kResultNoSavedFramesHistogram,
+                          TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
   ExpectTotalSamples(kResultNoSavedFramesFrozenHistogram, 1);
   ExpectResultBucketCount(kResultNoSavedFramesFrozenHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
-  ExpectTotalSamples(kResultNoSavedFramesUnloadedHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
 }
 
 // Same as TimeIsRecordedNoSavedFrame but with the destination frame unloaded.
@@ -170,20 +217,17 @@
       end, end - start, gfx::PresentationFeedback::Flags::kHWCompletion);
   std::move(callback).Run(presentation_feedback);
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept({kDurationNoSavedFramesUnloadedHistogram,
+                               kResultNoSavedFramesUnloadedHistogram});
 
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kDurationNoSavedFramesFrozenHistogram, 0);
+  // Duration.
   ExpectTotalSamples(kDurationNoSavedFramesUnloadedHistogram, 1);
   ExpectTimeBucketCount(kDurationNoSavedFramesUnloadedHistogram, kDuration, 1);
-  ExpectTotalSamples(kResultNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultNoSavedFramesFrozenHistogram, 0);
+
+  // Result.
   ExpectTotalSamples(kResultNoSavedFramesUnloadedHistogram, 1);
   ExpectResultBucketCount(kResultNoSavedFramesUnloadedHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
 }
 
 // A failure should be reported if gfx::PresentationFeedback contains the
@@ -197,16 +241,13 @@
       start);
   std::move(callback).Run(gfx::PresentationFeedback::Failure());
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept({kResultWithSavedFramesHistogram});
+
+  // Result (no duration is recorded on presentation failure).
   ExpectTotalSamples(kResultWithSavedFramesHistogram, 1);
   ExpectResultBucketCount(
       kResultWithSavedFramesHistogram,
       TabSwitchTimeRecorder::TabSwitchResult::kPresentationFailure, 1);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
-
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
 }
 
 // A failure should be reported if gfx::PresentationFeedback contains the
@@ -220,16 +261,18 @@
       start);
   std::move(callback).Run(gfx::PresentationFeedback::Failure());
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept(
+      {kResultNoSavedFramesHistogram, kResultNoSavedFramesNotFrozenHistogram});
 
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
+  // Result (no duration is recorded on presentation failure).
   ExpectTotalSamples(kResultNoSavedFramesHistogram, 1);
   ExpectResultBucketCount(
       kResultNoSavedFramesHistogram,
       TabSwitchTimeRecorder::TabSwitchResult::kPresentationFailure, 1);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
+  ExpectTotalSamples(kResultNoSavedFramesNotFrozenHistogram, 1);
+  ExpectResultBucketCount(
+      kResultNoSavedFramesNotFrozenHistogram,
+      TabSwitchTimeRecorder::TabSwitchResult::kPresentationFailure, 1);
 }
 
 // An incomplete tab switch is reported when no frame is shown before a tab is
@@ -245,18 +288,19 @@
   scoped_task_environment_.FastForwardBy(kDuration);
   tab_switch_time_recorder_.TabWasHidden();
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 1);
-  ExpectResultBucketCount(kResultWithSavedFramesHistogram,
-                          TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
-                          1);
+  ExpectHistogramsEmptyExcept({kResultWithSavedFramesHistogram,
+                               kIncompleteDurationWithSavedFramesHistogram});
+
+  // Duration.
   ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 1);
   ExpectTimeBucketCount(kIncompleteDurationWithSavedFramesHistogram, kDuration,
                         1);
 
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
+  // Result.
+  ExpectTotalSamples(kResultWithSavedFramesHistogram, 1);
+  ExpectResultBucketCount(kResultWithSavedFramesHistogram,
+                          TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
+                          1);
 
   const auto start2 = base::TimeTicks::Now();
   auto callback2 = tab_switch_time_recorder_.TabWasShown(
@@ -269,19 +313,22 @@
       end2, end2 - start2, gfx::PresentationFeedback::Flags::kHWCompletion);
   std::move(callback2).Run(presentation_feedback);
 
+  ExpectHistogramsEmptyExcept({kDurationWithSavedFramesHistogram,
+                               kResultWithSavedFramesHistogram,
+                               kIncompleteDurationWithSavedFramesHistogram});
+
+  // Duration.
+  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 1);
   ExpectTotalSamples(kDurationWithSavedFramesHistogram, 1);
   ExpectTimeBucketCount(kDurationWithSavedFramesHistogram, kOtherDuration, 1);
+
+  // Result.
   ExpectTotalSamples(kResultWithSavedFramesHistogram, 2);
   ExpectResultBucketCount(kResultWithSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
                           1);
   ExpectResultBucketCount(kResultWithSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 1);
-
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultNoSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 0);
 }
 
 // An incomplete tab switch is reported when no frame is shown before a tab is
@@ -297,18 +344,28 @@
   scoped_task_environment_.FastForwardBy(kDuration);
   tab_switch_time_recorder_.TabWasHidden();
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept(
+      {kIncompleteDurationNoSavedFramesHistogram,
+       kIncompleteDurationNoSavedFramesNotFrozenHistogram,
+       kResultNoSavedFramesHistogram, kResultNoSavedFramesNotFrozenHistogram});
 
-  ExpectTotalSamples(kDurationNoSavedFramesHistogram, 0);
+  // Duration.
+  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 1);
+  ExpectTimeBucketCount(kIncompleteDurationNoSavedFramesHistogram, kDuration,
+                        1);
+  ExpectTotalSamples(kIncompleteDurationNoSavedFramesNotFrozenHistogram, 1);
+  ExpectTimeBucketCount(kIncompleteDurationNoSavedFramesNotFrozenHistogram,
+                        kDuration, 1);
+
+  // Result.
   ExpectTotalSamples(kResultNoSavedFramesHistogram, 1);
   ExpectResultBucketCount(kResultNoSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
                           1);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 1);
-  ExpectTimeBucketCount(kIncompleteDurationNoSavedFramesHistogram, kDuration,
-                        1);
+  ExpectTotalSamples(kResultNoSavedFramesNotFrozenHistogram, 1);
+  ExpectResultBucketCount(kResultNoSavedFramesNotFrozenHistogram,
+                          TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
+                          1);
 
   const auto start2 = base::TimeTicks::Now();
   auto callback2 = tab_switch_time_recorder_.TabWasShown(
@@ -322,19 +379,40 @@
       end2, end2 - start2, gfx::PresentationFeedback::Flags::kHWCompletion);
   std::move(callback2).Run(presentation_feedback);
 
-  ExpectTotalSamples(kDurationWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kResultWithSavedFramesHistogram, 0);
-  ExpectTotalSamples(kIncompleteDurationWithSavedFramesHistogram, 0);
+  ExpectHistogramsEmptyExcept(
+      {kIncompleteDurationNoSavedFramesHistogram,
+       kIncompleteDurationNoSavedFramesNotFrozenHistogram,
+       kDurationNoSavedFramesHistogram,
+       kDurationNoSavedFramesNotFrozenHistogram, kResultNoSavedFramesHistogram,
+       kResultNoSavedFramesNotFrozenHistogram});
+
+  // Duration.
+  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 1);
+  ExpectTimeBucketCount(kIncompleteDurationNoSavedFramesHistogram, kDuration,
+                        1);
+  ExpectTotalSamples(kIncompleteDurationNoSavedFramesNotFrozenHistogram, 1);
+  ExpectTimeBucketCount(kIncompleteDurationNoSavedFramesNotFrozenHistogram,
+                        kDuration, 1);
 
   ExpectTotalSamples(kDurationNoSavedFramesHistogram, 1);
   ExpectTimeBucketCount(kDurationNoSavedFramesHistogram, kOtherDuration, 1);
+  ExpectTotalSamples(kDurationNoSavedFramesNotFrozenHistogram, 1);
+  ExpectTimeBucketCount(kDurationNoSavedFramesNotFrozenHistogram,
+                        kOtherDuration, 1);
+
+  // Result.
   ExpectTotalSamples(kResultNoSavedFramesHistogram, 2);
   ExpectResultBucketCount(kResultNoSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
                           1);
   ExpectResultBucketCount(kResultNoSavedFramesHistogram,
                           TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
-  ExpectTotalSamples(kIncompleteDurationNoSavedFramesHistogram, 1);
+  ExpectTotalSamples(kResultNoSavedFramesNotFrozenHistogram, 2);
+  ExpectResultBucketCount(kResultNoSavedFramesNotFrozenHistogram,
+                          TabSwitchTimeRecorder::TabSwitchResult::kIncomplete,
+                          1);
+  ExpectResultBucketCount(kResultNoSavedFramesNotFrozenHistogram,
+                          TabSwitchTimeRecorder::TabSwitchResult::kSuccess, 1);
 }
 
 }  // namespace content
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc
index 456df42..af06d78 100644
--- a/content/public/app/content_main_delegate.cc
+++ b/content/public/app/content_main_delegate.cc
@@ -55,6 +55,10 @@
   return 0;
 }
 
+bool ContentMainDelegate::ShouldLockSchemeRegistry() {
+  return true;
+}
+
 service_manager::ProcessType ContentMainDelegate::OverrideProcessType() {
   return service_manager::ProcessType::kDefault;
 }
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h
index d4f3b809..94501a9 100644
--- a/content/public/app/content_main_delegate.h
+++ b/content/public/app/content_main_delegate.h
@@ -88,6 +88,20 @@
   virtual void ZygoteForked() {}
 #endif  // defined(OS_LINUX)
 
+  // Allows the embedder to prevent locking the scheme registry. The scheme
+  // registry is the list of URL schemes we recognize, with some additional
+  // information about each scheme such as whether it expects a host. The
+  // scheme registry is not thread-safe, so by default it is locked before any
+  // threads are created to ensure single-threaded access. An embedder can
+  // override this to prevent the scheme registry from being locked during
+  // startup, but if they do so then they are responsible for making sure that
+  // the registry is only accessed in a thread-safe way, and for calling
+  // url::LockSchemeRegistries() when initialization is complete. If possible,
+  // prefer registering additional schemes through
+  // ContentClient::AddAdditionalSchemes over preventing the scheme registry
+  // from being locked.
+  virtual bool ShouldLockSchemeRegistry();
+
   // Fatal errors during initialization are reported by this function, so that
   // the embedder can implement graceful exit by displaying some message and
   // returning initialization error code. Default behavior is CHECK(false).
diff --git a/content/public/app/mac_helpers.gni b/content/public/app/mac_helpers.gni
new file mode 100644
index 0000000..b7ada75
--- /dev/null
+++ b/content/public/app/mac_helpers.gni
@@ -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.
+
+# This list defines variants of the helper app bundles that macOS //content
+# embedders need to produce. The different variants are code signed with
+# different entitlements, which afford different capabilities depending on the
+# requirements of the process.
+#
+# This list should be kept in sync with the enum options defined in
+# //content/public/common/child_process_host.h.
+#
+# Each element of the list list is a tuple representing a helper variant. The
+# elements of the tuple are:
+#   target name - A short name to be used when defining the target for that
+#                 helper variant.
+#   bundle ID suffix - A string fragment to append to the CFBundleIdentifier of
+#                      the helper.
+#   app name suffix - A string fragment to append to the outer bundle name as
+#                     well as the inner executable. This should be reflected in
+#                     the target's output_name.
+content_mac_helpers = [
+  # The basic helper with no special entitlements.
+  [
+    "default",
+    "",
+    "",
+  ],
+
+  # A helper with the capability to JIT (execute writable memory), needed by V8,
+  # and used to run renderer processes.
+  [
+    "renderer",
+    ".renderer",
+    " (Renderer)",
+  ],
+
+  # A helper that does not perform library validation, allowing code not signed
+  # by either Apple or the signing identity to be loaded, and that can execute
+  # unsigned memory. This is used by binary plugins like Flash.
+  [
+    "plugin",
+    ".plugin",
+    " (Plugin)",
+  ],
+]
diff --git a/content/public/common/child_process_host.h b/content/public/common/child_process_host.h
index 8f26d3b..63e27bb 100644
--- a/content/public/common/child_process_host.h
+++ b/content/public/common/child_process_host.h
@@ -60,7 +60,27 @@
     // gdb). In this case, you'd use GetChildPath to get the real executable
     // file name, and then prepend the GDB command to the command line.
     CHILD_ALLOW_SELF = 1 << 0,
-#endif  // defined(OS_LINUX)
+#elif defined(OS_MACOSX)
+    // Note, on macOS these are not bitwise flags and each value is mutually
+    // exclusive with the others. Each one of these options should correspond
+    // to a value in //content/public/app/mac_helpers.gni.
+
+    // Starts a child process with the macOS entitlement that allows JIT (i.e.
+    // memory that is writable and executable). In order to make use of this,
+    // memory cannot simply be allocated as read-write-execute; instead, the
+    // MAP_JIT flag must be passed to mmap() when allocating the memory region
+    // into which the writable-and-executable data are stored.
+    CHILD_RENDERER,
+
+    // Starts a child process with the macOS entitlement that ignores the
+    // library validation code signing enforcement. Library validation mandates
+    // that all executable pages be backed by a code signature that either 1)
+    // is signed by Apple, or 2) signed by the same Team ID as the main
+    // executable. Binary plug-ins that are not always signed by the same Team
+    // ID as the main binary, so this flag should be used when needing to load
+    // third-party plug-ins.
+    CHILD_PLUGIN,
+#endif
   };
 
   // Returns the pathname to be used for a child process.  If a subprocess
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 5105923..0dc9814 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -5,7 +5,11 @@
 #include "content/public/test/browser_test_base.h"
 
 #include <stddef.h>
+
 #include <iostream>
+#include <memory>
+#include <utility>
+#include <vector>
 
 #include "base/base_switches.h"
 #include "base/bind.h"
@@ -43,6 +47,7 @@
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/no_renderer_crashes_assertion.h"
 #include "content/public/test/test_launcher.h"
 #include "content/public/test/test_utils.h"
 #include "content/test/content_browser_sanity_checker.h"
@@ -491,6 +496,16 @@
     // otherwise the test body will have to do it in order to use RunLoop for
     // waiting.
     base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
+
+#if !defined(OS_ANDROID)
+    // Fail the test if a renderer crashes while the test is running.
+    //
+    // This cannot be enabled on Android, because of renderer kills triggered
+    // aggressively by the OS itself.
+    no_renderer_crashes_assertion_ =
+        std::make_unique<NoRendererCrashesAssertion>();
+#endif
+
     PreRunTestOnMainThread();
     std::unique_ptr<InitialNavigationObserver> initial_navigation_observer;
     if (initial_web_contents_ &&
diff --git a/content/public/test/browser_test_base.h b/content/public/test/browser_test_base.h
index d2ad9f1..9763736db 100644
--- a/content/public/test/browser_test_base.h
+++ b/content/public/test/browser_test_base.h
@@ -12,6 +12,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
+#include "content/public/test/no_renderer_crashes_assertion.h"
 #include "content/public/test/test_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
@@ -206,6 +207,8 @@
   // not run and report a false positive result.
   bool set_up_called_;
 
+  std::unique_ptr<NoRendererCrashesAssertion> no_renderer_crashes_assertion_;
+
   bool initialized_network_process_ = false;
 
 #if defined(OS_POSIX)
diff --git a/content/public/test/content_test_suite_base.cc b/content/public/test/content_test_suite_base.cc
index bab9080..c1a65c7a 100644
--- a/content/public/test/content_test_suite_base.cc
+++ b/content/public/test/content_test_suite_base.cc
@@ -17,7 +17,6 @@
 #include "content/public/common/content_client.h"
 #include "content/renderer/in_process_renderer_thread.h"
 #include "content/utility/in_process_utility_thread.h"
-#include "services/network/network_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/ui_base_paths.h"
@@ -48,11 +47,6 @@
 void ContentTestSuiteBase::Initialize() {
   base::TestSuite::Initialize();
 
-  // Tell the network service to not create its own NetworkChangeNotifier
-  // instance, since it will get leaked and can mess with future tests.
-  // TODO(crbug.com/901092): Remove once the network service cleans itself up.
-  network::NetworkService::DisableNetworkChangeNotifierForTesting();
-
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
   gin::V8Initializer::LoadV8Snapshot(kSnapshotType);
   gin::V8Initializer::LoadV8Natives();
diff --git a/content/public/test/network_service_test_helper.cc b/content/public/test/network_service_test_helper.cc
index ef2de1f5..552ba2a4 100644
--- a/content/public/test/network_service_test_helper.cc
+++ b/content/public/test/network_service_test_helper.cc
@@ -208,6 +208,15 @@
     std::move(callback).Run(latest_memory_pressure_level_);
   }
 
+  void GetPeerToPeerConnectionsCountChange(
+      GetPeerToPeerConnectionsCountChangeCallback callback) override {
+    uint32_t count = network::NetworkService::GetNetworkServiceForTesting()
+                         ->network_quality_estimator()
+                         ->GetPeerToPeerConnectionsCountChange();
+
+    std::move(callback).Run(count);
+  }
+
   void GetEnvironmentVariableValue(
       const std::string& name,
       GetEnvironmentVariableValueCallback callback) override {
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index b3f0f01..5fc82ba 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -34,7 +34,6 @@
 #include "content/test/test_render_view_host_factory.h"
 #include "content/test/test_render_widget_host_factory.h"
 #include "content/test/test_web_contents.h"
-#include "net/base/network_change_notifier.h"
 #include "ui/base/material_design/material_design_controller.h"
 
 #if defined(OS_ANDROID)
@@ -229,12 +228,6 @@
 }
 
 void RenderViewHostTestHarness::SetUp() {
-  // Create and own a NetworkChangeNotifier so that it will not be created
-  // during the initialization of the global leaky singleton NetworkService. The
-  // global NetworkService's NetworkChangeNotifier can affect subsequent unit
-  // tests.
-  network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
-
   ui::MaterialDesignController::Initialize();
 
   rvh_test_enabler_.reset(new RenderViewHostTestEnabler);
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index 02a93e44..7c78035 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -34,10 +34,6 @@
 class Screen;
 }
 
-namespace net {
-class NetworkChangeNotifier;
-}
-
 namespace ui {
 class ScopedOleInitializer;
 }
@@ -262,8 +258,6 @@
 
   std::unique_ptr<TestBrowserThreadBundle> thread_bundle_;
 
-  std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
-
   std::unique_ptr<ContentBrowserSanityChecker> sanity_checker_;
 
   std::unique_ptr<BrowserContext> browser_context_;
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index 4842e09..ce56f14 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -117,10 +117,6 @@
                bool has_alpha,
                bool use_stencil) override {}
   uint32_t GetFramebufferCopyTextureFormat() override { return 0; }
-  std::unique_ptr<viz::OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() override {
-    return nullptr;
-  }
   bool IsDisplayedAsOverlayPlane() const override { return false; }
   unsigned GetOverlayTextureId() const override { return 0; }
   gfx::BufferFormat GetOverlayBufferFormat() const override {
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index ce4946f4..6849432 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -18,6 +18,7 @@
 } else if (is_mac) {
   import("//build/config/mac/rules.gni")
   import("//build/mac/tweak_info_plist.gni")
+  import("//content/public/app/mac_helpers.gni")
   import("//third_party/icu/config.gni")
   import("//ui/gl/features.gni")
   import("//v8/gni/v8.gni")
@@ -712,16 +713,20 @@
   bundle_data("content_shell_framework_helpers") {
     testonly = true
     sources = [
-      "$root_out_dir/$content_shell_helper_name.app",
       "$root_out_dir/chrome_crashpad_handler",
     ]
     outputs = [
       "{{bundle_contents_dir}}/Helpers/{{source_file_part}}",
     ]
     public_deps = [
-      ":content_shell_helper_app",
       "//components/crash/content/app:chrome_crashpad_handler",
     ]
+    foreach(helper_params, content_mac_helpers) {
+      sources += [
+        "$root_out_dir/${content_shell_helper_name}${helper_params[2]}.app",
+      ]
+      public_deps += [ ":content_shell_helper_app_${helper_params[0]}" ]
+    }
   }
 
   tweak_info_plist("content_shell_framework_plist") {
@@ -805,28 +810,49 @@
     ]
   }
 
-  mac_app_bundle("content_shell_helper_app") {
-    testonly = true
-    output_name = content_shell_helper_name
-    sources = [
-      "app/shell_main_mac.cc",
-    ]
-    defines = [
-      "HELPER_EXECUTABLE",
-      "SHELL_PRODUCT_NAME=\"$content_shell_product_name\"",
-    ]
-    deps = [
-      "//sandbox/mac:seatbelt",
-    ]
-    ldflags = [
-      # The helper is in Content Shell.app/Contents/Frameworks/
-      #     Content Shell Framework.framework/Versions/C/Helpers/
-      #     Content Shell Helper.app/Contents/MacOS/
-      # so set rpath up to the base.
-      "-rpath",
-      "@executable_path/../../../../../../../../../..",
-    ]
-    info_plist_target = ":content_shell_helper_plist"
+  template("content_shell_helper_app") {
+    mac_app_bundle(target_name) {
+      assert(defined(invoker.helper_name_suffix))
+      assert(defined(invoker.helper_bundle_id_suffix))
+
+      testonly = true
+
+      output_name = content_shell_helper_name + invoker.helper_name_suffix
+
+      sources = [
+        "app/shell_main_mac.cc",
+      ]
+      defines = [
+        "HELPER_EXECUTABLE",
+        "SHELL_PRODUCT_NAME=\"$content_shell_product_name\"",
+      ]
+      extra_substitutions = [
+        "CONTENT_SHELL_HELPER_SUFFIX=${invoker.helper_name_suffix}",
+        "CONTENT_SHELL_HELPER_BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
+      ]
+      deps = [
+        "//sandbox/mac:seatbelt",
+      ]
+      ldflags = [
+        # The helper is in Content Shell.app/Contents/Frameworks/
+        #     Content Shell Framework.framework/Versions/C/Helpers/
+        #     Content Shell Helper.app/Contents/MacOS/
+        # so set rpath up to the base.
+        "-rpath",
+        "@executable_path/../../../../../../../../../..",
+      ]
+      info_plist_target = ":content_shell_helper_plist"
+    }
+  }
+
+  foreach(helper_params, content_mac_helpers) {
+    _helper_target = helper_params[0]
+    _helper_bundle_id = helper_params[1]
+    _helper_suffix = helper_params[2]
+    content_shell_helper_app("content_shell_helper_app_${_helper_target}") {
+      helper_name_suffix = _helper_suffix
+      helper_bundle_id_suffix = _helper_bundle_id
+    }
   }
 
   bundle_data("content_shell_framework_bundle_data") {
diff --git a/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 b/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2
index fd0e1513..3bac4f2c 100644
--- a/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2
+++ b/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.content_browsertests_apk">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.CAMERA" />
diff --git a/content/shell/android/java/src/org/chromium/content_shell/Shell.java b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
index fcbfe1c..e9beb18 100644
--- a/content/shell/android/java/src/org/chromium/content_shell/Shell.java
+++ b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
@@ -296,6 +296,8 @@
         Context context = getContext();
         ContentView cv = ContentView.createContentView(context, webContents);
         mViewAndroidDelegate = new ShellViewAndroidDelegate(cv);
+        assert (mWebContents != webContents);
+        if (mWebContents != null) mWebContents.clearNativeReference();
         webContents.initialize(
                 "", mViewAndroidDelegate, cv, mWindow, WebContents.createDefaultInternalsHolder());
         mWebContents = webContents;
diff --git a/content/shell/android/javatests/AndroidManifest.xml b/content/shell/android/javatests/AndroidManifest.xml
index 24ae32d..8c1326f 100644
--- a/content/shell/android/javatests/AndroidManifest.xml
+++ b/content/shell/android/javatests/AndroidManifest.xml
@@ -6,7 +6,6 @@
        doesn't ignore this. -->
   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.chromium.content_shell_apk.tests">
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
     <!-- We add an application tag here just so that we can indicate that this
          package needs to link against the android.test library, which is
diff --git a/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2 b/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2
index aea6429..834e677 100644
--- a/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2
+++ b/content/shell/android/linker_test_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.chromium_linker_test_apk">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.CAMERA" />
diff --git a/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 b/content/shell/android/shell_apk/AndroidManifest.xml.jinja2
index e2c85cd..588468a 100644
--- a/content/shell/android/shell_apk/AndroidManifest.xml.jinja2
+++ b/content/shell/android/shell_apk/AndroidManifest.xml.jinja2
@@ -9,7 +9,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.content_shell_apk">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.CAMERA"/>
diff --git a/content/shell/app/helper-Info.plist b/content/shell/app/helper-Info.plist
index 298f2f7..2503b29 100644
--- a/content/shell/app/helper-Info.plist
+++ b/content/shell/app/helper-Info.plist
@@ -9,7 +9,7 @@
 	<key>CFBundleExecutable</key>
 	<string>${EXECUTABLE_NAME}</string>
 	<key>CFBundleIdentifier</key>
-	<string>org.chromium.ContentShell.helper</string>
+	<string>org.chromium.ContentShell.helper${CONTENT_SHELL_HELPER_BUNDLE_ID_SUFFIX}</string>
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index ab56065..3c3ccc0f 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -182,3 +182,7 @@
 # Failing on Linux, both Intel HD 630 and NVIDIA Quadro P400
 crbug.com/974380 [ linux ] Pixel_OffscreenCanvasUnaccelerated2DGPUCompositing [ Failure ]
 crbug.com/974380 [ linux ] Pixel_OffscreenCanvasUnaccelerated2DGPUCompositingWorker [ Failure ]
+
+# Producing blank images on Macmini and Macbook Pro
+crbug.com/974380 [ mac ] Pixel_OffscreenCanvasUnaccelerated2DGPUCompositingWorker [ Failure ]
+crbug.com/974383 [ mac ] Pixel_CanvasDisplayLinearRGBAccelerated2D [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 5c45ab3..937aa83 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -248,7 +248,7 @@
 crbug.com/602688 [ opengl win passthrough intel ] conformance2/glsl3/vector-dynamic-indexing.html [ Failure ]
 crbug.com/angleproject/2880 [ opengl win passthrough intel ] deqp/functional/gles3/shaderbuiltinvar.html [ Failure ]
 crbug.com/957631 [ opengl win passthrough intel ] conformance2/rendering/element-index-uint.html [ Failure ]
-crbug.com/963450 [ opengl win passthrough intel ] deqp/functional/gles3/textureshadow/cube_* [ RetryOnFailure ]
+crbug.com/963450 [ opengl win passthrough intel ] deqp/functional/gles3/textureshadow/cube_* [ Failure ]
 
 # Passthrough command decoder / Linux / OpenGL / NVIDIA
 crbug.com/773861 [ opengl linux passthrough nvidia ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ]
diff --git a/docs/android_dynamic_feature_modules.md b/docs/android_dynamic_feature_modules.md
index edc18fe..1b53699 100644
--- a/docs/android_dynamic_feature_modules.md
+++ b/docs/android_dynamic_feature_modules.md
@@ -54,11 +54,6 @@
     featureSplit="foo"
     package="{{manifest_package}}">
 
-    <!-- For Chrome Modern use android:minSdkVersion="21". -->
-    <uses-sdk
-        android:minSdkVersion="24"
-        android:targetSdkVersion="{{target_sdk_version}}" />
-
     <!-- dist:onDemand="true" makes this a separately installed module.
          dist:onDemand="false" would always install the module alongside the
          rest of Chrome. -->
diff --git a/docs/code_coverage_in_gerrit.md b/docs/code_coverage_in_gerrit.md
index 91a6a1f8..1954104 100644
--- a/docs/code_coverage_in_gerrit.md
+++ b/docs/code_coverage_in_gerrit.md
@@ -1,19 +1,28 @@
 # Code Coverage in Gerrit
 
-**Have you ever wanted to know if your CL has enough code coverage?** You can
-see uncovered lines in Gerrit, which can help you figure out if your CL or the
-CL you're reviewing needs more/better tests.
+Tests are critical because they find bugs and regressions, enforce better
+designs and make code easier to maintain. **Code coverage helps you ensure your
+tests are thorough**.
 
-To generate code coverage data for your CL, **manually** trigger the
-experimental coverage CQ builder: *linux-coverage-rel*:
+Chromium CLs can show a line-by-line breakdown of test coverage. **You can use
+the code coverage trybot to ensure you only submit well-tested code**.
+
+To see code coverage for a Chromium CL, trigger the code coverage trybot
+**linux-coverage-rel**:
 
 ![choose_tryjobs] ![linux_coverage_rel]
 
-Once the build finishes and code coverage data are processed successfully, look
-at the right column of the side by side diff view to see which lines are **not**
-covered:
+Once the build finishes and code coverage data is processed successfully, **look
+at the right column of the side by side diff view to see coverage information**:
 
-![uncovered_lines]
+![code_coverage_annotations]
+
+The code coverage tool currently **supports C/C++ code for Chrome on Linux**;
+support for more platforms and more languages is in progress.
+
+The code coverage trybot has been **rolled out to a 10% experiment**, and once
+we're more comfortable in its stability, we plan to enable it by default and
+expand it to more platforms.
 
 ## Contacts
 
@@ -24,17 +33,9 @@
 For questions and general discussions, please join [code-coverage group].
 
 ## FAQ
-### Why is the coverage CQ builder needs to be triggered manually?
-
-We're still evaluating the stability of the code coverage pipeline, and once
-it's proven to be stable, the experimental builder will be merged into one of
-the existing CQ builders, and at that time, the feature will be available by
-default.
-
 ### Why is coverage not shown even though the try job finished successfully?
 
 There are several possible reasons:
-* All the added/modified lines are covered.
 * A particular source file/test may not be available on a particular project or
 platform. As of now, only `chromium/src` project and `Linux` platform is
 supported.
@@ -45,13 +46,14 @@
 Please refer to [code_coverage.md] for how code coverage works in Chromium in
 general, and specifically, for per-CL coverage in Gerrit, the
 [clang_code_coverage_wrapper] is used to compile and instrument ONLY the source
-files that are affected by the CL and a [chromium-coverage Gerrit plugin] is
-used to annotate uncovered lines in Gerrit.
+files that are affected by the CL for the sake of performance and a
+[chromium-coverage Gerrit plugin] is used to display code coverage information
+in Gerrit.
 
 
 [choose_tryjobs]: images/code_coverage_choose_tryjobs.png
 [linux_coverage_rel]: images/code_coverage_linux_coverage_rel.png
-[uncovered_lines]: images/code_coverage_uncovered_lines.png
+[code_coverage_annotations]: images/code_coverage_annotations.png
 [file a bug]: https://bugs.chromium.org/p/chromium/issues/entry?components=Tools%3ECodeCoverage
 [code-coverage group]: https://groups.google.com/a/chromium.org/forum/#!forum/code-coverage
 [code_coverage.md]: code_coverage.md
diff --git a/docs/images/code_coverage_annotations.png b/docs/images/code_coverage_annotations.png
new file mode 100644
index 0000000..4a3418e
--- /dev/null
+++ b/docs/images/code_coverage_annotations.png
Binary files differ
diff --git a/docs/images/code_coverage_uncovered_lines.png b/docs/images/code_coverage_uncovered_lines.png
deleted file mode 100644
index 22150f4..0000000
--- a/docs/images/code_coverage_uncovered_lines.png
+++ /dev/null
Binary files differ
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
index 50ffcdd..dda8e38 100644
--- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -33,7 +33,6 @@
 #include "extensions/test/result_catcher.h"
 #include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
-#include "net/log/test_net_log.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gmock_mutant.h"
@@ -253,7 +252,6 @@
   net::IPEndPoint ip_endpoint_;
   LastError last_error_;
   CastSocket::Observer* message_observer_;
-  net::TestNetLog capturing_net_log_;
   int channel_id_;
   base::test::ScopedFeatureList feature_list_;
 };
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index d5f57eb..a88384de 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -1544,14 +1544,6 @@
     if (listener->extra_info_spec &
         (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
       listener->blocked_requests.insert(request->id);
-      // If this is the first delegate blocking the request, go ahead and log
-      // it.
-      if (num_handlers_blocking == 0) {
-        std::string delegate_info = l10n_util::GetStringFUTF8(
-            IDS_LOAD_STATE_PARAMETER_EXTENSION,
-            base::UTF8ToUTF16(listener->extension_name));
-        request->logger->LogBlockedBy(delegate_info);
-      }
       ++num_handlers_blocking;
     }
   }
@@ -2329,21 +2321,7 @@
   }
 
   if (num_handlers_blocking == 0) {
-    blocked_request.request->logger->LogUnblocked();
     ExecuteDeltas(browser_context, blocked_request.request, true);
-  } else {
-    // Log that the request was blocked by an extension.
-    Listeners& listeners = listeners_[browser_context][event_name];
-
-    for (const auto& listener : listeners) {
-      if (!base::Contains(listener->blocked_requests, request_id))
-        continue;
-      std::string delegate_info = l10n_util::GetStringFUTF8(
-          IDS_LOAD_STATE_PARAMETER_EXTENSION,
-          base::UTF8ToUTF16(listener->extension_name));
-      blocked_request.request->logger->LogBlockedBy(delegate_info);
-      break;
-    }
   }
 }
 
@@ -2390,15 +2368,14 @@
   deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
 
   bool canceled = false;
-  helpers::MergeCancelOfResponses(blocked_request.response_deltas, &canceled,
-                                  request->logger.get());
+  helpers::MergeCancelOfResponses(blocked_request.response_deltas, &canceled);
 
   extension_web_request_api_helpers::IgnoredActions ignored_actions;
   if (blocked_request.event == kOnBeforeRequest) {
     CHECK(!blocked_request.callback.is_null());
     helpers::MergeOnBeforeRequestResponses(
         request->url, blocked_request.response_deltas, blocked_request.new_url,
-        &ignored_actions, request->logger.get());
+        &ignored_actions);
   } else if (blocked_request.event == kOnBeforeSendHeaders) {
     CHECK(!blocked_request.before_send_headers_callback.is_null());
     helpers::MergeOnBeforeSendHeadersResponses(
@@ -2424,7 +2401,7 @@
     CHECK(!blocked_request.auth_callback.is_null());
     credentials_set = helpers::MergeOnAuthRequiredResponses(
         blocked_request.response_deltas, blocked_request.auth_credentials,
-        &ignored_actions, request->logger.get());
+        &ignored_actions);
   } else {
     NOTREACHED();
   }
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.cc b/extensions/browser/api/web_request/web_request_api_helpers.cc
index 1ea4fff2..9d9001c 100644
--- a/extensions/browser/api/web_request/web_request_api_helpers.cc
+++ b/extensions/browser/api/web_request/web_request_api_helpers.cc
@@ -483,30 +483,6 @@
 EventResponseDelta::~EventResponseDelta() {
 }
 
-// Creates NetLog parameters to indicate that an extension modified a request.
-std::unique_ptr<base::Value> MakeHeaderModificationLogValue(
-    const EventResponseDelta* delta) {
-  auto dict = std::make_unique<base::DictionaryValue>();
-  dict->SetString("extension_id", delta->extension_id);
-
-  auto modified_headers = std::make_unique<base::ListValue>();
-  net::HttpRequestHeaders::Iterator modification(
-      delta->modified_request_headers);
-  while (modification.GetNext()) {
-    std::string line = modification.name() + ": " + modification.value();
-    modified_headers->AppendString(line);
-  }
-  dict->Set("modified_headers", std::move(modified_headers));
-
-  auto deleted_headers = std::make_unique<base::ListValue>();
-  for (auto key = delta->deleted_request_headers.cbegin();
-       key != delta->deleted_request_headers.cend(); ++key) {
-    deleted_headers->AppendString(*key);
-  }
-  dict->Set("deleted_headers", std::move(deleted_headers));
-  return dict;
-}
-
 bool InDecreasingExtensionInstallationTimeOrder(const EventResponseDelta& a,
                                                 const EventResponseDelta& b) {
   return a.extension_install_time > b.extension_install_time;
@@ -668,14 +644,10 @@
   return result;
 }
 
-void MergeCancelOfResponses(const EventResponseDeltas& deltas,
-                            bool* canceled,
-                            extensions::WebRequestInfoLogger* logger) {
+void MergeCancelOfResponses(const EventResponseDeltas& deltas, bool* canceled) {
   for (const auto& delta : deltas) {
     if (delta.cancel) {
       *canceled = true;
-      logger->LogEvent(net::NetLogEventType::CHROME_EXTENSION_ABORTED_REQUEST,
-                       delta.extension_id);
       break;
     }
   }
@@ -693,7 +665,6 @@
     const EventResponseDeltas& deltas,
     GURL* new_url,
     IgnoredActions* ignored_actions,
-    extensions::WebRequestInfoLogger* logger,
     bool consider_only_cancel_scheme_urls) {
   // Redirecting WebSocket handshake request is prohibited.
   if (url.SchemeIsWSOrWSS())
@@ -713,15 +684,9 @@
     if (!redirected || *new_url == delta.new_url) {
       *new_url = delta.new_url;
       redirected = true;
-      logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_REDIRECTED_REQUEST,
-          delta.extension_id);
     } else {
       ignored_actions->emplace_back(delta.extension_id,
                                     web_request::IGNORED_ACTION_TYPE_REDIRECT);
-      logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
-          delta.extension_id);
     }
   }
   return redirected;
@@ -730,12 +695,11 @@
 void MergeRedirectUrlOfResponses(const GURL& url,
                                  const EventResponseDeltas& deltas,
                                  GURL* new_url,
-                                 IgnoredActions* ignored_actions,
-                                 extensions::WebRequestInfoLogger* logger) {
+                                 IgnoredActions* ignored_actions) {
   // First handle only redirects to data:// URLs and about:blank. These are a
   // special case as they represent a way of cancelling a request.
   if (MergeRedirectUrlOfResponsesHelper(url, deltas, new_url, ignored_actions,
-                                        logger, true)) {
+                                        true)) {
     // If any extension cancelled a request by redirecting to a data:// URL or
     // about:blank, we don't consider the other redirects.
     return;
@@ -743,15 +707,14 @@
 
   // Handle all other redirects.
   MergeRedirectUrlOfResponsesHelper(url, deltas, new_url, ignored_actions,
-                                    logger, false);
+                                    false);
 }
 
 void MergeOnBeforeRequestResponses(const GURL& url,
                                    const EventResponseDeltas& deltas,
                                    GURL* new_url,
-                                   IgnoredActions* ignored_actions,
-                                   extensions::WebRequestInfoLogger* logger) {
-  MergeRedirectUrlOfResponses(url, deltas, new_url, ignored_actions, logger);
+                                   IgnoredActions* ignored_actions) {
+  MergeRedirectUrlOfResponses(url, deltas, new_url, ignored_actions);
 }
 
 static bool DoesRequestCookieMatchFilter(
@@ -879,8 +842,7 @@
 void MergeCookiesInOnBeforeSendHeadersResponses(
     const GURL& url,
     const EventResponseDeltas& deltas,
-    net::HttpRequestHeaders* request_headers,
-    extensions::WebRequestInfoLogger* logger) {
+    net::HttpRequestHeaders* request_headers) {
   // Skip all work if there are no registered cookie modifications.
   bool cookie_modifications_exist = false;
   for (const auto& delta : deltas) {
@@ -1020,16 +982,10 @@
           removed_headers->insert(base::ToLowerASCII(header));
         }
       }
-      request.logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_MODIFIED_HEADERS,
-          delta.extension_id);
       *request_headers_modified = true;
     } else {
       ignored_actions->emplace_back(
           delta.extension_id, web_request::IGNORED_ACTION_TYPE_REQUEST_HEADERS);
-      request.logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
-          delta.extension_id);
     }
   }
 
@@ -1067,8 +1023,8 @@
   record_request_headers(overridden_headers, &RecordRequestHeaderChanged);
 
   // Currently, conflicts are ignored while merging cookies.
-  MergeCookiesInOnBeforeSendHeadersResponses(
-      request.url, deltas, request_headers, request.logger.get());
+  MergeCookiesInOnBeforeSendHeadersResponses(request.url, deltas,
+                                             request_headers);
 }
 
 // Retrieves all cookies from |override_response_headers|.
@@ -1259,8 +1215,7 @@
     const GURL& url,
     const EventResponseDeltas& deltas,
     const net::HttpResponseHeaders* original_response_headers,
-    scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
-    extensions::WebRequestInfoLogger* logger) {
+    scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
   // Skip all work if there are no registered cookie modifications.
   bool cookie_modifications_exist = false;
   for (const auto& delta : base::Reversed(deltas)) {
@@ -1380,28 +1335,21 @@
               ->AddHeader(header.first + ": " + header.second);
         }
       }
-      request.logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_MODIFIED_HEADERS,
-          delta.extension_id);
       *response_headers_modified = true;
     } else {
       ignored_actions->emplace_back(
           delta.extension_id,
           web_request::IGNORED_ACTION_TYPE_RESPONSE_HEADERS);
-      request.logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
-          delta.extension_id);
     }
   }
 
   // Currently, conflicts are ignored while merging cookies.
-  MergeCookiesInOnHeadersReceivedResponses(
-      request.url, deltas, original_response_headers, override_response_headers,
-      request.logger.get());
+  MergeCookiesInOnHeadersReceivedResponses(request.url, deltas,
+                                           original_response_headers,
+                                           override_response_headers);
 
   GURL new_url;
-  MergeRedirectUrlOfResponses(request.url, deltas, &new_url, ignored_actions,
-                              request.logger.get());
+  MergeRedirectUrlOfResponses(request.url, deltas, &new_url, ignored_actions);
   if (new_url.is_valid()) {
     // Only create a copy if we really want to modify the response headers.
     if (override_response_headers->get() == NULL) {
@@ -1468,8 +1416,7 @@
 
 bool MergeOnAuthRequiredResponses(const EventResponseDeltas& deltas,
                                   net::AuthCredentials* auth_credentials,
-                                  IgnoredActions* ignored_actions,
-                                  extensions::WebRequestInfoLogger* logger) {
+                                  IgnoredActions* ignored_actions) {
   CHECK(auth_credentials);
   bool credentials_set = false;
 
@@ -1483,13 +1430,7 @@
       ignored_actions->emplace_back(
           delta.extension_id,
           web_request::IGNORED_ACTION_TYPE_AUTH_CREDENTIALS);
-      logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
-          delta.extension_id);
     } else {
-      logger->LogEvent(
-          net::NetLogEventType::CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS,
-          delta.extension_id);
       *auth_credentials = *delta.auth_credentials;
       credentials_set = true;
     }
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.h b/extensions/browser/api/web_request/web_request_api_helpers.h
index b02827fa..cdada0d 100644
--- a/extensions/browser/api/web_request/web_request_api_helpers.h
+++ b/extensions/browser/api/web_request/web_request_api_helpers.h
@@ -32,7 +32,6 @@
 
 namespace extensions {
 class Extension;
-class WebRequestInfoLogger;
 struct WebRequestInfo;
 }
 
@@ -399,37 +398,31 @@
 // These functions merge the responses (the |deltas|) of request handlers.
 // The |deltas| need to be sorted in decreasing order of precedence of
 // extensions. In case extensions had |deltas| that could not be honored, their
-// IDs are reported in |conflicting_extensions|. NetLog events that shall be
-// reported will be stored in |event_log_entries|.
+// IDs are reported in |conflicting_extensions|.
 
 // Stores in |canceled| whether any extension wanted to cancel the request.
-void MergeCancelOfResponses(const EventResponseDeltas& deltas,
-                            bool* canceled,
-                            extensions::WebRequestInfoLogger* logger);
+void MergeCancelOfResponses(const EventResponseDeltas& deltas, bool* canceled);
 // Stores in |*new_url| the redirect request of the extension with highest
 // precedence. Extensions that did not command to redirect the request are
 // ignored in this logic.
 void MergeRedirectUrlOfResponses(const GURL& url,
                                  const EventResponseDeltas& deltas,
                                  GURL* new_url,
-                                 IgnoredActions* ignored_actions,
-                                 extensions::WebRequestInfoLogger* logger);
+                                 IgnoredActions* ignored_actions);
 // Stores in |*new_url| the redirect request of the extension with highest
 // precedence. Extensions that did not command to redirect the request are
 // ignored in this logic.
 void MergeOnBeforeRequestResponses(const GURL& url,
                                    const EventResponseDeltas& deltas,
                                    GURL* new_url,
-                                   IgnoredActions* ignored_actions,
-                                   extensions::WebRequestInfoLogger* logger);
+                                   IgnoredActions* ignored_actions);
 // Modifies the "Cookie" header in |request_headers| according to
 // |deltas.request_cookie_modifications|. Conflicts are currently ignored
 // silently.
 void MergeCookiesInOnBeforeSendHeadersResponses(
     const GURL& gurl,
     const EventResponseDeltas& deltas,
-    net::HttpRequestHeaders* request_headers,
-    extensions::WebRequestInfoLogger* logger);
+    net::HttpRequestHeaders* request_headers);
 // Modifies the headers in |request_headers| according to |deltas|. Conflicts
 // are tried to be resolved.
 // Stores in |request_headers_modified| whether the request headers were
@@ -450,8 +443,7 @@
     const GURL& url,
     const EventResponseDeltas& deltas,
     const net::HttpResponseHeaders* original_response_headers,
-    scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
-    extensions::WebRequestInfoLogger* logger);
+    scoped_refptr<net::HttpResponseHeaders>* override_response_headers);
 // Stores a copy of |original_response_header| into |override_response_headers|
 // that is modified according to |deltas|. If |deltas| does not instruct to
 // modify the response headers, |override_response_headers| remains empty.
@@ -476,8 +468,7 @@
 // Returns whether authentication credentials are set.
 bool MergeOnAuthRequiredResponses(const EventResponseDeltas& deltas,
                                   net::AuthCredentials* auth_credentials,
-                                  IgnoredActions* ignored_actions,
-                                  extensions::WebRequestInfoLogger* logger);
+                                  IgnoredActions* ignored_actions);
 
 // Triggers clearing each renderer's in-memory cache the next time it navigates.
 void ClearCacheOnNavigation();
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc
index da2862e..7e1bb92e 100644
--- a/extensions/browser/api/web_request/web_request_info.cc
+++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -23,7 +23,6 @@
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/base/upload_data_stream.h"
 #include "net/base/upload_file_element_reader.h"
-#include "net/log/net_log_with_source.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/url_loader.h"
@@ -75,23 +74,6 @@
   DISALLOW_COPY_AND_ASSIGN(FileUploadDataSource);
 };
 
-// TODO(https://crbug.com/721414): Need a real implementation here to support
-// the Network Service case. For now this is only to prevent crashing.
-class NetworkServiceLogger : public WebRequestInfoLogger {
- public:
-  NetworkServiceLogger() = default;
-  ~NetworkServiceLogger() override = default;
-
-  // WebRequestInfo::Logger:
-  void LogEvent(net::NetLogEventType event_type,
-                const std::string& extension_id) override {}
-  void LogBlockedBy(const std::string& blocker_info) override {}
-  void LogUnblocked() override {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NetworkServiceLogger);
-};
-
 bool CreateUploadDataSourcesFromResourceRequest(
     const network::ResourceRequest& request,
     std::vector<std::unique_ptr<UploadDataSource>>* data_sources) {
@@ -193,7 +175,6 @@
       type(static_cast<content::ResourceType>(request.resource_type)),
       is_async(is_async),
       extra_request_headers(request.headers),
-      logger(std::make_unique<NetworkServiceLogger>()),
       resource_context(resource_context) {
   if (url.SchemeIsWSOrWSS())
     web_request_type = WebRequestResourceType::WEB_SOCKET;
@@ -267,7 +248,6 @@
       web_view_instance_id(params.web_view_instance_id),
       web_view_rules_registry_id(params.web_view_rules_registry_id),
       web_view_embedder_process_id(params.web_view_embedder_process_id),
-      logger(std::move(params.logger)),
       resource_context(params.resource_context) {}
 
 WebRequestInfo::~WebRequestInfo() = default;
diff --git a/extensions/browser/api/web_request/web_request_info.h b/extensions/browser/api/web_request/web_request_info.h
index 27520d2..925445b 100644
--- a/extensions/browser/api/web_request/web_request_info.h
+++ b/extensions/browser/api/web_request/web_request_info.h
@@ -21,7 +21,6 @@
 #include "extensions/browser/extension_api_frame_id_map.h"
 #include "ipc/ipc_message.h"
 #include "net/http/http_request_headers.h"
-#include "net/log/net_log_event_type.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -38,20 +37,6 @@
 
 class ExtensionNavigationUIData;
 
-// Helper interface used to delegate event logging operations relevant to an
-// in-process web request. This is a transitional interface to move WebRequest
-// code away from direct coupling to NetLog and will be removed once event
-// logging is done through the tracing subsystem instead of through net.
-class WebRequestInfoLogger {
- public:
-  virtual ~WebRequestInfoLogger() {}
-
-  virtual void LogEvent(net::NetLogEventType event_type,
-                        const std::string& extension_id) = 0;
-  virtual void LogBlockedBy(const std::string& blocker_info) = 0;
-  virtual void LogUnblocked() = 0;
-};
-
 // Helper struct to initialize WebRequestInfo.
 struct WebRequestInfoInitParams {
   WebRequestInfoInitParams();
@@ -91,7 +76,6 @@
   int web_view_instance_id = -1;
   int web_view_rules_registry_id = -1;
   int web_view_embedder_process_id = -1;
-  std::unique_ptr<WebRequestInfoLogger> logger;
   content::ResourceContext* resource_context = nullptr;
   base::Optional<ExtensionApiFrameIdMap::FrameData> frame_data;
 
@@ -189,10 +173,6 @@
   const int web_view_rules_registry_id;
   const int web_view_embedder_process_id;
 
-  // Helper used to log events relevant to WebRequest processing. This is always
-  // non-null.
-  const std::unique_ptr<WebRequestInfoLogger> logger;
-
   // The ResourceContext associated with this request. May be null.
   content::ResourceContext* const resource_context;
 
diff --git a/fuchsia/BUILD.gn b/fuchsia/BUILD.gn
index 6ba6259..f665f80 100644
--- a/fuchsia/BUILD.gn
+++ b/fuchsia/BUILD.gn
@@ -5,8 +5,6 @@
 assert(is_fuchsia)
 
 import("//build/config/fuchsia/fidl_library.gni")
-import("//build/util/process_version.gni")
-import("//fuchsia/cipd/test_archive.gni")
 
 fidl_library("cast_fidl") {
   library_name = "cast"
@@ -24,7 +22,17 @@
   ]
 }
 
+# DEPRECATED. Use //fuchsia/cipd instead.
+# TODO(crbug.com/974363): Remove this.
 if (is_official_build) {
+  group("archive_sources") {
+    testonly = true
+    deps = [
+      ":release_archives",
+      ":symbol_tarballs",
+    ]
+  }
+
   # Location where Fuchsia release archives and supporting files are placed.
   _release_artifact_root = "$root_out_dir/fuchsia_artifacts"
 
@@ -39,49 +47,11 @@
     "$root_gen_dir/fuchsia/runners/web_runner/web_runner.symbols.tar.bz2",
   ]
   _symbol_manifest = "$target_gen_dir/debug_symbols.json"
-  write_file(_symbol_manifest, _symbol_tarballs, "json")
-
-  # gn binary location.
-  if (host_os == "mac") {
-    _gn_path = "//buildtools/mac/gn"
-  } else if (host_os == "linux") {
-    _gn_path = "//buildtools/linux64/gn"
+  _symbol_manifest_contents = []
+  foreach(_symbol_file, _symbol_tarballs) {
+    _symbol_manifest_contents += [ get_path_info(_symbol_file, "file") ]
   }
-
-  # Produces a LICENSE file for Fuchsia packages.
-  _license_path = "$_release_artifact_root/LICENSE"
-  action("license") {
-    script = "//tools/licenses.py"
-    inputs = [
-      "$_gn_path",
-    ]
-    outputs = [
-      _license_path,
-    ]
-    args = [
-      "license_file",
-      rebase_path(_license_path, root_build_dir),
-      "--gn-target",
-      "//fuchsia/runners:web_runner_pkg",
-      "--gn-out-dir",
-      ".",
-    ]
-  }
-
-  # Extracts the numeric Chrome build ID and writes it to a file in the output
-  # directory.
-  #
-  # To check out the repository on the commit where the build ID was generated,
-  # simply call `git checkout <build-id>`, and Git will check out the commit
-  # associated with the <build-id> tag.
-  process_version("build_id") {
-    template_file = "cipd/build_id.template"
-    sources = [
-      "//chrome/VERSION",
-    ]
-    output = "$_release_artifact_root/build_id.txt"
-    process_only = true
-  }
+  write_file(_symbol_manifest, _symbol_manifest_contents, "json")
 
   # Puts copies of files at the top level of the CIPD archive's structure.
   copy("release_archives") {
@@ -105,57 +75,21 @@
   copy("symbol_tarballs") {
     sources = [
                 _symbol_manifest,
-                "$_release_artifact_root/build_id.txt",
-                _license_path,
+                "${root_gen_dir}/fuchsia/cipd/build_id.txt",
+                "${root_gen_dir}/fuchsia/cipd/LICENSE",
               ] + _symbol_tarballs
     outputs = [
       "$_symbol_artifact_root/{{source_file_part}}",
     ]
     deps = [
-      ":build_id",
-      ":license",
+      "//fuchsia/cipd:build_id",
+      "//fuchsia/cipd:license",
       "//fuchsia/engine:symbol_archive",
       "//fuchsia/http:symbol_archive",
       "//fuchsia/runners:cast_runner_symbol_archive",
       "//fuchsia/runners:web_runner_symbol_archive",
     ]
   }
-
-  cipd_archive("test_archive") {
-    cipd_manifest_name = "tests.yaml"
-    cipd_path = "chromium/fuchsia/tests-\${targetarch}"
-    cipd_description = "Prebuilt Chromium tests for Fuchsia."
-    include_manifest = true
-
-    packages = [
-      "//base:base_unittests",
-      "//fuchsia/runners:cast_runner_integration_tests",
-      "//fuchsia/runners:web_runner_integration_tests",
-      "//ipc:ipc_tests",
-      "//media:media_unittests",
-      "//mojo:mojo_unittests",
-      "//skia:skia_unittests",
-      "//third_party/blink/common:blink_common_unittests",
-    ]
-
-    deps = [
-      ":build_id",
-      ":license",
-    ]
-  }
-
-  # Specifies the build steps that must be performed before the creation of
-  # a CIPD archive.
-  group("archive_sources") {
-    testonly = true
-    deps = [
-      ":build_id",
-      ":license",
-      ":release_archives",
-      ":symbol_tarballs",
-      ":test_archive",
-    ]
-  }
 }  # is_official_build
 
 # Used by the top-level "gn_all" target to discover Fuchsia build targets.
@@ -173,4 +107,8 @@
     "runners:web_runner",
     "//chromecast/bindings:bindings_manager_fuchsia",
   ]
+
+  if (is_official_build) {
+    deps += [ "cipd" ]
+  }
 }
diff --git a/fuchsia/cipd/BUILD.gn b/fuchsia/cipd/BUILD.gn
new file mode 100644
index 0000000..d8fed68
--- /dev/null
+++ b/fuchsia/cipd/BUILD.gn
@@ -0,0 +1,213 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Build targets for constructing CIPD release archives.
+
+assert(is_fuchsia)
+
+import("//build/util/process_version.gni")
+
+# gn binary location.
+if (host_os == "mac") {
+  _gn_path = "//buildtools/mac/gn"
+} else if (host_os == "linux") {
+  _gn_path = "//buildtools/linux64/gn"
+}
+
+# Produces a consolidated license file.
+action("license") {
+  _license_path = "${target_gen_dir}/LICENSE"
+  script = "//tools/licenses.py"
+  inputs = [
+    "$_gn_path",
+  ]
+  outputs = [
+    _license_path,
+  ]
+  args = [
+    "license_file",
+    rebase_path(_license_path, root_build_dir),
+    "--gn-target",
+    "//fuchsia/runners:web_runner_pkg",
+    "--gn-out-dir",
+    ".",
+  ]
+}
+
+# Extracts the numeric Chrome build ID and writes it to a file in the output
+# directory.
+#
+# To check out the repository on the commit where the build ID was generated,
+# simply call `git checkout <build-id>`, and Git will check out the commit
+# associated with the <build-id> tag.
+process_version("build_id") {
+  template_file = "build_id.template"
+  sources = [
+    "//chrome/VERSION",
+  ]
+  output = "${target_gen_dir}/build_id.txt"
+  process_only = true
+}
+
+# Prepares a CIPD archive and generates a manifest file.
+#
+# Parameters:
+#   cipd_manifest_name: The filename to use for the generated CIPD YAML file.
+#   cipd_path: The path where the package will be located inside the CIPD
+#              repository.
+#   cipd_description: Sets the "description" field in CIPD metadata.
+#   deps: A list of targets to build prior to copying files.
+#   sources: A list of files to copy into the staging root.
+template("cipd_archive") {
+  forward_variables_from(invoker,
+                         [
+                           "cipd_manifest_name",
+                           "cipd_path",
+                           "cipd_description",
+                           "deps",
+                           "sources",
+                         ])
+  archive_staging_dir = "${target_gen_dir}/${target_name}"
+
+  yaml_contents = [
+    "package: ${cipd_path}",
+    "description: ${cipd_description}",
+    "root: \${outdir}/" + rebase_path(archive_staging_dir, root_build_dir),
+    "data:",
+    "  - file: LICENSE",
+  ]
+
+  if (!defined(deps)) {
+    deps = []
+  }
+  deps += [
+    ":build_id",
+    ":license",
+  ]
+
+  foreach(source, sources) {
+    yaml_contents += [ "  - file: " + get_path_info(source, "file") ]
+  }
+
+  sources += get_target_outputs(":license")
+  write_file("${archive_staging_dir}/${cipd_manifest_name}", yaml_contents)
+
+  copy(target_name) {
+    testonly = true
+    outputs = [
+      "${archive_staging_dir}/{{source_file_part}}",
+    ]
+  }
+}
+
+cipd_archive("webrunner") {
+  cipd_manifest_name = "webrunner.yaml"
+  cipd_path = "chromium/fuchsia/webrunner-\${targetarch}"
+  cipd_description = "Prebuilt Chrome and Web Runner binaries for Fuchsia."
+
+  deps = [
+    "//fuchsia/engine:web_engine",
+    "//fuchsia/runners:web_runner_pkg",
+  ]
+
+  sources = [
+    "${root_gen_dir}/fuchsia/engine/chromium/chromium.far",
+    "${root_gen_dir}/fuchsia/runners/web_runner/web_runner.far",
+  ]
+}
+
+cipd_archive("castrunner") {
+  cipd_manifest_name = "castrunner.yaml"
+  cipd_path = "chromium/fuchsia/castrunner-\${targetarch}"
+  cipd_description = "Prebuilt Cast application Runner binaries for Fuchsia."
+
+  deps = [
+    "//fuchsia/runners:cast_runner_pkg",
+  ]
+
+  sources = [
+    "${root_gen_dir}/fuchsia/runners/cast_runner/cast_runner.far",
+  ]
+}
+
+cipd_archive("tests") {
+  _manifest_path = "${target_gen_dir}/test_manifest.json"
+  cipd_manifest_name = "tests.yaml"
+  cipd_path = "chromium/fuchsia/tests-\${targetarch}"
+  cipd_description = "Prebuilt Chromium tests for Fuchsia."
+
+  deps = [
+    "//base:base_unittests_pkg",
+    "//fuchsia/runners:cast_runner_integration_tests_pkg",
+    "//fuchsia/runners:web_runner_integration_tests_pkg",
+    "//ipc:ipc_tests_pkg",
+    "//media:media_unittests_pkg",
+    "//mojo:mojo_unittests_pkg",
+    "//skia:skia_unittests_pkg",
+    "//third_party/blink/common:blink_common_unittests_pkg",
+  ]
+
+  far_sources = [
+    "${root_gen_dir}/base/base_unittests/base_unittests.far",
+    "${root_gen_dir}/fuchsia/runners/cast_runner_integration_tests/cast_runner_integration_tests.far",
+    "${root_gen_dir}/fuchsia/runners/web_runner_integration_tests/web_runner_integration_tests.far",
+    "${root_gen_dir}/ipc/ipc_tests/ipc_tests.far",
+    "${root_gen_dir}/media/media_unittests/media_unittests.far",
+    "${root_gen_dir}/mojo/mojo_unittests/mojo_unittests.far",
+    "${root_gen_dir}/skia/skia_unittests/skia_unittests.far",
+    "${root_gen_dir}/third_party/blink/common/blink_common_unittests/blink_common_unittests.far",
+  ]
+
+  # Build a JSON manifest of the tests and include it in the archive.
+  _manifest_contents = []
+  foreach(source, far_sources) {
+    package_name = get_path_info(source, "name")
+
+    _manifest_contents += [
+      {
+        package = package_name
+        component_name = package_name
+      },
+    ]
+  }
+  write_file(_manifest_path, _manifest_contents, "json")
+
+  sources = far_sources + [ _manifest_path ]
+}
+
+cipd_archive("debug_symbols") {
+  cipd_manifest_name = "debug_symbols.yaml"
+  cipd_path = "chromium/fuchsia/debug-symbols-\${targetarch}"
+  cipd_description = "Debugging symbols for prebuilt binaries from Chromium."
+
+  _symbol_tarballs = [
+    "${root_gen_dir}/fuchsia/engine/chromium/chromium.symbols.tar.bz2",
+    "${root_gen_dir}/fuchsia/runners/cast_runner/cast_runner.symbols.tar.bz2",
+    "${root_gen_dir}/fuchsia/runners/web_runner/web_runner.symbols.tar.bz2",
+  ]
+  _symbol_manifest = "$target_gen_dir/debug_symbols.json"
+  write_file(_symbol_manifest, _symbol_tarballs, "json")
+  _symbol_manifest_contents = []
+  foreach(_symbol_file, _symbol_tarballs) {
+    _symbol_manifest_contents += [ get_path_info(_symbol_file, "file") ]
+  }
+  write_file(_symbol_manifest, _symbol_manifest_contents, "json")
+
+  deps = [
+    "//fuchsia/engine:symbol_archive",
+    "//fuchsia/runners:cast_runner_symbol_archive",
+    "//fuchsia/runners:web_runner_symbol_archive",
+  ]
+  sources = [ _symbol_manifest ] + _symbol_tarballs
+}
+
+group("cipd") {
+  testonly = true
+  deps = [
+    ":castrunner",
+    ":debug_symbols",
+    ":tests",
+    ":webrunner",
+  ]
+}
diff --git a/fuchsia/cipd/test_archive.gni b/fuchsia/cipd/test_archive.gni
deleted file mode 100644
index 94c35a2e..0000000
--- a/fuchsia/cipd/test_archive.gni
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-assert(is_fuchsia)
-
-# Prepares a staging directory for creating a CIPD archive of Fuchsia
-# packages. Generates a manifest JSON file used by consumers to discover
-# the set of available FARs.
-#
-# Parameters:
-#   cipd_manifest_name: The filename to use for the generated CIPD YAML file.
-#   cipd_path: The path where the package will be located inside the CIPD
-#              repository.
-#   cipd_description: Sets the "description" field in CIPD metadata.
-#   packages: A list of test targets whose FAR files will be included in the
-#             archive.
-#             Dependency links to these targets are implicitly created.
-#   include_manifest: If set, includes a JSON-encoded listing of FAR files in
-#                     the archive.
-template("cipd_archive") {
-  forward_variables_from(invoker,
-                         [
-                           "additional_files",
-                           "cipd_description",
-                           "cipd_manifest_name",
-                           "cipd_path",
-                           "deps",
-                           "include_manifest",
-                           "packages",
-                         ])
-  archive_staging_dir = "${target_gen_dir}/${target_name}"
-
-  manifest_contents = []
-  yaml_contents = [
-    "package: ${cipd_path}",
-    "description: ${cipd_description}",
-    "root: \${outdir}/" + rebase_path(archive_staging_dir, root_build_dir),
-    "data:",
-    "  - file: LICENSE",
-  ]
-
-  if (!defined(deps)) {
-    deps = []
-  }
-  deps += [
-    "//fuchsia:build_id",
-    "//fuchsia:license",
-  ]
-
-  copy_sources = [
-    "${root_out_dir}/fuchsia_artifacts/build_id.txt",
-    "${root_out_dir}/fuchsia_artifacts/LICENSE",
-  ]
-
-  package_deps = []
-  foreach(package, packages) {
-    package_name = get_label_info(package, "name")
-    package_deps += [ "${package}_pkg" ]
-
-    copy_sources += [ root_build_dir + "/gen" + get_label_info(package, "dir") +
-                      "/" + package_name + "/" + package_name + ".far" ]
-
-    manifest_contents += [
-      {
-        package = package_name
-        component_name = package_name
-      },
-    ]
-
-    yaml_contents += [ "  - file: ${package_name}.far" ]
-  }
-
-  if (defined(include_manifest) && include_manifest) {
-    yaml_contents += [ "  - file: test_manifest.json" ]
-    write_file("${archive_staging_dir}/test_manifest.json",
-               manifest_contents,
-               "json")
-  }
-  write_file("${archive_staging_dir}/${cipd_manifest_name}", yaml_contents)
-
-  copy(target_name) {
-    testonly = true
-    sources = copy_sources
-    deps += package_deps
-    outputs = [
-      "${archive_staging_dir}/{{source_file_part}}",
-    ]
-  }
-}
diff --git a/fuchsia/runners/common/web_component.cc b/fuchsia/runners/common/web_component.cc
index 6db6658..ceab7f38 100644
--- a/fuchsia/runners/common/web_component.cc
+++ b/fuchsia/runners/common/web_component.cc
@@ -21,7 +21,11 @@
         controller_request)
     : runner_(runner),
       startup_context_(std::move(context)),
-      controller_binding_(this) {
+      controller_binding_(this),
+      module_context_(
+          startup_context()
+              ->incoming_services()
+              ->ConnectToService<fuchsia::modular::ModuleContext>()) {
   DCHECK(runner);
 
   // If the ComponentController request is valid then bind it, and configure it
@@ -61,6 +65,10 @@
 }
 
 WebComponent::~WebComponent() {
+  // If Modular is available, request to be removed from the Story.
+  if (module_context_)
+    module_context_->RemoveSelfFromStory();
+
   // Send process termination details to the client.
   controller_binding_.events().OnTerminated(termination_exit_code_,
                                             termination_reason_);
diff --git a/fuchsia/runners/common/web_component.h b/fuchsia/runners/common/web_component.h
index b6452e0..7c9eb234 100644
--- a/fuchsia/runners/common/web_component.h
+++ b/fuchsia/runners/common/web_component.h
@@ -5,6 +5,7 @@
 #ifndef FUCHSIA_RUNNERS_COMMON_WEB_COMPONENT_H_
 #define FUCHSIA_RUNNERS_COMMON_WEB_COMPONENT_H_
 
+#include <fuchsia/modular/cpp/fidl.h>
 #include <fuchsia/sys/cpp/fidl.h>
 #include <fuchsia/ui/app/cpp/fidl.h>
 #include <fuchsia/web/cpp/fidl.h>
@@ -82,6 +83,9 @@
   fidl::Binding<fuchsia::sys::ComponentController> controller_binding_;
   std::unique_ptr<cr_fuchsia::LifecycleImpl> lifecycle_;
 
+  // If running as a Mod then these are used to e.g. RemoveSelfFromStory().
+  fuchsia::modular::ModuleContextPtr module_context_;
+
   // Incoming services provided at component creation.
   std::unique_ptr<base::fuchsia::ServiceDirectoryClient> additional_services_;
 
diff --git a/fuchsia/runners/web/web_runner_smoke_test.cc b/fuchsia/runners/web/web_runner_smoke_test.cc
index 3c238cb..03d804e 100644
--- a/fuchsia/runners/web/web_runner_smoke_test.cc
+++ b/fuchsia/runners/web/web_runner_smoke_test.cc
@@ -3,16 +3,21 @@
 // found in the LICENSE file.
 
 #include <fuchsia/modular/cpp/fidl.h>
+#include <fuchsia/modular/cpp/fidl_test_base.h>
 #include <fuchsia/sys/cpp/fidl.h>
 
 #include "base/bind.h"
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
 #include "base/fuchsia/service_directory_client.h"
+#include "base/fuchsia/service_provider_impl.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using net::test_server::HttpRequest;
@@ -29,6 +34,20 @@
     test_server_.RegisterRequestHandler(base::BindRepeating(
         &WebRunnerSmokeTest::HandleRequest, base::Unretained(this)));
     ASSERT_TRUE(test_server_.Start());
+
+    fidl::InterfaceHandle<fuchsia::io::Directory> directory;
+    service_directory_ = std::make_unique<base::fuchsia::ServiceDirectory>(
+        directory.NewRequest());
+    service_provider_ = std::make_unique<base::fuchsia::ServiceProviderImpl>(
+        std::move(directory));
+  }
+
+  fuchsia::sys::LaunchInfo LaunchInfoWithServices() {
+    auto services = fuchsia::sys::ServiceList::New();
+    service_provider_->AddBinding(services->provider.NewRequest());
+    fuchsia::sys::LaunchInfo launch_info;
+    launch_info.additional_services = std::move(services);
+    return launch_info;
   }
 
   std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
@@ -67,6 +86,9 @@
 
   base::MessageLoopForIO message_loop_;
 
+  std::unique_ptr<base::fuchsia::ServiceDirectory> service_directory_;
+  std::unique_ptr<base::fuchsia::ServiceProviderImpl> service_provider_;
+
   net::EmbeddedTestServer test_server_;
 
   base::RunLoop run_loop_;
@@ -76,7 +98,7 @@
 
 // Verify that the Component loads and fetches the desired page.
 TEST_F(WebRunnerSmokeTest, RequestHtmlAndImage) {
-  fuchsia::sys::LaunchInfo launch_info;
+  fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
   launch_info.url = test_server_.GetURL("/test.html").spec();
 
   auto launcher = base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
@@ -95,7 +117,7 @@
 TEST_F(WebRunnerSmokeTest, LifecycleTerminate) {
   fidl::InterfaceHandle<fuchsia::io::Directory> directory;
 
-  fuchsia::sys::LaunchInfo launch_info;
+  fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
   launch_info.url = test_server_.GetURL("/test.html").spec();
   launch_info.directory_request = directory.NewRequest().TakeChannel();
 
@@ -126,14 +148,11 @@
 
 // Verify that if the Frame disconnects, the Component tears down.
 TEST_F(WebRunnerSmokeTest, ComponentExitOnFrameClose) {
-  fidl::InterfaceHandle<fuchsia::io::Directory> directory;
-
-  fuchsia::sys::LaunchInfo launch_info;
+  fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
   launch_info.url = test_server_.GetURL("/window_close.html").spec();
-  launch_info.directory_request = directory.NewRequest().TakeChannel();
 
   auto launcher = base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
-                      ->ConnectToServiceSync<fuchsia::sys::Launcher>();
+                      ->ConnectToService<fuchsia::sys::Launcher>();
 
   fuchsia::sys::ComponentControllerPtr controller;
   launcher->CreateComponent(std::move(launch_info), controller.NewRequest());
@@ -151,4 +170,53 @@
   EXPECT_FALSE(controller);
 }
 
+class MockModuleContext
+    : public fuchsia::modular::testing::ModuleContext_TestBase {
+ public:
+  MockModuleContext() = default;
+  ~MockModuleContext() override = default;
+
+  MOCK_METHOD0(RemoveSelfFromStory, void());
+
+  void NotImplemented_(const std::string& name) override {
+    NOTIMPLEMENTED() << name;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(MockModuleContext);
+};
+
+// Verify that Modular's RemoveSelfFromStory() is called on teardown.
+TEST_F(WebRunnerSmokeTest, RemoveSelfFromStoryOnFrameClose) {
+  fuchsia::sys::LaunchInfo launch_info = LaunchInfoWithServices();
+  launch_info.url = test_server_.GetURL("/window_close.html").spec();
+
+  MockModuleContext module_context;
+  EXPECT_CALL(module_context, RemoveSelfFromStory);
+  base::fuchsia::ScopedServiceBinding<fuchsia::modular::ModuleContext> binding(
+      service_directory_.get(), &module_context);
+  launch_info.additional_services->names.emplace_back(
+      fuchsia::modular::ModuleContext::Name_);
+
+  auto launcher = base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
+                      ->ConnectToService<fuchsia::sys::Launcher>();
+
+  fuchsia::sys::ComponentControllerPtr controller;
+  launcher->CreateComponent(std::move(launch_info), controller.NewRequest());
+
+  // Script in the page will execute window.close(), which should teardown the
+  // Component, causing |controller| to be disconnected.
+  base::RunLoop loop;
+  controller.set_error_handler(
+      [quit_loop = loop.QuitClosure()](zx_status_t status) {
+        EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
+        quit_loop.Run();
+      });
+  loop.Run();
+
+  EXPECT_FALSE(controller);
+
+  // Spin the loop again to ensure that RemoveSelfFromStory is processed.
+  base::RunLoop().RunUntilIdle();
+}
+
 }  // anonymous namespace
diff --git a/google_apis/gcm/engine/heartbeat_manager.cc b/google_apis/gcm/engine/heartbeat_manager.cc
index 9f0b049..c01ddb7 100644
--- a/google_apis/gcm/engine/heartbeat_manager.cc
+++ b/google_apis/gcm/engine/heartbeat_manager.cc
@@ -42,7 +42,8 @@
 }  // namespace
 
 HeartbeatManager::HeartbeatManager(
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner)
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    scoped_refptr<base::SequencedTaskRunner> maybe_power_wrapped_io_task_runner)
     : waiting_for_ack_(false),
       heartbeat_interval_ms_(0),
       server_interval_ms_(0),
@@ -52,7 +53,11 @@
       weak_ptr_factory_(this) {
   DCHECK(io_task_runner_);
   DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
-  heartbeat_timer_->SetTaskRunner(io_task_runner_);
+  // Set the heartbeat timer task runner to |maybe_power_wrapped_io_task_runner|
+  // so that a delayed task posted to it can wake the system up from sleep to
+  // perform the task.
+  heartbeat_timer_->SetTaskRunner(
+      std::move(maybe_power_wrapped_io_task_runner));
 }
 
 HeartbeatManager::~HeartbeatManager() {
diff --git a/google_apis/gcm/engine/heartbeat_manager.h b/google_apis/gcm/engine/heartbeat_manager.h
index 370083b..a517114 100644
--- a/google_apis/gcm/engine/heartbeat_manager.h
+++ b/google_apis/gcm/engine/heartbeat_manager.h
@@ -32,10 +32,15 @@
   typedef base::Callback<void(ConnectionFactory::ConnectionResetReason)>
       ReconnectCallback;
 
-  // Constructs a heartbeat manager with a passed in |io_task_runner|. Must be
-  // called on |io_task_runner|
+  // |io_task_runner|: for running IO tasks.
+  // |maybe_power_wrapped_io_task_runner|: for running IO tasks, where if the
+  //     feature is provided, it could be a wrapper on top of |io_task_runner|
+  //     to provide power management featueres so that a delayed task posted to
+  //     it can wake the system up from sleep to perform the task.
   explicit HeartbeatManager(
-      scoped_refptr<base::SequencedTaskRunner> io_task_runner);
+      scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+      scoped_refptr<base::SequencedTaskRunner>
+          maybe_power_wrapped_io_task_runner);
   ~HeartbeatManager() override;
 
   // Start the heartbeat logic.
diff --git a/google_apis/gcm/engine/heartbeat_manager_unittest.cc b/google_apis/gcm/engine/heartbeat_manager_unittest.cc
index 5a16428e..feb1617 100644
--- a/google_apis/gcm/engine/heartbeat_manager_unittest.cc
+++ b/google_apis/gcm/engine/heartbeat_manager_unittest.cc
@@ -28,8 +28,10 @@
 
 class TestHeartbeatManager : public HeartbeatManager {
  public:
-  TestHeartbeatManager(scoped_refptr<base::SequencedTaskRunner> io_task_runner)
-      : HeartbeatManager(io_task_runner) {}
+  TestHeartbeatManager(scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+                       scoped_refptr<base::SequencedTaskRunner>
+                           maybe_power_wrapped_io_task_runner)
+      : HeartbeatManager(io_task_runner, maybe_power_wrapped_io_task_runner) {}
   ~TestHeartbeatManager() override {}
 
   // Bypass the heartbeat timer, and send the heartbeat now.
@@ -76,7 +78,7 @@
 HeartbeatManagerTest::HeartbeatManagerTest()
     : task_runner_(new base::TestSimpleTaskRunner()),
       task_runner_handle_(task_runner_),
-      manager_(new TestHeartbeatManager(task_runner_)),
+      manager_(new TestHeartbeatManager(task_runner_, task_runner_)),
       heartbeats_sent_(0),
       reconnects_triggered_(0) {}
 
diff --git a/google_apis/gcm/engine/mcs_client.cc b/google_apis/gcm/engine/mcs_client.cc
index 8af46f09..16d98e6 100644
--- a/google_apis/gcm/engine/mcs_client.cc
+++ b/google_apis/gcm/engine/mcs_client.cc
@@ -179,7 +179,8 @@
       stream_id_in_(0),
       gcm_store_(gcm_store),
       io_task_runner_(io_task_runner),
-      heartbeat_manager_(std::move(io_task_runner)),
+      heartbeat_manager_(std::move(base::ThreadTaskRunnerHandle::Get()),
+                         std::move(io_task_runner)),
       recorder_(recorder),
       weak_ptr_factory_(this) {
   DCHECK(io_task_runner_);
diff --git a/gpu/vulkan/vulkan_command_buffer.h b/gpu/vulkan/vulkan_command_buffer.h
index a7c9552..b48b61d 100644
--- a/gpu/vulkan/vulkan_command_buffer.h
+++ b/gpu/vulkan/vulkan_command_buffer.h
@@ -25,6 +25,7 @@
   ~VulkanCommandBuffer();
 
   bool Initialize();
+  // Destroy() should be called when all related GPU tasks have been finished.
   void Destroy();
 
   // Submit primary command buffer to the queue.
diff --git a/gpu/vulkan/vulkan_command_pool.h b/gpu/vulkan/vulkan_command_pool.h
index bd1b84c..d740fd6 100644
--- a/gpu/vulkan/vulkan_command_pool.h
+++ b/gpu/vulkan/vulkan_command_pool.h
@@ -23,6 +23,7 @@
   ~VulkanCommandPool();
 
   bool Initialize();
+  // Destroy() should be called when all related GPU tasks have been finished.
   void Destroy();
 
   std::unique_ptr<VulkanCommandBuffer> CreatePrimaryCommandBuffer();
diff --git a/gpu/vulkan/vulkan_device_queue.cc b/gpu/vulkan/vulkan_device_queue.cc
index 441940cb..dad2651 100644
--- a/gpu/vulkan/vulkan_device_queue.cc
+++ b/gpu/vulkan/vulkan_device_queue.cc
@@ -201,7 +201,7 @@
   return true;
 }
 
-bool VulkanDeviceQueue::InitializeForWevbView(
+bool VulkanDeviceQueue::InitializeForWebView(
     VkPhysicalDevice vk_physical_device,
     VkDevice vk_device,
     VkQueue vk_queue,
diff --git a/gpu/vulkan/vulkan_device_queue.h b/gpu/vulkan/vulkan_device_queue.h
index 0e769958..32e831ec 100644
--- a/gpu/vulkan/vulkan_device_queue.h
+++ b/gpu/vulkan/vulkan_device_queue.h
@@ -41,11 +41,11 @@
       const GetPresentationSupportCallback& get_presentation_support,
       bool use_swiftshader);
 
-  bool InitializeForWevbView(VkPhysicalDevice vk_physical_device,
-                             VkDevice vk_device,
-                             VkQueue vk_queue,
-                             uint32_t vk_queue_index,
-                             gfx::ExtensionSet enabled_extensions);
+  bool InitializeForWebView(VkPhysicalDevice vk_physical_device,
+                            VkDevice vk_device,
+                            VkQueue vk_queue,
+                            uint32_t vk_queue_index,
+                            gfx::ExtensionSet enabled_extensions);
 
   const gfx::ExtensionSet& enabled_extensions() const {
     return enabled_extensions_;
diff --git a/gpu/vulkan/vulkan_instance.cc b/gpu/vulkan/vulkan_instance.cc
index be186b4..85aa153 100644
--- a/gpu/vulkan/vulkan_instance.cc
+++ b/gpu/vulkan/vulkan_instance.cc
@@ -148,19 +148,26 @@
 
   // 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 =
+  constexpr base::StringPiece xlib_surface_extension_name(
+      "VK_KHR_xlib_surface");
+  bool require_xlib_surface_extension =
       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());
+                   }) != enabled_extensions.end();
+
+  // VK_LAYER_LUNARG_standard_validation 1.0.106 is required to support
+  // VK_KHR_xlib_surface.
+  constexpr base::StringPiece standard_validation(
+      "VK_LAYER_LUNARG_standard_validation");
+  for (const VkLayerProperties& layer_property : instance_layers) {
+    if (standard_validation != layer_property.layerName)
+      continue;
+    if (!require_xlib_surface_extension ||
+        layer_property.specVersion >= VK_MAKE_VERSION(1, 0, 106)) {
+      enabled_layer_names.push_back(standard_validation.data());
     }
+    break;
   }
 #endif  // DCHECK_IS_ON()
 
diff --git a/gpu/vulkan/vulkan_surface.h b/gpu/vulkan/vulkan_surface.h
index 08260c21..8bae0235 100644
--- a/gpu/vulkan/vulkan_surface.h
+++ b/gpu/vulkan/vulkan_surface.h
@@ -36,6 +36,7 @@
 
   bool Initialize(VulkanDeviceQueue* device_queue,
                   VulkanSurface::Format format);
+  // Destroy() should be called when all related GPU tasks have been finished.
   void Destroy();
 
   gfx::SwapResult SwapBuffers();
diff --git a/gpu/vulkan/vulkan_swap_chain.cc b/gpu/vulkan/vulkan_swap_chain.cc
index ecbf1a58..1018527 100644
--- a/gpu/vulkan/vulkan_swap_chain.cc
+++ b/gpu/vulkan/vulkan_swap_chain.cc
@@ -158,8 +158,9 @@
   }
 
   if (old_swap_chain) {
-    old_swap_chain->Destroy();
-    old_swap_chain = nullptr;
+    auto* fence_helper = device_queue_->GetFenceHelper();
+    fence_helper->EnqueueVulkanObjectCleanupForSubmittedWork(
+        std::move(old_swap_chain));
   }
 
   swap_chain_ = new_swap_chain;
@@ -172,15 +173,8 @@
 void VulkanSwapChain::DestroySwapChain() {
   if (swap_chain_ == VK_NULL_HANDLE)
     return;
-
-  device_queue_->GetFenceHelper()->EnqueueCleanupTaskForSubmittedWork(
-      base::BindOnce(
-          [](VkSwapchainKHR swapchain, VulkanDeviceQueue* device_queue,
-             bool /* is_lost */) {
-            VkDevice device = device_queue->GetVulkanDevice();
-            vkDestroySwapchainKHR(device, swapchain, nullptr /* pAllocator */);
-          },
-          swap_chain_));
+  vkDestroySwapchainKHR(device_queue_->GetVulkanDevice(), swap_chain_,
+                        nullptr /* pAllocator */);
   swap_chain_ = VK_NULL_HANDLE;
 }
 
@@ -230,32 +224,26 @@
 }
 
 void VulkanSwapChain::DestroySwapImages() {
-  auto* fence_helper = device_queue_->GetFenceHelper();
-  fence_helper->EnqueueCleanupTaskForSubmittedWork(base::BindOnce(
-      [](VkSemaphore begin_semaphore, VkSemaphore end_semaphore,
-         std::vector<ImageData> images,
-         std::unique_ptr<VulkanCommandPool> command_pool,
-         VulkanDeviceQueue* device_queue, bool /* is_lost */) {
-        auto* vk_device = device_queue->GetVulkanDevice();
-        if (begin_semaphore)
-          vkDestroySemaphore(vk_device, begin_semaphore,
-                             nullptr /* pAllocator */);
-        if (end_semaphore)
-          vkDestroySemaphore(vk_device, end_semaphore,
-                             nullptr /* pAllocator */);
-        for (auto& image_data : images) {
-          if (!image_data.command_buffer)
-            continue;
-          image_data.command_buffer->Destroy();
-          image_data.command_buffer = nullptr;
-        }
-        command_pool->Destroy();
-      },
-      begin_write_semaphore_, end_write_semaphore_, std::move(images_),
-      std::move(command_pool_)));
+  if (begin_write_semaphore_)
+    vkDestroySemaphore(device_queue_->GetVulkanDevice(), begin_write_semaphore_,
+                       nullptr /* pAllocator */);
   begin_write_semaphore_ = VK_NULL_HANDLE;
+
+  if (end_write_semaphore_)
+    vkDestroySemaphore(device_queue_->GetVulkanDevice(), end_write_semaphore_,
+                       nullptr /* pAllocator */);
   end_write_semaphore_ = VK_NULL_HANDLE;
+
+  for (auto& image_data : images_) {
+    if (!image_data.command_buffer)
+      continue;
+    image_data.command_buffer->Destroy();
+    image_data.command_buffer = nullptr;
+  }
   images_.clear();
+
+  command_pool_->Destroy();
+  command_pool_ = nullptr;
 }
 
 void VulkanSwapChain::BeginWriteCurrentImage(VkImage* image,
diff --git a/gpu/vulkan/vulkan_swap_chain.h b/gpu/vulkan/vulkan_swap_chain.h
index 73037337..c073c50 100644
--- a/gpu/vulkan/vulkan_swap_chain.h
+++ b/gpu/vulkan/vulkan_swap_chain.h
@@ -59,6 +59,7 @@
                   const VkSurfaceCapabilitiesKHR& surface_caps,
                   const VkSurfaceFormatKHR& surface_format,
                   std::unique_ptr<VulkanSwapChain> old_swap_chain);
+  // Destroy() should be called when all related GPU tasks have been finished.
   void Destroy();
   gfx::SwapResult SwapBuffers();
 
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index fb74e90..302e176 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -675,6 +675,26 @@
 }
 
 builder_mixins {
+  name: "linux-gpu-ci-builder"
+  dimensions: "cores:8"
+  mixins: "builderless"
+  mixins: "linux"
+  recipe {
+    properties: "mastername:chromium.gpu"
+  }
+}
+
+builder_mixins {
+  name: "linux-gpu-ci-tester"
+  dimensions: "cores:2"
+  mixins: "builderless"
+  mixins: "linux"
+  recipe {
+    properties: "mastername:chromium.gpu"
+  }
+}
+
+builder_mixins {
   name: "linux-gpu-fyi-ci"
   mixins: "linux"
   mixins: "gpu-fyi-ci"
@@ -688,6 +708,24 @@
 }
 
 builder_mixins {
+  name: "linux-gpu-fyi-ci-builder"
+  dimensions: "cores:8"
+  mixins: "builderless"
+  mixins: "gpu-fyi-ci"
+  mixins: "gpu-slow-bot"
+  mixins: "linux"
+}
+
+builder_mixins {
+  name: "linux-gpu-fyi-ci-tester"
+  dimensions: "cores:2"
+  mixins: "builderless"
+  mixins: "gpu-fyi-ci"
+  mixins: "gpu-slow-bot"
+  mixins: "linux"
+}
+
+builder_mixins {
   name: "mac"
   dimensions: "os:Mac"
   # Macs tend to have a variety of cores.
@@ -1673,105 +1711,106 @@
     # chromium.gpu
     builders {
       name: "GPU Linux Builder"
-      mixins: "linux-gpu-ci"
+      mixins: "linux-gpu-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "GPU Linux Builder (dbg)"
-      mixins: "linux-gpu-ci"
+      mixins: "linux-gpu-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "Linux Debug (NVIDIA)"
-      mixins: "linux-gpu-ci"
+      mixins: "linux-gpu-ci-tester"
     }
 
     builders {
       name: "Linux Release (NVIDIA)"
-      mixins: "linux-gpu-ci"
+      mixins: "linux-gpu-ci-tester"
     }
 
     # chromium.gpu.fyi
     builders {
       name: "GPU FYI Linux Builder"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "GPU FYI Linux Builder (dbg)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "GPU FYI Linux Ozone Builder"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "GPU FYI Linux dEQP Builder"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "Linux FYI Experimental Release (Intel HD 630)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI Release (NVIDIA)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI Experimental Release (NVIDIA)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI Debug (NVIDIA)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI dEQP Release (NVIDIA)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI SkiaRenderer Vulkan (NVIDIA)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI Release (Intel HD 630)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI dEQP Release (Intel HD 630)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI GPU TSAN Release"
-      mixins: "linux-gpu-fyi-ci"
+      # Builder/tester, thus needs more cores
+      mixins: "linux-gpu-fyi-ci-builder"
       mixins: "goma-rbe-prod"
     }
 
     builders {
       name: "Linux FYI Release (AMD R7 240)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     builders {
       name: "Linux FYI Ozone (Intel)"
-      mixins: "linux-gpu-fyi-ci"
+      mixins: "linux-gpu-fyi-ci-tester"
     }
 
     # Mac bots.
diff --git a/ios/build/tools/convert_gn_xcodeproj.py b/ios/build/tools/convert_gn_xcodeproj.py
index e198f1d..f26c4354 100755
--- a/ios/build/tools/convert_gn_xcodeproj.py
+++ b/ios/build/tools/convert_gn_xcodeproj.py
@@ -102,6 +102,7 @@
       build_config_template = project.objects[value['buildConfigurations'][0]]
       build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \
           '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
+      build_config_template['buildSettings']['CODE_SIGN_IDENTITY'] = ''
 
       value['buildConfigurations'] = []
       for configuration in configurations:
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index b0b65df4..2cd1e30 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -443,8 +443,6 @@
 - (void)showTabSwitcher;
 // Starts a voice search on the current BVC.
 - (void)startVoiceSearchInCurrentBVC;
-// Dismisses |signinInteractionCoordinator|.
-- (void)dismissSigninInteractionCoordinator;
 // Called when the last incognito tab was closed.
 - (void)lastIncognitoTabClosed;
 // Called when the last regular tab was closed.
@@ -2214,12 +2212,6 @@
                                  completion:nil];
 }
 
-- (void)dismissSigninInteractionCoordinator {
-  // The SigninInteractionCoordinator must not be destroyed at this point, as
-  // it may dismiss the sign in UI in a future callback.
-  [self.signinInteractionCoordinator cancelAndDismiss];
-}
-
 - (void)closeSettingsAnimated:(BOOL)animated
                    completion:(ProceduralBlock)completion {
   if (_settingsNavigationController) {
@@ -2431,15 +2423,12 @@
       ->GetMailtoHandlerProvider()
       ->DismissAllMailtoHandlerInterfaces();
 
-  // Cancel interaction with SSO.
-  // First, cancel the signin interaction.
-  [self.signinInteractionCoordinator cancel];
-
   // Then, depending on what the SSO view controller is presented on, dismiss
   // it.
   ProceduralBlock completionWithBVC = ^{
     DCHECK(self.currentBVC);
     DCHECK(![self isTabSwitcherActive]);
+    DCHECK(!self.signinInteractionCoordinator.isActive);
     // This will dismiss the SSO view controller.
     [self.interfaceProvider.currentInterface
         clearPresentedStateWithCompletion:completion
@@ -2449,7 +2438,7 @@
     // |self.currentBVC| may exist but tab switcher should be active.
     DCHECK([self isTabSwitcherActive]);
     // This will dismiss the SSO view controller.
-    [self dismissSigninInteractionCoordinator];
+    [self.signinInteractionCoordinator cancelAndDismiss];
     // History coordinator can be started on top of the tab grid. This is not
     // true of the other tab switchers.
     DCHECK(self.mainCoordinator);
@@ -2462,7 +2451,6 @@
   if (![self isTabSwitcherActive] && self.isSettingsViewPresented) {
     // In this case, the settings are up and the BVC is showing. Close the
     // settings then call the BVC completion.
-    DCHECK(!self.signinInteractionCoordinator.isActive);
     [self closeSettingsAnimated:NO completion:completionWithBVC];
   } else if (self.isSettingsViewPresented) {
     // In this case, the settings are up but the BVC is not showing. Close the
@@ -2471,6 +2459,7 @@
   } else if (![self isTabSwitcherActive]) {
     // In this case, the settings are not shown but the BVC is showing. Call the
     // BVC completion.
+    [self.signinInteractionCoordinator cancel];
     completionWithBVC();
   } else {
     // In this case, neither the settings nor the BVC are shown. Call the no-BVC
diff --git a/ios/chrome/browser/metrics/previous_session_info.h b/ios/chrome/browser/metrics/previous_session_info.h
index f37accc..c56eb44 100644
--- a/ios/chrome/browser/metrics/previous_session_info.h
+++ b/ios/chrome/browser/metrics/previous_session_info.h
@@ -22,6 +22,18 @@
   kSerious = 3,
   kCritical = 4,
 };
+
+// The values of this enum are persisted representing the state of the last
+// session (which may have been running a different version of the application).
+// Therefore, entries should not be renumbered and numeric values should never
+// be reused.
+enum class DeviceBatteryState {
+  kUnknown = 0,
+  kUnplugged = 1,
+  kCharging = 2,
+  // Battery is plugged into power and the battery is 100% charged.
+  kFull = 3,
+};
 }  // namespace previous_session_info_constants
 
 // PreviousSessionInfo has two jobs:
@@ -31,6 +43,13 @@
 // - Persist information about the current session, for use in a next session.
 @interface PreviousSessionInfo : NSObject
 
+// The battery level of the device at the end of the previous session.
+@property(nonatomic, assign, readonly) float deviceBatteryLevel;
+
+// The battery state of the device at the end of the previous session.
+@property(nonatomic, assign, readonly)
+    previous_session_info_constants::DeviceBatteryState deviceBatteryState;
+
 // The thermal state of the device at the end of the previous session.
 @property(nonatomic, assign, readonly)
     previous_session_info_constants::DeviceThermalState deviceThermalState;
@@ -62,6 +81,12 @@
 // persisting information about the current session, for use in a next session.
 - (void)beginRecordingCurrentSession;
 
+// Updates the saved last known battery level of the device.
+- (void)updateStoredBatteryLevel;
+
+// Updates the saved last known battery state of the device.
+- (void)updateStoredBatteryState;
+
 // Updates the saved last known low power mode setting of the device.
 - (void)updateStoredLowPowerMode;
 
diff --git a/ios/chrome/browser/metrics/previous_session_info.mm b/ios/chrome/browser/metrics/previous_session_info.mm
index 4a58c20..9338473 100644
--- a/ios/chrome/browser/metrics/previous_session_info.mm
+++ b/ios/chrome/browser/metrics/previous_session_info.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/metrics/previous_session_info.h"
 
+#import <UIKit/UIKit.h>
+
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/system/sys_info.h"
@@ -14,10 +16,28 @@
 #error "This file requires ARC support."
 #endif
 
+using previous_session_info_constants::DeviceBatteryState;
 using previous_session_info_constants::DeviceThermalState;
 
 namespace {
 
+// Translates a UIDeviceBatteryState value to DeviceBatteryState value.
+DeviceBatteryState GetBatteryStateFromUIDeviceBatteryState(
+    UIDeviceBatteryState device_battery_state) {
+  switch (device_battery_state) {
+    case UIDeviceBatteryStateUnknown:
+      return DeviceBatteryState::kUnknown;
+    case UIDeviceBatteryStateUnplugged:
+      return DeviceBatteryState::kUnplugged;
+    case UIDeviceBatteryStateCharging:
+      return DeviceBatteryState::kCharging;
+    case UIDeviceBatteryStateFull:
+      return DeviceBatteryState::kFull;
+  }
+
+  return DeviceBatteryState::kUnknown;
+}
+
 // Translates a NSProcessInfoThermalState value to DeviceThermalState value.
 DeviceThermalState GetThermalStateFromNSProcessInfoThermalState(
     NSProcessInfoThermalState process_info_thermal_state) {
@@ -40,6 +60,13 @@
 NSString* const kLastRanVersion = @"LastRanVersion";
 // - The (string) device language.
 NSString* const kLastRanLanguage = @"LastRanLanguage";
+// - The (float) battery charge level.
+NSString* const kPreviousSessionInfoBatteryLevel =
+    @"PreviousSessionInfoBatteryLevel";
+// - The (integer) underlying value of the DeviceBatteryState enum representing
+//   the device battery state.
+NSString* const kPreviousSessionInfoBatteryState =
+    @"PreviousSessionInfoBatteryState";
 // - The (string) OS version.
 NSString* const kPreviousSessionInfoOSVersion = @"PreviousSessionInfoOSVersion";
 // - The (integer) underlying value of the DeviceThermalState enum representing
@@ -63,6 +90,8 @@
 @property(nonatomic, assign) BOOL didBeginRecordingCurrentSession;
 
 // Redefined to be read-write.
+@property(nonatomic, assign) float deviceBatteryLevel;
+@property(nonatomic, assign) DeviceBatteryState deviceBatteryState;
 @property(nonatomic, assign) DeviceThermalState deviceThermalState;
 @property(nonatomic, assign) BOOL deviceWasInLowPowerMode;
 @property(nonatomic, assign) BOOL didSeeMemoryWarningShortlyBeforeTerminating;
@@ -74,6 +103,8 @@
 
 @implementation PreviousSessionInfo
 
+@synthesize deviceBatteryLevel = _deviceBatteryLevel;
+@synthesize deviceBatteryState = _deviceBatteryState;
 @synthesize deviceThermalState = _deviceThermalState;
 @synthesize deviceWasInLowPowerMode = _deviceWasInLowPowerMode;
 @synthesize didBeginRecordingCurrentSession = _didBeginRecordingCurrentSession;
@@ -98,6 +129,10 @@
                                  kDidSeeMemoryWarningShortlyBeforeTerminating];
     gSharedInstance.deviceWasInLowPowerMode =
         [defaults boolForKey:kPreviousSessionInfoLowPowerMode];
+    gSharedInstance.deviceBatteryState = static_cast<DeviceBatteryState>(
+        [defaults integerForKey:kPreviousSessionInfoBatteryState]);
+    gSharedInstance.deviceBatteryLevel =
+        [defaults floatForKey:kPreviousSessionInfoBatteryLevel];
     gSharedInstance.deviceThermalState = static_cast<DeviceThermalState>(
         [defaults integerForKey:kPreviousSessionInfoThermalState]);
 
@@ -152,6 +187,21 @@
       removeObjectForKey:previous_session_info_constants::
                              kDidSeeMemoryWarningShortlyBeforeTerminating];
 
+  [UIDevice currentDevice].batteryMonitoringEnabled = YES;
+  [self updateStoredBatteryLevel];
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(updateStoredBatteryLevel)
+             name:UIDeviceBatteryLevelDidChangeNotification
+           object:nil];
+
+  [self updateStoredBatteryState];
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(updateStoredBatteryState)
+             name:UIDeviceBatteryStateDidChangeNotification
+           object:nil];
+
   [self updateStoredLowPowerMode];
   [[NSNotificationCenter defaultCenter]
       addObserver:self
@@ -170,6 +220,26 @@
   [defaults synchronize];
 }
 
+- (void)updateStoredBatteryLevel {
+  [[NSUserDefaults standardUserDefaults]
+      setFloat:[UIDevice currentDevice].batteryLevel
+        forKey:kPreviousSessionInfoBatteryLevel];
+}
+
+- (void)updateStoredBatteryState {
+  UIDevice* device = [UIDevice currentDevice];
+  // Translate value to an app defined enum as the system could change the
+  // underlying values of UIDeviceBatteryState between OS versions.
+  DeviceBatteryState batteryState =
+      GetBatteryStateFromUIDeviceBatteryState(device.batteryState);
+  NSInteger batteryStateValue =
+      static_cast<std::underlying_type<DeviceBatteryState>::type>(batteryState);
+
+  [[NSUserDefaults standardUserDefaults]
+      setInteger:batteryStateValue
+          forKey:kPreviousSessionInfoBatteryState];
+}
+
 - (void)updateStoredLowPowerMode {
   BOOL isLowPoweredModeEnabled =
       [[NSProcessInfo processInfo] isLowPowerModeEnabled];
diff --git a/ios/chrome/browser/ui/signin_interaction/BUILD.gn b/ios/chrome/browser/ui/signin_interaction/BUILD.gn
index 3790c4d..a617a6c36 100644
--- a/ios/chrome/browser/ui/signin_interaction/BUILD.gn
+++ b/ios/chrome/browser/ui/signin_interaction/BUILD.gn
@@ -62,23 +62,30 @@
     "//base",
     "//base/test:test_support",
     "//components/unified_consent",
+    "//ios/chrome/app:app_internal",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui/authentication",
     "//ios/chrome/browser/ui/authentication:eg_test_support",
     "//ios/chrome/browser/ui/authentication/cells",
     "//ios/chrome/browser/ui/authentication/unified_consent/identity_chooser:identity_chooser_ui",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant",
+    "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui",
     "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/browser/ui/tab_grid:egtest_support",
+    "//ios/chrome/browser/ui/table_view/cells",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/web_state_list",
     "//ios/chrome/test/app:test_support",
     "//ios/chrome/test/earl_grey:test_support",
     "//ios/public/provider/chrome/browser/signin:test_support",
     "//ios/testing/earl_grey:earl_grey_support",
     "//ios/third_party/earl_grey:earl_grey+link",
     "//ui/base",
+    "//ui/base",
   ]
   libs = [ "XCTest.framework" ]
 }
diff --git a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
index f399d8f..0a3a052 100644
--- a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
+++ b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
@@ -5,11 +5,14 @@
 #import <EarlGrey/EarlGrey.h>
 #import <XCTest/XCTest.h>
 
+#import "base/ios/block_types.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/unified_consent/feature.h"
+#import "ios/chrome/app/main_controller.h"
 #include "ios/chrome/browser/system_flags.h"
+#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
 #import "ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
@@ -17,8 +20,11 @@
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 #import "ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest_util.h"
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_egtest_util.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
@@ -27,16 +33,46 @@
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
+#import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 using chrome_test_util::BookmarksNavigationBarDoneButton;
+using chrome_test_util::PrimarySignInButton;
 using chrome_test_util::SecondarySignInButton;
 using chrome_test_util::SettingsDoneButton;
 using chrome_test_util::SyncSettingsConfirmButton;
 
+typedef NS_ENUM(NSInteger, OpenSigninMethod) {
+  OpenSigninMethodFromSettings,
+  OpenSigninMethodFromBookmarks,
+  OpenSigninMethodFromRecentTabs,
+  OpenSigninMethodFromTabSwitcher,
+};
+
+namespace {
+
+// Taps on the primary sign-in button in recent tabs, and scroll first, if
+// necessary.
+void TapOnPrimarySignInButtonInRecentTabs() {
+  id<GREYMatcher> matcher =
+      grey_allOf(PrimarySignInButton(), grey_sufficientlyVisible(), nil);
+  const CGFloat kPixelsToScroll = 300;
+  id<GREYAction> searchAction =
+      grey_scrollInDirection(kGREYDirectionDown, kPixelsToScroll);
+  GREYElementInteraction* interaction =
+      [[EarlGrey selectElementWithMatcher:matcher]
+             usingSearchAction:searchAction
+          onElementWithMatcher:
+              grey_accessibilityID(
+                  kRecentTabsTableViewControllerAccessibilityIdentifier)];
+  [interaction performAction:grey_tap()];
+}
+
+}
+
 // Sign-in interaction tests that work both with Unified Consent enabled or
 // disabled.
 @interface SigninInteractionControllerTestCase : ChromeTestCase
@@ -306,4 +342,107 @@
       performAction:grey_tap()];
 }
 
+#pragma mark - Dismiss tests
+
+- (void)testDismissSigninFromSettings {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromSettings
+                        tapSettingsLink:NO];
+}
+
+- (void)testDismissAdvancedSigninSettingsFromAdvancedSigninSettings {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromSettings
+                        tapSettingsLink:YES];
+}
+
+- (void)testDismissSigninFromBookmarks {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromBookmarks
+                        tapSettingsLink:NO];
+}
+
+- (void)testDismissAdvancedSigninBookmarksFromAdvancedSigninSettings {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromBookmarks
+                        tapSettingsLink:YES];
+}
+
+- (void)testDismissSigninFromRecentTabs {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromRecentTabs
+                        tapSettingsLink:NO];
+}
+
+- (void)testDismissSigninFromRecentTabsFromAdvancedSigninSettings {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromRecentTabs
+                        tapSettingsLink:YES];
+}
+
+- (void)testDismissSigninFromTabSwitcher {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromTabSwitcher
+                        tapSettingsLink:NO];
+}
+
+- (void)testDismissSigninFromTabSwitcherFromAdvancedSigninSettings {
+  [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromTabSwitcher
+                        tapSettingsLink:YES];
+}
+
+#pragma mark - Utils
+
+- (void)assertOpenURLWhenSigninFromView:(OpenSigninMethod)openSigninMethod
+                        tapSettingsLink:(BOOL)tapSettingsLink {
+  ChromeIdentity* identity = [SigninEarlGreyUtils fakeIdentity1];
+  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
+      identity);
+  switch (openSigninMethod) {
+    case OpenSigninMethodFromSettings:
+      [ChromeEarlGreyUI openSettingsMenu];
+      [ChromeEarlGreyUI tapSettingsMenuButton:PrimarySignInButton()];
+      break;
+    case OpenSigninMethodFromBookmarks:
+      [ChromeEarlGreyUI openToolsMenu];
+      [ChromeEarlGreyUI
+          tapToolsMenuButton:chrome_test_util::BookmarksMenuButton()];
+      [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
+          performAction:grey_tap()];
+      break;
+    case OpenSigninMethodFromRecentTabs:
+      [ChromeEarlGreyUI openToolsMenu];
+      [ChromeEarlGreyUI
+          tapToolsMenuButton:chrome_test_util::RecentTabsMenuButton()];
+      TapOnPrimarySignInButtonInRecentTabs();
+      break;
+    case OpenSigninMethodFromTabSwitcher:
+      [[EarlGrey selectElementWithMatcher:chrome_test_util::TabGridOpenButton()]
+          performAction:grey_tap()];
+      [[EarlGrey selectElementWithMatcher:chrome_test_util::
+                                              TabGridOtherDevicesPanelButton()]
+          performAction:grey_tap()];
+      TapOnPrimarySignInButtonInRecentTabs();
+      break;
+  }
+  if (tapSettingsLink) {
+    [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+    [SigninEarlGreyUI tapSettingsLink];
+  }
+  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+  // Open the URL as if it was opened from another app.
+  UIApplication* application = UIApplication.sharedApplication;
+  id<UIApplicationDelegate> applicationDelegate = application.delegate;
+  NSURL* url = [NSURL URLWithString:@"http://www.example.com/"];
+  [applicationDelegate application:application openURL:url options:@{}];
+  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+  // Check if the URL was opened.
+  web::WebState* webState = chrome_test_util::GetMainController()
+                                .interfaceProvider.mainInterface.tabModel
+                                .webStateList->GetActiveWebState();
+  GURL expectedString(url.absoluteString.UTF8String);
+  GREYAssertEqual(expectedString, webState->GetVisibleURL(), @"url not loaded");
+  if (tapSettingsLink) {
+    // Should be signed in.
+    CHROME_EG_ASSERT_NO_ERROR(
+        [SigninEarlGreyUtils checkSignedInWithIdentity:identity]);
+  } else {
+    // Should be not signed in.
+    CHROME_EG_ASSERT_NO_ERROR([SigninEarlGreyUtils checkSignedOut]);
+  }
+}
+
 @end
diff --git a/media/gpu/android/codec_allocator.cc b/media/gpu/android/codec_allocator.cc
index c6eee5a1..4bd8b0e00 100644
--- a/media/gpu/android/codec_allocator.cc
+++ b/media/gpu/android/codec_allocator.cc
@@ -67,6 +67,9 @@
 void CodecAllocator::CreateMediaCodecAsync(
     CodecCreatedCB codec_created_cb,
     std::unique_ptr<VideoCodecConfig> codec_config) {
+  DCHECK(codec_created_cb);
+  DCHECK(codec_config);
+
   if (!task_runner_->RunsTasksInCurrentSequence()) {
     task_runner_->PostTask(
         FROM_HERE,
@@ -77,9 +80,6 @@
     return;
   }
 
-  DCHECK(codec_created_cb);
-  DCHECK(codec_config);
-
   // Select the task runner before adding the PendingOperation and before
   // querying the |force_sw_codecs_| state.
   auto* task_runner = SelectCodecTaskRunner();
@@ -110,6 +110,9 @@
 
 void CodecAllocator::ReleaseMediaCodec(std::unique_ptr<MediaCodecBridge> codec,
                                        base::OnceClosure codec_released_cb) {
+  DCHECK(codec);
+  DCHECK(codec_released_cb);
+
   if (!task_runner_->RunsTasksInCurrentSequence()) {
     task_runner_->PostTask(
         FROM_HERE,
@@ -119,8 +122,6 @@
     return;
   }
 
-  DCHECK(codec);
-
   // Update |force_sw_codecs_| status.
   auto* task_runner = SelectCodecTaskRunner();
 
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index a774417..67a2127 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -574,12 +574,14 @@
     scoped_refptr<CodecSurfaceBundle> surface_bundle,
     std::unique_ptr<MediaCodecBridge> codec) {
   if (!weak_this) {
-    codec_allocator->ReleaseMediaCodec(
-        std::move(codec),
-        base::BindOnce(
-            &base::SequencedTaskRunner::ReleaseSoon<CodecSurfaceBundle>,
-            base::SequencedTaskRunnerHandle::Get(), FROM_HERE,
-            std::move(surface_bundle)));
+    if (codec) {
+      codec_allocator->ReleaseMediaCodec(
+          std::move(codec),
+          base::BindOnce(
+              &base::SequencedTaskRunner::ReleaseSoon<CodecSurfaceBundle>,
+              base::SequencedTaskRunnerHandle::Get(), FROM_HERE,
+              std::move(surface_bundle)));
+    }
     return;
   }
   weak_this->OnCodecConfigured(std::move(surface_bundle), std::move(codec));
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index f801bc2..fe594b6f 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -802,6 +802,20 @@
   ASSERT_TRUE(codec_allocator_->ProvideMockCodecAsync());
 }
 
+TEST_P(MediaCodecVideoDecoderTest,
+       TeardownInvalidatesCodecCreationWeakPtrButDoesNotCallReleaseMediaCodec) {
+  InitializeWithTextureOwner_OneDecodePending(TestVideoConfig::Large(codec_));
+  destruction_observer_->DoNotAllowDestruction();
+  mcvd_.reset();
+  // DeleteSoon() is now pending. Ensure it's safe if the codec creation
+  // completes before it runs.
+  destruction_observer_->ExpectDestruction();
+
+  // A null codec should not be released via ReleaseMediaCodec().
+  EXPECT_CALL(*codec_allocator_, MockReleaseMediaCodec(_)).Times(0);
+  codec_allocator_->ProvideNullCodecAsync();
+}
+
 TEST_P(MediaCodecVideoDecoderTest, TeardownDoesNotDrainFlushedCodecs) {
   InitializeFully_OneDecodePending(TestVideoConfig::Large(codec_));
   // Since we assert that MCVD is destructed by default, this test verifies that
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index e5d45f8b..7f9c724 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -176,6 +176,7 @@
     "receiver.h",
     "receiver_set.h",
     "remote.h",
+    "remote_set.h",
     "self_owned_receiver.h",
     "sequence_local_sync_event_watcher.h",
     "shared_associated_remote.h",
@@ -211,6 +212,7 @@
     ":bindings_base",
     ":struct_traits",
     "//base",
+    "//base/util/type_safety",
     "//ipc:message_support",
     "//ipc:param_traits",
     "//mojo/public/cpp/system",
diff --git a/mojo/public/cpp/bindings/remote_set.h b/mojo/public/cpp/bindings/remote_set.h
new file mode 100644
index 0000000..4a09721
--- /dev/null
+++ b/mojo/public/cpp/bindings/remote_set.h
@@ -0,0 +1,154 @@
+// 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 MOJO_PUBLIC_CPP_BINDINGS_REMOTE_SET_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_REMOTE_SET_H_
+
+#include <iterator>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/util/type_safety/id_type.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace mojo {
+
+namespace internal {
+struct RemoteSetElementIdTypeTag {};
+}  // namespace internal
+
+using RemoteSetElementId = util::IdTypeU32<internal::RemoteSetElementIdTypeTag>;
+
+// Shared implementation of a set of remotes, used by both RemoteSet and
+// AssociatedRemoteSet aliases (see below).
+//
+// A RemoteSet or AssociatedRemoteSet is a collection of remote interface
+// endpoints whose lifetime is conveniently managed by the set, i.e., remotes
+// are removed from the set automatically when losing a connection).
+template <typename Interface,
+          template <typename>
+          class RemoteType,
+          template <typename>
+          class PendingRemoteType>
+class RemoteSetImpl {
+ public:
+  using Storage = std::map<RemoteSetElementId, RemoteType<Interface>>;
+
+  // An iterator definition to support range-for iteration over RemoteSet
+  // objects. An iterator can be dereferenced to get at the Remote, and |id()|
+  // can be called to get the element's ID (for e.g. later removal).
+  struct Iterator {
+    using self_type = Iterator;
+    using value_type = RemoteType<Interface>;
+    using reference = const value_type&;
+    using pointer = const value_type*;
+    using iterator_category = std::bidirectional_iterator_tag;
+    using difference_type = std::ptrdiff_t;
+
+    explicit Iterator(typename Storage::const_iterator it) : it_(it) {}
+
+    self_type& operator++() {
+      ++it_;
+      return *this;
+    }
+    self_type operator++(int) {
+      self_type result(*this);
+      ++(*this);
+      return result;
+    }
+    self_type& operator--() {
+      --it_;
+      return *this;
+    }
+    self_type operator--(int) {
+      self_type result(*this);
+      --(*this);
+      return result;
+    }
+
+    RemoteSetElementId id() const { return it_.first; }
+
+    reference operator*() const { return it_->second; }
+    pointer operator->() const { return &it_->second; }
+    bool operator==(const self_type& rhs) { return it_ == rhs.it_; }
+    bool operator!=(const self_type& rhs) { return it_ != rhs.it_; }
+
+   private:
+    typename Storage::const_iterator it_;
+  };
+
+  RemoteSetImpl() = default;
+  ~RemoteSetImpl() = default;
+
+  // Adds a new remote to this set and returns a unique ID that can be used to
+  // identify the remote later.
+  RemoteSetElementId Add(RemoteType<Interface> remote) {
+    auto id = GenerateNextElementId();
+    remote.set_disconnect_handler(base::BindOnce(&RemoteSetImpl::OnDisconnect,
+                                                 base::Unretained(this), id));
+    auto result = storage_.emplace(id, std::move(remote));
+    DCHECK(result.second);
+    return id;
+  }
+
+  // Same as above but for the equivalent pending remote type, for convenience.
+  RemoteSetElementId Add(PendingRemoteType<Interface> remote) {
+    return Add(RemoteType<Interface>(std::move(remote)));
+  }
+
+  // Removes a remote from the set given |id|, if present.
+  void Remove(RemoteSetElementId id) { storage_.erase(id); }
+
+  // Indicates whether a remote with the given ID is present in the set.
+  bool Contains(RemoteSetElementId id) { return base::Contains(storage_, id); }
+
+  // Sets a callback to invoke any time a remote in the set is disconnected.
+  // Note that the remote in question is already removed from the set by the
+  // time the callback is run for its disconnection.
+  using DisconnectHandler = base::RepeatingCallback<void(RemoteSetElementId)>;
+  void set_disconnect_handler(DisconnectHandler handler) {
+    disconnect_handler_ = std::move(handler);
+  }
+
+  bool empty() const { return storage_.empty(); }
+  Iterator begin() { return Iterator(storage_.begin()); }
+  Iterator begin() const { return Iterator(storage_.begin()); }
+  Iterator end() { return Iterator(storage_.end()); }
+  Iterator end() const { return Iterator(storage_.end()); }
+
+ private:
+  RemoteSetElementId GenerateNextElementId() {
+    return RemoteSetElementId::FromUnsafeValue(next_element_id_++);
+  }
+
+  void OnDisconnect(RemoteSetElementId id) {
+    Remove(id);
+    if (disconnect_handler_)
+      disconnect_handler_.Run(id);
+  }
+
+  uint32_t next_element_id_ = 1;
+  Storage storage_;
+  DisconnectHandler disconnect_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteSetImpl);
+};
+
+template <typename Interface>
+using RemoteSet = RemoteSetImpl<Interface, Remote, PendingRemote>;
+
+template <typename Interface>
+using AssociatedRemoteSet =
+    RemoteSetImpl<Interface, AssociatedRemote, PendingAssociatedRemote>;
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_REMOTE_SET_H_
diff --git a/mojo/public/cpp/bindings/tests/remote_unittest.cc b/mojo/public/cpp/bindings/tests/remote_unittest.cc
index 7ddb8d908..6f70a3f 100644
--- a/mojo/public/cpp/bindings/tests/remote_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/remote_unittest.cc
@@ -5,10 +5,12 @@
 #include <stdint.h>
 #include <utility>
 
+#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
+#include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
@@ -19,6 +21,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
 #include "mojo/public/cpp/bindings/shared_remote.h"
 #include "mojo/public/cpp/bindings/tests/bindings_test_base.h"
 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
@@ -56,6 +59,8 @@
 
   Receiver<math::Calculator>& receiver() { return receiver_; }
 
+  double total() const { return total_; }
+
  private:
   double total_;
   Receiver<math::Calculator> receiver_;
@@ -928,6 +933,92 @@
   shared_remote.reset();
 }
 
+TEST_P(RemoteTest, RemoteSet) {
+  std::vector<base::Optional<MathCalculatorImpl>> impls(3);
+
+  PendingRemote<math::Calculator> remote0;
+  PendingRemote<math::Calculator> remote1;
+  PendingRemote<math::Calculator> remote2;
+  impls[0].emplace(remote0.InitWithNewPipeAndPassReceiver());
+  impls[1].emplace(remote1.InitWithNewPipeAndPassReceiver());
+  impls[2].emplace(remote2.InitWithNewPipeAndPassReceiver());
+
+  RemoteSet<math::Calculator> remotes;
+  auto id0 = remotes.Add(Remote<math::Calculator>(std::move(remote0)));
+  auto id1 = remotes.Add(std::move(remote1));
+  auto id2 = remotes.Add(std::move(remote2));
+
+  // Send a message to each and wait for a reply.
+  {
+    base::RunLoop loop;
+    constexpr double kValue = 42.0;
+    auto on_add = base::BarrierClosure(3, loop.QuitClosure());
+    for (auto& remote : remotes) {
+      remote->Add(kValue, base::BindLambdaForTesting([&](double total) {
+                    EXPECT_EQ(kValue, total);
+                    on_add.Run();
+                  }));
+    }
+    loop.Run();
+
+    EXPECT_EQ(kValue, impls[0]->total());
+    EXPECT_EQ(kValue, impls[1]->total());
+    EXPECT_EQ(kValue, impls[2]->total());
+  }
+
+  EXPECT_FALSE(remotes.empty());
+
+  // Wipe out each of the impls and wait for a disconnect notification for each.
+
+  {
+    base::RunLoop loop;
+    remotes.set_disconnect_handler(
+        base::BindLambdaForTesting([&](RemoteSetElementId id) {
+          EXPECT_EQ(id, id0);
+          EXPECT_FALSE(remotes.Contains(id0));
+          EXPECT_TRUE(remotes.Contains(id1));
+          EXPECT_TRUE(remotes.Contains(id2));
+          loop.Quit();
+        }));
+    impls[0].reset();
+    loop.Run();
+  }
+
+  EXPECT_FALSE(remotes.empty());
+
+  {
+    base::RunLoop loop;
+    remotes.set_disconnect_handler(
+        base::BindLambdaForTesting([&](RemoteSetElementId id) {
+          EXPECT_EQ(id, id2);
+          EXPECT_FALSE(remotes.Contains(id0));
+          EXPECT_TRUE(remotes.Contains(id1));
+          EXPECT_FALSE(remotes.Contains(id2));
+          loop.Quit();
+        }));
+    impls[2].reset();
+    loop.Run();
+  }
+
+  EXPECT_FALSE(remotes.empty());
+
+  {
+    base::RunLoop loop;
+    remotes.set_disconnect_handler(
+        base::BindLambdaForTesting([&](RemoteSetElementId id) {
+          EXPECT_EQ(id, id1);
+          EXPECT_FALSE(remotes.Contains(id0));
+          EXPECT_FALSE(remotes.Contains(id1));
+          EXPECT_FALSE(remotes.Contains(id2));
+          loop.Quit();
+        }));
+    impls[1].reset();
+    loop.Run();
+  }
+
+  EXPECT_TRUE(remotes.empty());
+}
+
 INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(RemoteTest);
 
 }  // namespace
diff --git a/mojo/public/java/system/BUILD.gn b/mojo/public/java/system/BUILD.gn
index 49b2dbca..cc70e425 100644
--- a/mojo/public/java/system/BUILD.gn
+++ b/mojo/public/java/system/BUILD.gn
@@ -174,5 +174,6 @@
   shared_libraries = [ ":mojo_java_unittests" ]
   apk_name = "MojoTest"
   android_manifest = "javatests/AndroidManifest.xml"
+  target_sdk_version = 21
   enable_multidex = false
 }
diff --git a/mojo/public/java/system/javatests/AndroidManifest.xml b/mojo/public/java/system/javatests/AndroidManifest.xml
index 84b217b..04abc64 100644
--- a/mojo/public/java/system/javatests/AndroidManifest.xml
+++ b/mojo/public/java/system/javatests/AndroidManifest.xml
@@ -8,8 +8,6 @@
       xmlns:tools="http://schemas.android.com/tools"
       package="org.chromium.mojo.tests">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21" />
-
     <uses-permission android:name="android.permission.INJECT_EVENTS"
         tools:ignore="ProtectedPermissions"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
diff --git a/net/OWNERS b/net/OWNERS
index 08065b9..b2ff564 100644
--- a/net/OWNERS
+++ b/net/OWNERS
@@ -6,7 +6,6 @@
 eroman@chromium.org
 jkarlin@chromium.org
 mattm@chromium.org
-mef@chromium.org
 mmenke@chromium.org
 morlovich@chromium.org
 nharper@chromium.org
diff --git a/net/android/unittest_support/AndroidManifest.xml b/net/android/unittest_support/AndroidManifest.xml
index e9175e9f..7f34abc 100644
--- a/net/android/unittest_support/AndroidManifest.xml
+++ b/net/android/unittest_support/AndroidManifest.xml
@@ -10,7 +10,6 @@
       android:versionCode="1"
       android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 275be18a..d8738a4 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -8335,7 +8335,6 @@
     { "name": "arnesolutions.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "arpa.ph", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "arrowgrove.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "artetrama.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "artisanhd.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "artistnetwork.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "arubasunsetbeach.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -12663,7 +12662,6 @@
     { "name": "cheapticket.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "chelseafs.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "chennien.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "cherryonit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "chicisimo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "choiralberta.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "chourishi-shigoto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -23547,7 +23545,6 @@
     { "name": "bitmainwarranty.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bitrush.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bixservice.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "bizeau.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bizniskatalog.mk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bizzi.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "blackdiam.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -24862,7 +24859,6 @@
     { "name": "johannaojanen.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "johannes-bauer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "johannes-zinke.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "johnsiu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jomp16.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jonandnoraswedding.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jonathansanchez.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -26704,7 +26700,6 @@
     { "name": "vsc-don-stocksport.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vsesrazu-raiffeisen.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vstehn.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "vsx.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vuakhuyenmai.vn", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vulpine.club", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vuojolahti.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -28368,7 +28363,6 @@
     { "name": "gvpt.sk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hanashi.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hexapt.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "hd1tj.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "groupghistelinck-cars.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "heroicpixel.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "helenaknowledge.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -28965,7 +28959,6 @@
     { "name": "matthijssen.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ma-plancha.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "me-dc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "memfrob.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "me-center.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "marin-business-center.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "martingansler.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29014,7 +29007,6 @@
     { "name": "millhousenchurch.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "metrans-spedition.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mikedugan.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "mirco-grams.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "microblading.pe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mikegarnett.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "medifab.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -33472,7 +33464,6 @@
     { "name": "bouchonville-knifemaker.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bourqu.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bowlsheet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "boz.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bqr.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "brasilien.guide", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "breathedreamgo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -42429,7 +42420,6 @@
     { "name": "noobswhatelse.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nordicirc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nova.com.hk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "novojet.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nv.gw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nytrafficticket.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ochrepoint.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -42905,7 +42895,6 @@
     { "name": "blupig.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "boat-engines.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "boskeopolis-stories.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "brainbuxa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "breadofgod.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bremen-restaurants.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "briefvorlagen-papierformat.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44123,7 +44112,6 @@
     { "name": "poopr.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "portofala.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "posyperfume.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "precision.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prijsvergelijken.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "primalbase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pristinegreenlandscaping.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -48001,7 +47989,6 @@
     { "name": "bytesign.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cad-noerdlingen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cangku.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cangku.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "carassure.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cascadesjobcorpscca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "casio-caisses-enregistreuses.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -50683,7 +50670,6 @@
     { "name": "onepointsafeband.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onepointsafeband.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "online-horoskop.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "onnext.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "openbankproject.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "openstreetmap.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "orangenuts.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51830,7 +51816,6 @@
     { "name": "jeroldirvin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jessicahrehor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jisha.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "joaoaugusto.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jockbusuttil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jockbusuttil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jockbusuttil.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51882,7 +51867,6 @@
     { "name": "nazigol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nebenbeiblog.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nevergreen.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nexril.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nextcloud.nerdpol.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nhgteam.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ninverse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56726,7 +56710,6 @@
     { "name": "spartacuslife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "spectroom.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "spectrum.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sportabee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "st-bede.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "steemyy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stfrancisnaugatuck.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -62417,7 +62400,6 @@
     { "name": "ryuanerin.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "saga-umzuege.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sajtoskal.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "samdrewtakeson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "samorazvitie.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sangyoui.health", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sanovnik.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64321,7 +64303,6 @@
     { "name": "continental-zermatt.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "contourheating.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "controllertech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cookiee.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cradle.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crowdspire.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "current-usa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64582,7 +64563,6 @@
     { "name": "takipone.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tech-ninja.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "teetje-doko.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "terrorismattacks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "terrybutler.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "textbrawlers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tgbabyzoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67168,11 +67148,8 @@
     { "name": "alteria.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "am-39.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "am156.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "am5039.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "am5199.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "am6118.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "am8213.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "am9588.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "am9d104.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "amaranthinewanderlust.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "amateurpornhours.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67293,7 +67270,6 @@
     { "name": "bytepark.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "byteterrace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "c0o.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "c2media.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cabuna.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cakeoffencesact.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "calendriergratuit.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68317,9 +68293,7 @@
     { "name": "xn--die-hrercharts-zpb.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--t8jo9k1b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xpiuat.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "yamei1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yamei8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "yamei88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yao28.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yesogovinpetcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ym039.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69760,7 +69734,6 @@
     { "name": "asfaleianet.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "attendanceondemand.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "auvidos.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "awakenedmind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "awesomenamegenerator.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b5197.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b9297.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73588,7 +73561,6 @@
     { "name": "gulcinulutuna.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "haehnel.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hawaiiwho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "headlineclub.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "healthfitapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "heinrich-kleyer-schule.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hereticle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73806,6 +73778,495 @@
     { "name": "zaadnet.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zombie-40th.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ztk.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "010888a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "10365a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "135374.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "17187q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "177ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1ag777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1ag88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1ticks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "233hub.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "233hub.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "23lhb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "291.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "360marketlaunch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "501117.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "7893.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "7894.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "7l00p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "82ag88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "89386.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "89386a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "89386b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "89386c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "89386d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "89386e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8ag88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9ag88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acatec.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acquaparrucchieri.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acquire.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adidasrunningpartners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adpkdsim.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adventureworldtour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aeksistem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aetherlink.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "afterpay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag0101g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag0202a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag0707a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1515a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1588.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2020a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3131a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3232g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag4141a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag4848g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag4949g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6005.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6016.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6033.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6037.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6072.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6086.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6211.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6215.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6225.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6306.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag660.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag698.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag700.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag80808.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag80880.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag855.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag87777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88-guide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88001.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88028.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88056.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88068.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88080.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88081.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88089.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88090.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88094.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88098.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88110.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88158.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88220.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88309.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88518.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88550.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88618.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag887.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8876.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88799.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88801.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8890.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88905.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88906.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8891.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88988.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag88dc22.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag89000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag998.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agaa41.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agks008.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aglh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agm2525.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agm8383.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip8800.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agwin7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agyacht.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ai-media.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aj-foster.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aktca.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alchemy.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allcarespecialty.pharmacy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allied.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alpharail.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amsfoodhk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anora.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "approval-workflow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apt-one.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "archina.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aresanel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "as5158.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "asaabforever.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "atheist-faq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autospurgo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "axiodl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ba47.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bakersfieldhomeoffer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "becomeabricklayer.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beizsley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beizsoft.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beizsoft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "benjaminmarket.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bettyweber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "big-tits-video.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blackstrapsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blaumedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blenderman.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blogdefarmacia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "botnam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bouwplaatscheckin.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "briangosnell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brianpagan.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buddy-development-rabodirectconnect-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buddytop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buggmedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buggshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "byraje.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "caetanoflotas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cafedelahalle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carbonating.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino-cash-flow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino-cash-flow.com.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino-cash-flow.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino-cash-flow.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinocash-flow.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinocashflow.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinocashflow.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinocashflow.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cdireland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "centumail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chataberan.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chaturbate.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cheapautoinsuranceblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chicguay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cifapme.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clinicaltrialpodcast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudclouds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "colombiajeans.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "connexfilter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "contact.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "copticexchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "corriel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "creationsgate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "creermonsite-wp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crossroads-gmbh.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cuatroymedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cumnock.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cybersecurity.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "danbergen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dccwiki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "defensivefirearmsinstruction.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dennisforbes.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diarionoticia.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diretashop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dnsmate.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donaldjenkins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dorfpark-falkenburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "doublelist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dreatho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drogavista.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "droperplus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dsgvo-analyse.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dziaduch.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ebteam.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecalculator.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "edcaptain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eet.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eikentafels.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eisblau.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elldus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emrullahsahin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enodais.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "espaciosdelalma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eve-ua.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "evearly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "everglow.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "expromo.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "extrawdw.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fapp.tube", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "farmacia-lloret.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fashionflavorph.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fattyink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fernland.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fhservices.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flywus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frozendurian.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fundkyapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "funmountaincanyon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gaganenterprises.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gambling-business.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "getcheapinsurancenow.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "glamur-video.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "godan.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goldlevelmarketing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goldlevelprint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goparity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goswak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "graviola.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gunlukburc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gutscheinemagic.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "guzdek.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gynem.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hannes.paris", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hellosalmon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "highpressuretech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "holtackersleather.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "horsky.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hospitalitylinked.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "housemates.uk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "humanit.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "humaniza.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hwxvip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyncice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "idouying.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ilemonrain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infosexual.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ingwaz.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "init.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inprotec.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intakesync.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intellimatica.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "internetstiftelsen.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inwebo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ip6.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iperconnessi.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ironfittings.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "irrigadorbucal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "itsuki.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ivanaleksandrov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "j-l.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "j1879.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jean-luc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jezeravillage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jezibaba.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jmsjms.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joustsec.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joustsec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joustsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jouwtechnischecoach.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joyinverse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jpprivatehiretaxis.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jugwallonie.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "justmysocks.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jwr.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k-sails.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kawaiicon.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb0283.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb1717.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb2929.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb3636.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb7272.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb7373.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb848.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb9292.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kb9797.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kbcso.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kiokoman.eu.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kk575757.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "konfekcjonowanie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "koreanrandom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ks3636.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ks509.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ks531.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ks5808.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ks629.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kusadasiforum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "labworks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lamujerquesoy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lelux.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "leminhduong.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lenafonster.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lesbi-porno-video.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lilomatrixcorner.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linux.pizza", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "little-bird-bayreuth.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lnhydy.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lnrsoft.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "logiccircle.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loginmailpage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "londontaxipr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "luctam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lueersen.homedns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "luu.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lxx77.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "m23cal.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magestionfinanciere.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magic-photo-events.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maiscelular.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mamaisondefamille.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mamasorganizedchaos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manelli.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mangabank.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mantuo.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mastermindcesar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "media-soft-pro.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mediamaklumat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mega1.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "menh.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mifarmaciaenbarcelona.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "miyatakaikei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mohot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mohot.fit", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "monitorbox.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "montrealcatadoptions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "movilcelular.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mr-bills.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "msafiri.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "my-news-portal.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myhealthyday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myinstapy.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mynewsspot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neighborshop.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nekomio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newgraphics.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nextstart-staging.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nextstart.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nicht-blau.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "noinghene.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nonglamfarm.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nostalgische-attracties.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "notilus.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ntpana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nvlocalbusiness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odensc.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odysea.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "offerhome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ohioflockcote.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oic-ci.gc.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "omega-gaming.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "omexcables.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "open.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "orbitcleaning.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ouac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ovejabohemia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "overframe.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pagecdn.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paintersgc.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pandit.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pangoly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parltrack.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parrilladasparaeventos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "partoenagua.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pborn.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pcatv.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "peertube.uno", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "peniarth.cymru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "perfumestudio.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "philippestudiopro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phone888.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phonemore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "photo-castings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "photolessya.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pirateproxy.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "piucellulare.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "planetofwoman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "planetofwomen.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plu-pro.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plusmobile.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pointclickcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pokeli.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "porkyx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "porno-stars-video.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "posbich.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "potature.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pravaha-elixirs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "presidentialserviceawards.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "privorot-taro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qnickx.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "redpatronus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rodrigoacevedo.com.uy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roh.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roi.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rotring.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rphyncice.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "russia.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "s-u.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sacaleches.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sagagardencentre.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sampatjewelers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schermkapot.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "searchforbeer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seats2meet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "selfiehome.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "serviciodebarralibreparaeventos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sewing-world.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sharingphotos.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shelvacu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sice-si.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sikademy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skolni-system.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smartplace.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "southernlights.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "speedyjanes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "srb.help", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "srx.sx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stuartbell.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "suplments.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "surgenights.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swedentelugucommunity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "synapsepain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sys-tm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tadamstudio.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "talis-bs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxi-uslu.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxichic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "technology.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techzjc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teen-porno-video.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teleport.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "test-allegrodev.pantheonsite.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tetsai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theforexvalley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thehopefuture.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theleap.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thenexteducation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theodeboer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theperry.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theycallmefox.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thingsandcode.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thomaspluschris.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "threatmonitor.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tiendasmart.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tinyppt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tncentro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tolmaidis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tomkempers.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toolshero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "top2servers.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "topreit.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trianglebruins.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trutopoffer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "twin-tails.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tytod.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ubytovanihyncice.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ukari.hokkaido.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unblocked.lc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "up2mark.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uyen.party", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "veganrecipereviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "venditorepoa.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "venetkaarsenovart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vigorspa.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "viki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vinktwebdesign.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vkwebsite.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vontainment.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "voshod.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wearetuzag.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webdesigngc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wemakeit.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wincasinosmoney.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wongu.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ws159.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www63605.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wwwindows.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wzxaini9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yapeal.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ystream.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuzzamatuzz.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zeckenhilfe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index c7ab2bc..6bf9428d 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -2414,53 +2414,6 @@
 EVENT_TYPE(DNS_TRANSACTION_RESPONSE)
 
 // ------------------------------------------------------------------------
-// ChromeExtension
-// ------------------------------------------------------------------------
-
-// TODO(eroman): This is a layering violation. Fix this in the context
-// of http://crbug.com/90674.
-
-// This event is created when a Chrome extension aborts a request.
-//
-//  {
-//    "extension_id": <Extension ID that caused the abortion>
-//  }
-EVENT_TYPE(CHROME_EXTENSION_ABORTED_REQUEST)
-
-// This event is created when a Chrome extension redirects a request.
-//
-//  {
-//    "extension_id": <Extension ID that caused the redirection>
-//  }
-EVENT_TYPE(CHROME_EXTENSION_REDIRECTED_REQUEST)
-
-// This event is created when a Chrome extension modifies the headers of a
-// request.
-//
-//  {
-//    "extension_id":     <Extension ID that caused the modification>,
-//    "modified_headers": [ "<header>: <value>", ... ],
-//    "deleted_headers":  [ "<header>", ... ]
-//  }
-EVENT_TYPE(CHROME_EXTENSION_MODIFIED_HEADERS)
-
-// This event is created when a Chrome extension tried to modify a request
-// but was ignored due to a conflict.
-//
-//  {
-//    "extension_id": <Extension ID that was ignored>
-//  }
-EVENT_TYPE(CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT)
-
-// This event is created when a Chrome extension provides authentication
-// credentials.
-//
-//  {
-//    "extension_id": <Extension ID that provides credentials>
-//  }
-EVENT_TYPE(CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS)
-
-// ------------------------------------------------------------------------
 // CertVerifier
 // ------------------------------------------------------------------------
 
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index f582d01..52ed2e8 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1676,4 +1676,15 @@
   AddAndNotifyObserversOfRTT(observation);
 }
 
+void NetworkQualityEstimator::OnPeerToPeerConnectionsCountChange(
+    uint32_t count) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  webrtc_active_connections_count_ = count;
+}
+
+uint32_t NetworkQualityEstimator::GetPeerToPeerConnectionsCountChange() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return webrtc_active_connections_count_;
+}
+
 }  // namespace net
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index bb2ca133..460040d 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -264,6 +264,13 @@
   virtual void RecordSpdyPingLatency(const HostPortPair& host_port_pair,
                                      base::TimeDelta rtt);
 
+  // Sets the current count of media connections that require low latency.
+  void OnPeerToPeerConnectionsCountChange(uint32_t count);
+
+  // Returns the current count of peer to peer connections that may require low
+  // latency.
+  uint32_t GetPeerToPeerConnectionsCountChange() const;
+
   typedef nqe::internal::Observation Observation;
   typedef nqe::internal::ObservationBuffer ObservationBuffer;
 
@@ -531,6 +538,8 @@
   // type.
   void ClampKbpsBasedOnEct();
 
+  uint32_t webrtc_active_connections_count_ = 0u;
+
   // Determines if the requests to local host can be used in estimating the
   // network quality. Set to true only for tests.
   bool use_localhost_requests_;
diff --git a/net/test/android/javatests/AndroidManifest.xml b/net/test/android/javatests/AndroidManifest.xml
index 4f0a46e..2291685 100644
--- a/net/test/android/javatests/AndroidManifest.xml
+++ b/net/test/android/javatests/AndroidManifest.xml
@@ -8,7 +8,6 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="org.chromium.net.test.support">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
 
diff --git a/net/tools/print_certificates.py b/net/tools/print_certificates.py
index a60bfd7..5a05187 100755
--- a/net/tools/print_certificates.py
+++ b/net/tools/print_certificates.py
@@ -13,6 +13,7 @@
 import re
 import subprocess
 import sys
+import traceback
 
 
 def read_file_to_string(path):
@@ -155,6 +156,9 @@
     self.pos += 1
     return i
 
+  def consume_int16(self):
+    return ((self.consume_byte() << 8) + self.consume_byte())
+
   def consume_int24(self):
     return ((self.consume_byte() << 16) + (self.consume_byte() << 8) +
             self.consume_byte())
@@ -170,25 +174,18 @@
     return len(self.data) - self.pos
 
 
-def decode_tls_certificate_message(certificate_message):
-  reader = ByteReader(certificate_message)
-  if reader.consume_byte() != 11:
-    sys.stderr.write('HandshakeType != 11. Not a Certificate Message.\n')
-    return []
-
+def decode_tls10_certificate_message(reader):
   message_length = reader.consume_int24()
   if reader.remaining_byte_count() != message_length:
-    sys.stderr.write(
+    raise RuntimeError(
         'message_length(%d) != remaining_byte_count(%d)\n' % (
             message_length, reader.remaining_byte_count()))
-    return []
 
   certificate_list_length = reader.consume_int24()
   if reader.remaining_byte_count() != certificate_list_length:
-    sys.stderr.write(
+    raise RuntimeError(
         'certificate_list_length(%d) != remaining_byte_count(%d)\n' % (
             certificate_list_length, reader.remaining_byte_count()))
-    return []
 
   certificates_der = []
   while reader.remaining_byte_count():
@@ -198,6 +195,69 @@
   return certificates_der
 
 
+def decode_tls13_certificate_message(reader):
+  message_length = reader.consume_int24()
+  if reader.remaining_byte_count() != message_length:
+    raise RuntimeError(
+        'message_length(%d) != remaining_byte_count(%d)\n' % (
+            message_length, reader.remaining_byte_count()))
+
+  # Ignore certificate_request_context.
+  certificate_request_context_length = reader.consume_byte()
+  reader.consume_bytes(certificate_request_context_length)
+
+  certificate_list_length = reader.consume_int24()
+  if reader.remaining_byte_count() != certificate_list_length:
+    raise RuntimeError(
+        'certificate_list_length(%d) != remaining_byte_count(%d)\n' % (
+            certificate_list_length, reader.remaining_byte_count()))
+
+  certificates_der = []
+  while reader.remaining_byte_count():
+    # Assume certificate_type is X.509.
+    cert_len = reader.consume_int24()
+    certificates_der.append(reader.consume_bytes(cert_len))
+    # Ignore extensions.
+    extension_len = reader.consume_int16()
+    reader.consume_bytes(extension_len)
+
+  return certificates_der
+
+
+def decode_tls_certificate_message(certificate_message):
+  reader = ByteReader(certificate_message)
+  if reader.consume_byte() != 11:
+    sys.stderr.write('HandshakeType != 11. Not a Certificate Message.\n')
+    return []
+
+  # The TLS certificate message encoding changed in TLS 1.3. Rather than
+  # require pasting in and parsing the whole handshake to discover the TLS
+  # version, just try parsing the message with both the old and new encodings.
+
+  # First try the old style certificate message:
+  try:
+    return decode_tls10_certificate_message(reader)
+  except (IndexError, RuntimeError):
+    tls10_traceback = traceback.format_exc()
+
+  # Restart the ByteReader and consume the HandshakeType byte again.
+  reader = ByteReader(certificate_message)
+  reader.consume_byte()
+  # Try the new style certificate message:
+  try:
+    return decode_tls13_certificate_message(reader)
+  except (IndexError, RuntimeError):
+    tls13_traceback = traceback.format_exc()
+
+  # Neither attempt succeeded, just dump some error info:
+  sys.stderr.write("Couldn't parse TLS certificate message\n")
+  sys.stderr.write("TLS1.0 parse attempt:\n%s\n" % tls10_traceback)
+  sys.stderr.write("TLS1.3 parse attempt:\n%s\n" % tls13_traceback)
+  sys.stderr.write("\n")
+
+  return []
+
+
 def extract_tls_certificate_message(netlog_text):
   raw_certificate_message = decode_netlog_hexdump(netlog_text)
   if not raw_certificate_message:
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn
index 888389503..0aaa68d 100644
--- a/remoting/android/BUILD.gn
+++ b/remoting/android/BUILD.gn
@@ -82,6 +82,7 @@
 instrumentation_test_apk("remoting_test_apk") {
   android_manifest = "$root_gen_dir/remoting/android_test/AndroidManifest.xml"
   android_manifest_dep = ":remoting_test_apk_manifest"
+  target_sdk_version = 28
   apk_name = "ChromotingTest"
   apk_under_test = ":remoting_apk"
   java_files = [
diff --git a/remoting/android/java/AndroidManifest.xml.jinja2 b/remoting/android/java/AndroidManifest.xml.jinja2
index ce070c0..ac40602a 100644
--- a/remoting/android/java/AndroidManifest.xml.jinja2
+++ b/remoting/android/java/AndroidManifest.xml.jinja2
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="{{ APK_PACKAGE_NAME }}">
-    <uses-sdk android:minSdkVersion="19"
-            android:targetSdkVersion="28"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-feature android:glEsVersion="0x00020000" android:required="true" />
 
diff --git a/remoting/android/javatests/AndroidManifest.xml.jinja2 b/remoting/android/javatests/AndroidManifest.xml.jinja2
index 8f76f95..09e6419 100644
--- a/remoting/android/javatests/AndroidManifest.xml.jinja2
+++ b/remoting/android/javatests/AndroidManifest.xml.jinja2
@@ -11,7 +11,6 @@
     <!-- We add an application tag here just so that we can indicate that this
          package needs to link against the android.test library, which is
          needed when building test cases. -->
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/sandbox/win/src/sandbox_nt_util.cc b/sandbox/win/src/sandbox_nt_util.cc
index f71177fd..bace310 100644
--- a/sandbox/win/src/sandbox_nt_util.cc
+++ b/sandbox/win/src/sandbox_nt_util.cc
@@ -646,6 +646,40 @@
   return true;
 }
 
+bool NtGetPathFromHandle(HANDLE handle,
+                         std::unique_ptr<wchar_t, NtAllocDeleter>* path) {
+  OBJECT_NAME_INFORMATION initial_buffer;
+  OBJECT_NAME_INFORMATION* name;
+  ULONG size = 0;
+  // Query the name information a first time to get the size of the name.
+  NTSTATUS status = g_nt.QueryObject(handle, ObjectNameInformation,
+                                     &initial_buffer, size, &size);
+
+  if (!NT_SUCCESS(status) && status != STATUS_INFO_LENGTH_MISMATCH)
+    return false;
+
+  std::unique_ptr<BYTE[], NtAllocDeleter> name_ptr;
+  if (!size)
+    return false;
+  name_ptr.reset(new (NT_ALLOC) BYTE[size]);
+  name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(name_ptr.get());
+
+  // Query the name information a second time to get the name of the
+  // object referenced by the handle.
+  status = g_nt.QueryObject(handle, ObjectNameInformation, name, size, &size);
+
+  if (STATUS_SUCCESS != status)
+    return false;
+  size_t num_path_wchars = (name->ObjectName.Length / sizeof(wchar_t)) + 1;
+  path->reset(new (NT_ALLOC) wchar_t[num_path_wchars]);
+  status =
+      CopyData(path->get(), name->ObjectName.Buffer, name->ObjectName.Length);
+  path->get()[num_path_wchars - 1] = L'\0';
+  if (STATUS_SUCCESS != status)
+    return false;
+  return true;
+}
+
 }  // namespace sandbox
 
 void* operator new(size_t size, sandbox::AllocationType type, void* near_to) {
diff --git a/sandbox/win/src/sandbox_nt_util.h b/sandbox/win/src/sandbox_nt_util.h
index 08880d19..e32e4ccb 100644
--- a/sandbox/win/src/sandbox_nt_util.h
+++ b/sandbox/win/src/sandbox_nt_util.h
@@ -179,6 +179,10 @@
 // Converts an ansi string to an UNICODE_STRING.
 UNICODE_STRING* AnsiToUnicode(const char* string);
 
+// Resolves a handle to an nt path. Returns true if the handle can be resolved.
+bool NtGetPathFromHandle(HANDLE handle,
+                         std::unique_ptr<wchar_t, NtAllocDeleter>* path);
+
 // Provides a simple way to temporarily change the protection of a memory page.
 class AutoProtectMemory {
  public:
diff --git a/sandbox/win/src/sandbox_nt_util_unittest.cc b/sandbox/win/src/sandbox_nt_util_unittest.cc
index 4471f6c..a98392f 100644
--- a/sandbox/win/src/sandbox_nt_util_unittest.cc
+++ b/sandbox/win/src/sandbox_nt_util_unittest.cc
@@ -9,9 +9,13 @@
 #include <memory>
 #include <vector>
 
+#include "base/files/file.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_process_information.h"
 #include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/win_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace sandbox {
@@ -237,5 +241,26 @@
   EXPECT_TRUE(verify_buffer());
 }
 
+TEST(SandboxNtUtil, NtGetPathFromHandle) {
+  InitGlobalNt();
+
+  base::FilePath exe;
+  ASSERT_TRUE(base::PathService::Get(base::FILE_EXE, &exe));
+  base::File exe_file(exe, base::File::FLAG_OPEN);
+  ASSERT_TRUE(exe_file.IsValid());
+  std::unique_ptr<wchar_t, NtAllocDeleter> path;
+  EXPECT_TRUE(NtGetPathFromHandle(exe_file.GetPlatformFile(), &path));
+
+  // Basic sanity test, the functionality of NtGetPathFromHandle to return
+  // the correct value is already tested from win_utils_unittest.cc.
+  EXPECT_TRUE(base::EndsWith(path.get(), exe.BaseName().value(),
+                             base::CompareCase::INSENSITIVE_ASCII));
+
+  // Compare to GetNtPathFromWin32Path for extra check.
+  base::string16 nt_path;
+  EXPECT_TRUE(GetNtPathFromWin32Path(exe.value(), &nt_path));
+  EXPECT_STREQ(path.get(), nt_path.c_str());
+}
+
 }  // namespace
 }  // namespace sandbox
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index 39467a1..ed24210e 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -40,6 +40,7 @@
 #include "net/log/net_log.h"
 #include "net/log/net_log_capture_mode.h"
 #include "net/log/net_log_util.h"
+#include "net/nqe/network_quality_estimator.h"
 #include "net/ssl/ssl_key_logger_impl.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
@@ -73,7 +74,6 @@
 
 namespace {
 
-bool g_disable_network_change_notifier = false;
 NetworkService* g_network_service = nullptr;
 
 net::NetLog* GetNetLog() {
@@ -90,8 +90,7 @@
     net::NetworkChangeNotifier::ConnectionSubtype initial_connection_subtype) {
   // There is a global singleton net::NetworkChangeNotifier if NetworkService
   // is running inside of the browser process.
-  if (!g_disable_network_change_notifier &&
-      !net::NetworkChangeNotifier::HasNetworkChangeNotifier()) {
+  if (!net::NetworkChangeNotifier::HasNetworkChangeNotifier()) {
 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
     // On Android and ChromeOS, network change events are synced from the
     // browser process.
@@ -643,6 +642,11 @@
   base::MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
 }
 
+void NetworkService::OnPeerToPeerConnectionsCountChange(uint32_t count) {
+  network_quality_estimator_manager_->GetNetworkQualityEstimator()
+      ->OnPeerToPeerConnectionsCountChange(count);
+}
+
 #if defined(OS_ANDROID)
 void NetworkService::OnApplicationStateChange(
     base::android::ApplicationState state) {
@@ -833,10 +837,4 @@
   return g_network_service;
 }
 
-// static
-void NetworkService::DisableNetworkChangeNotifierForTesting() {
-  DCHECK(!g_network_service);
-  g_disable_network_change_notifier = true;
-}
-
 }  // namespace network
diff --git a/services/network/network_service.h b/services/network/network_service.h
index 1c61321..34c8cd2c 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -184,6 +184,7 @@
       const std::vector<std::string>& mime_types) override;
   void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel
                             memory_pressure_level) override;
+  void OnPeerToPeerConnectionsCountChange(uint32_t count) override;
 #if defined(OS_ANDROID)
   void OnApplicationStateChange(base::android::ApplicationState state) override;
 #endif
@@ -234,10 +235,6 @@
 
   static NetworkService* GetNetworkServiceForTesting();
 
-  // Tells the network service to not create a NetworkChangeNotifier instance.
-  // Must be called before the network service is started.
-  static void DisableNetworkChangeNotifierForTesting();
-
  private:
   // service_manager::Service implementation.
   void OnBindInterface(const service_manager::BindSourceInfo& source_info,
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index bc869d6c..d3499ce 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -403,6 +403,10 @@
   // Called when the system is low on memory.
   OnMemoryPressure(mojo_base.mojom.MemoryPressureLevel memory_pressure_level);
 
+  // Called when there is a change in the current count of peer to peer
+  // connections that may require low latency.
+  OnPeerToPeerConnectionsCountChange(uint32 count);
+
   // Called on state changes of the Android application.
   [EnableIf=is_android]
   OnApplicationStateChange(mojo_base.mojom.ApplicationState state);
diff --git a/services/network/public/mojom/network_service_test.mojom b/services/network/public/mojom/network_service_test.mojom
index 29ee1b7a..057d4433 100644
--- a/services/network/public/mojom/network_service_test.mojom
+++ b/services/network/public/mojom/network_service_test.mojom
@@ -85,6 +85,12 @@
   GetLatestMemoryPressureLevel()
       => (mojo_base.mojom.MemoryPressureLevel memory_pressure_level);
 
+  // Gets the current count of peer to peer connections that may require low
+  // latency.
+  [Sync]
+  GetPeerToPeerConnectionsCountChange()
+      => (uint32 connection_count);
+
   // Returns the value of an environment variable in the network service's
   // process, or an empty string if it's not set.
   [Sync]
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index e4cb7cb..a6dbc7b 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -523,6 +523,7 @@
     sources += skia_gpu_sources
     sources += skia_null_gpu_sources
     sources += skia_sksl_sources
+    sources += skia_sksl_gpu_sources
     if (enable_vulkan) {
       sources += skia_vk_sources
       sources += [
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index f6271fc..95a6652 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -1547,10 +1547,9 @@
   }
 }
 
-std::set<url::Origin> QuotaManager::GetEvictionOriginExceptions(
-    const std::set<url::Origin>& extra_exceptions) {
+std::set<url::Origin> QuotaManager::GetEvictionOriginExceptions() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::set<url::Origin> exceptions = extra_exceptions;
+  std::set<url::Origin> exceptions;
   for (const auto& p : origins_in_use_) {
     if (p.second > 0)
       exceptions.insert(p.first);
@@ -1585,7 +1584,6 @@
 
 void QuotaManager::GetEvictionOrigin(
     StorageType type,
-    const std::set<url::Origin>& extra_exceptions,
     int64_t global_quota,
     GetOriginCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1651,7 +1649,7 @@
   PostTaskAndReplyWithResultForDBThread(
       FROM_HERE,
       base::BindOnce(&GetLRUOriginOnDBThread, type,
-                     GetEvictionOriginExceptions(std::set<url::Origin>()),
+                     GetEvictionOriginExceptions(),
                      base::RetainedRef(special_storage_policy_),
                      base::Unretained(origin_ptr)),
       base::BindOnce(&QuotaManager::DidGetLRUOrigin, weak_factory_.GetWeakPtr(),
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h
index c2852e6..c397fd3a 100644
--- a/storage/browser/quota/quota_manager.h
+++ b/storage/browser/quota/quota_manager.h
@@ -81,7 +81,6 @@
   // Returns next origin to evict, or nullopt if there are no evictable
   // origins.
   virtual void GetEvictionOrigin(blink::mojom::StorageType type,
-                                 const std::set<url::Origin>& extra_exceptions,
                                  int64_t global_quota,
                                  GetOriginCallback callback) = 0;
 
@@ -378,14 +377,12 @@
   void DidDumpOriginInfoTableForHistogram(
       const OriginInfoTableEntries& entries);
 
-  std::set<url::Origin> GetEvictionOriginExceptions(
-      const std::set<url::Origin>& extra_exceptions);
+  std::set<url::Origin> GetEvictionOriginExceptions();
   void DidGetEvictionOrigin(GetOriginCallback callback,
                             const base::Optional<url::Origin>& origin);
 
   // QuotaEvictionHandler.
   void GetEvictionOrigin(blink::mojom::StorageType type,
-                         const std::set<url::Origin>& extra_exceptions,
                          int64_t global_quota,
                          GetOriginCallback callback) override;
   void EvictOriginData(const url::Origin& origin,
diff --git a/storage/browser/quota/quota_manager_unittest.cc b/storage/browser/quota/quota_manager_unittest.cc
index 8d32f73..27856ee 100644
--- a/storage/browser/quota/quota_manager_unittest.cc
+++ b/storage/browser/quota/quota_manager_unittest.cc
@@ -312,7 +312,7 @@
     // The quota manager's default eviction policy is to use an LRU eviction
     // policy.
     quota_manager_->GetEvictionOrigin(
-        type, std::set<url::Origin>(), 0,
+        type, 0,
         base::BindOnce(&QuotaManagerTest::DidGetEvictionOrigin,
                        weak_factory_.GetWeakPtr()));
   }
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.cc b/storage/browser/quota/quota_temporary_storage_evictor.cc
index f97d7fb..ba4076f5 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor.cc
+++ b/storage/browser/quota/quota_temporary_storage_evictor.cc
@@ -114,7 +114,6 @@
 
 void QuotaTemporaryStorageEvictor::OnEvictionRoundFinished() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  in_progress_eviction_origins_.clear();
 
   // Check if skipped round
   if (round_statistics_.num_evicted_origins_in_round) {
@@ -203,8 +202,7 @@
     // TODO(michaeln): if the reason for eviction is low physical disk space,
     // make 'unlimited' origins subject to eviction too.
     quota_eviction_handler_->GetEvictionOrigin(
-        blink::mojom::StorageType::kTemporary, in_progress_eviction_origins_,
-        settings.pool_size,
+        blink::mojom::StorageType::kTemporary, settings.pool_size,
         base::BindOnce(&QuotaTemporaryStorageEvictor::OnGotEvictionOrigin,
                        weak_factory_.GetWeakPtr()));
     return;
@@ -234,7 +232,6 @@
   }
 
   DCHECK(!origin->GetURL().is_empty());
-  in_progress_eviction_origins_.insert(*origin);
 
   quota_eviction_handler_->EvictOriginData(
       *origin, blink::mojom::StorageType::kTemporary,
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.h b/storage/browser/quota/quota_temporary_storage_evictor.h
index eb987dd1..09c902b2 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor.h
+++ b/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -102,7 +102,6 @@
   EvictionRoundStatistics round_statistics_;
   base::Time time_of_end_of_last_nonskipped_round_;
   base::Time time_of_end_of_last_round_;
-  std::set<url::Origin> in_progress_eviction_origins_;
 
   int64_t interval_ms_;
   bool timer_disabled_for_testing_;
diff --git a/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc b/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
index 74eedd2..ab7f169 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
+++ b/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -70,7 +70,6 @@
   }
 
   void GetEvictionOrigin(StorageType type,
-                         const std::set<url::Origin>& exceptions,
                          int64_t global_quota,
                          storage::GetOriginCallback callback) override {
     if (origin_order_.empty())
diff --git a/testing/android/driver/java/AndroidManifest.xml b/testing/android/driver/java/AndroidManifest.xml
index cae6f08d..011841a 100644
--- a/testing/android/driver/java/AndroidManifest.xml
+++ b/testing/android/driver/java/AndroidManifest.xml
@@ -10,7 +10,6 @@
       android:versionCode="1"
       android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application android:label="OnDeviceInstrumentationDriver" />
diff --git a/testing/android/native_test/java/AndroidManifest.xml.jinja2 b/testing/android/native_test/java/AndroidManifest.xml.jinja2
index 6d6c029..96780ec 100644
--- a/testing/android/native_test/java/AndroidManifest.xml.jinja2
+++ b/testing/android/native_test/java/AndroidManifest.xml.jinja2
@@ -10,7 +10,6 @@
       android:versionCode="1"
       android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
diff --git a/testing/buildbot/filters/skia_renderer.content_browsertests.filter b/testing/buildbot/filters/skia_renderer.content_browsertests.filter
index dc64d63..aeb98e870 100644
--- a/testing/buildbot/filters/skia_renderer.content_browsertests.filter
+++ b/testing/buildbot/filters/skia_renderer.content_browsertests.filter
@@ -1,4 +1,5 @@
 AuraWindowVideoCaptureDeviceBrowserTestP.*
 CaptureScreenshotTest.*
+OOPBrowserTest.Basic
 SnapshotBrowserTest.*
 WebContentsVideoCaptureDeviceBrowserTestP.*
diff --git a/testing/test.gni b/testing/test.gni
index 9fb6865..84796d21 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -96,11 +96,13 @@
         "android_manifest",
         "android_manifest_dep",
         "enable_multidex",
+        "min_sdk_version",
         "proguard_configs",
         "proguard_enabled",
+        "target_sdk_version",
         "use_default_launcher",
-        "write_asset_list",
         "use_native_activity",
+        "write_asset_list",
       ]
 
       # Adds the unwind tables from unstripped binary as an asset file in the
diff --git a/third_party/android_sdk/BUILD.gn b/third_party/android_sdk/BUILD.gn
index c302490..d9412ef 100644
--- a/third_party/android_sdk/BUILD.gn
+++ b/third_party/android_sdk/BUILD.gn
@@ -90,11 +90,6 @@
   android_java_prebuilt("android_gcm_java") {
     jar_path = "//third_party/android_sdk/public/extras/google/gcm/gcm-client/dist/gcm.jar"
   }
-  java_prebuilt("emma_device_java") {
-    jar_path = "//third_party/android_sdk/public/tools/lib/emma_device.jar"
-    include_java_resources = true
-    supports_android = true
-  }
 
   # The current version of //third_party/byte_buddy relies on an older
   # version of dx.
diff --git a/third_party/android_sdk/README.chromium b/third_party/android_sdk/README.chromium
index eac869d..aa6ad2a 100644
--- a/third_party/android_sdk/README.chromium
+++ b/third_party/android_sdk/README.chromium
@@ -2,14 +2,11 @@
 URL: http://developer.android.com/sdk/index.html
 Version: 28
   Android SDK Build-tools 27.0.3
-  Android SDK Emulator 28.0.23
-  Android SDK Platform-tools 28.0.2
+  Android SDK Emulator 29.0.9
+  Android SDK Platform-tools 28.0.3
   Android SDK Platform API 28
   Android SDK Sources 28
   Android SDK Tools 26.1.1
-  Android Support Repository 47.0.0
-  Android Support Library 23.2.1
-  Android Instant Apps 1.6.0
   Android Lint 26.4.0-alpha04
   Google Cloud Messaging 3
   SDK Patch Applier v4
@@ -23,7 +20,6 @@
 Local Modifications:
 
 - public/
-  - Added tools/lib/emma_device.jar and tools/lib/emma.jar.
   - Included the Android support library and required extras packages.
   - Added extras/chromium/.
   - Added build-tools/25.0.2/lib/dx.jar for //third_party/byte_buddy
@@ -38,4 +34,15 @@
   - Unzip and rename tools to tools-lint and move to the right spot in our repo.
   - Create CL and carbon copy tnorbye@google.com
 
-No other modifications has been made to the public Android SDK/NDK.
+No other modifications has been made to the public Android SDK.
+
+Update Instructions:
+
+public/tools/bin/sdkmanager --list  # Look for"Installed packages:"
+public/tools/bin/sdkmanager --update "name from --list's output"
+cipd create --pkg-def cipd_emulator.yaml  # For each package updated
+
+Then,
+* Update //DEPS with InstanceIds printed by "cipd create".
+* Update versions in this README.chromium.
+  * The overall Version field should corresponde to the Platform API version.
diff --git a/third_party/blink/renderer/core/css/resolver/element_style_resources.cc b/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
index 173a46c..148480f 100644
--- a/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
+++ b/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
@@ -223,7 +223,8 @@
                                  image_request_optimization);
             if (new_image && new_image->IsLazyloadPossiblyDeferred()) {
               LazyLoadImageObserver::StartMonitoring(
-                  pseudo_element_ ? pseudo_element_ : element_.Get());
+                  pseudo_element_ ? pseudo_element_ : element_.Get(),
+                  false /* is_for_intervention */);
             }
             background_layer->SetImage(new_image);
           }
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index 48f94d7..dd9329d 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -28,6 +28,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_EXECUTION_CONTEXT_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_EXECUTION_CONTEXT_H_
 
+#include <bitset>
 #include <memory>
 
 #include "base/location.h"
diff --git a/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc b/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
index b9f8791..57bf39f 100644
--- a/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
@@ -233,10 +233,12 @@
   // The hidden form element should be removed.
   EXPECT_EQ(WTF::kNotFound, mhtml.Find("<input type=3D\"hidden\""));
 
+  // The style element should be converted to link element.
+  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<style"));
+
   // All other hidden elements should not be removed.
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<html"));
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<head"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<style"));
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<title"));
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<h1"));
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<h2"));
@@ -244,10 +246,9 @@
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<option"));
   // One for meta in head and another for meta in body.
   EXPECT_EQ(2, MatchSubstring(mhtml, "<meta", 5));
-  // One for style in head and another for style in body.
-  EXPECT_EQ(2, MatchSubstring(mhtml, "<style", 6));
-  // One for link in head and another for link in body.
-  EXPECT_EQ(2, MatchSubstring(mhtml, "<link", 5));
+  // Two for original link elements: one in head and another in body.
+  // Two for original style elemtns: one in head and another in body.
+  EXPECT_EQ(4, MatchSubstring(mhtml, "<link", 5));
 
   // These visible elements should remain intact.
   EXPECT_NE(WTF::kNotFound, mhtml.Find("<p id=3D\"visible_id\""));
@@ -402,4 +403,14 @@
   EXPECT_EQ(WTF::kNotFound, mhtml.Find("shadowdelegatesfocus=3D\"bar\">"));
 }
 
+TEST_F(WebFrameSerializerSanitizationTest, StyleElementsWithDynamicCSS) {
+  String mhtml = GenerateMHTMLFromHtml("http://www.test.com",
+                                       "style_element_with_dynamic_css.html");
+
+  // The dynamically updated CSS rules should be preserved.
+  EXPECT_NE(WTF::kNotFound, mhtml.Find("div { color: blue; }"));
+  EXPECT_NE(WTF::kNotFound, mhtml.Find("p { color: red; }"));
+  EXPECT_EQ(WTF::kNotFound, mhtml.Find("h1 { color: green; }"));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/frame_serializer.cc b/third_party/blink/renderer/core/frame/frame_serializer.cc
index aa2eff37..9c258b0 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer.cc
+++ b/third_party/blink/renderer/core/frame/frame_serializer.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/core/css/css_rule_list.h"
 #include "third_party/blink/renderer/core/css/css_style_declaration.h"
 #include "third_party/blink/renderer/core/css/css_style_rule.h"
+#include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/css_value_list.h"
 #include "third_party/blink/renderer/core/css/style_rule.h"
 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
@@ -64,6 +65,7 @@
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/mhtml/serialized_resource.h"
+#include "third_party/blink/renderer/platform/uuid.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
@@ -83,8 +85,8 @@
 
  public:
   SerializerMarkupAccumulator(FrameSerializer::Delegate&,
-                              const Document&,
-                              HeapVector<Member<const Element>>&);
+                              FrameSerializerResourceDelegate&,
+                              Document&);
   ~SerializerMarkupAccumulator() override;
 
  protected:
@@ -100,15 +102,11 @@
   void AppendRewrittenAttribute(const Element&,
                                 const String& attribute_name,
                                 const String& attribute_value);
+  void AppendExtraForHeadElement(const Element&);
 
   FrameSerializer::Delegate& delegate_;
-  Member<const Document> document_;
-
-  // FIXME: |FrameSerializer| uses |elements_| for collecting elements in
-  // document included into serialized text then extracts image, object, etc.
-  // The size of this vector isn't small for large document. It is better to use
-  // callback like functionality.
-  HeapVector<Member<const Element>>& elements_;
+  FrameSerializerResourceDelegate& resource_delegate_;
+  Member<Document> document_;
 
   // Elements with links rewritten via appendAttribute method.
   HeapHashSet<Member<const Element>> elements_with_rewritten_links_;
@@ -116,14 +114,14 @@
 
 SerializerMarkupAccumulator::SerializerMarkupAccumulator(
     FrameSerializer::Delegate& delegate,
-    const Document& document,
-    HeapVector<Member<const Element>>& elements)
+    FrameSerializerResourceDelegate& resource_delegate,
+    Document& document)
     : MarkupAccumulator(kResolveAllURLs,
                         document.IsHTMLDocument() ? SerializationType::kHTML
                                                   : SerializationType::kXML),
       delegate_(delegate),
-      document_(&document),
-      elements_(elements) {}
+      resource_delegate_(resource_delegate),
+      document_(&document) {}
 
 SerializerMarkupAccumulator::~SerializerMarkupAccumulator() = default;
 
@@ -150,6 +148,9 @@
       ToHTMLMetaElement(element).ComputeEncoding().IsValid()) {
     return true;
   }
+  // This is done in serializing document.StyleSheets.
+  if (IsHTMLStyleElement(element))
+    return true;
   return delegate_.ShouldIgnoreElement(element);
 }
 
@@ -157,19 +158,10 @@
     const Element& element) {
   AtomicString prefix = MarkupAccumulator::AppendElement(element);
 
-  // TODO(tiger): Refactor MarkupAccumulator so it is easier to append an
-  // element like this, without special cases for XHTML
-  if (IsHTMLHeadElement(element)) {
-    markup_.Append("<meta http-equiv=\"Content-Type\" content=\"");
-    AppendAttributeValue(document_->SuggestedMIMEType());
-    markup_.Append("; charset=");
-    AppendAttributeValue(document_->characterSet());
-    if (document_->IsXHTMLDocument())
-      markup_.Append("\" />");
-    else
-      markup_.Append("\">");
-  }
-  elements_.push_back(&element);
+  if (IsHTMLHeadElement(element))
+    AppendExtraForHeadElement(element);
+
+  resource_delegate_.AddResourceForElement(*document_, element);
 
   // FIXME: For object (plugins) tags and video tag we could replace them by an
   // image of their current contents.
@@ -177,6 +169,48 @@
   return prefix;
 }
 
+void SerializerMarkupAccumulator::AppendExtraForHeadElement(
+    const Element& element) {
+  DCHECK(IsHTMLHeadElement(element));
+
+  // TODO(tiger): Refactor MarkupAccumulator so it is easier to append an
+  // element like this, without special cases for XHTML
+  markup_.Append("<meta http-equiv=\"Content-Type\" content=\"");
+  AppendAttributeValue(document_->SuggestedMIMEType());
+  markup_.Append("; charset=");
+  AppendAttributeValue(document_->characterSet());
+  if (document_->IsXHTMLDocument())
+    markup_.Append("\" />");
+  else
+    markup_.Append("\">");
+
+  // The CSS rules of a style element can be updated dynamically independent of
+  // the CSS text included in the style element. So we can't use the inline
+  // CSS text defined in the style element. To solve this, we serialize the
+  // working CSS rules in document.stylesheets and wrap them in link elements.
+  StyleSheetList& sheets = document_->StyleSheets();
+  for (unsigned i = 0; i < sheets.length(); ++i) {
+    StyleSheet* sheet = sheets.item(i);
+    if (!sheet->IsCSSStyleSheet() || sheet->disabled() ||
+        !IsHTMLStyleElement(sheet->ownerNode())) {
+      continue;
+    }
+
+    StringBuilder pseudo_sheet_url_builder;
+    pseudo_sheet_url_builder.Append("cid:css-");
+    pseudo_sheet_url_builder.Append(CreateCanonicalUUIDString());
+    pseudo_sheet_url_builder.Append("@mhtml.blink");
+    KURL pseudo_sheet_url = KURL(pseudo_sheet_url_builder.ToString());
+
+    markup_.Append("<link rel=\"stylesheet\" type=\"text/css\" href=\"");
+    markup_.Append(pseudo_sheet_url.GetString());
+    markup_.Append("\" />");
+
+    resource_delegate_.SerializeCSSStyleSheet(
+        static_cast<CSSStyleSheet&>(*sheet), pseudo_sheet_url);
+  }
+}
+
 void SerializerMarkupAccumulator::AppendAttribute(const Element& element,
                                                   const Attribute& attribute) {
   // Check if link rewriting can affect the attribute.
@@ -268,58 +302,24 @@
     return;
   }
 
-  HeapVector<Member<const Element>> serialized_elements;
+  should_collect_problem_metric_ =
+      delegate_.ShouldCollectProblemMetric() && frame.IsMainFrame();
   {
     TRACE_EVENT0("page-serialization", "FrameSerializer::serializeFrame HTML");
     SCOPED_BLINK_UMA_HISTOGRAM_TIMER(
         "PageSerialization.SerializationTime.Html");
-    SerializerMarkupAccumulator accumulator(delegate_, document,
-                                            serialized_elements);
+    SerializerMarkupAccumulator accumulator(delegate_, *this, document);
     String text =
         accumulator.SerializeNodes<EditingStrategy>(document, kIncludeNode);
 
     std::string frame_html =
         document.Encoding().Encode(text, WTF::kEntitiesForUnencodables);
-    resources_->push_back(SerializedResource(
+    // Note that the frame has to be 1st resource.
+    resources_->push_front(SerializedResource(
         url, document.SuggestedMIMEType(),
         SharedBuffer::Create(frame_html.c_str(), frame_html.length())));
   }
 
-  should_collect_problem_metric_ =
-      delegate_.ShouldCollectProblemMetric() && frame.IsMainFrame();
-  for (const Element* node : serialized_elements) {
-    DCHECK(node);
-    const Element& element = *node;
-    // We have to process in-line style as it might contain some resources
-    // (typically background images).
-    if (element.IsStyledElement()) {
-      RetrieveResourcesForProperties(element.InlineStyle(), document);
-      RetrieveResourcesForProperties(
-          const_cast<Element&>(element).PresentationAttributeStyle(), document);
-    }
-
-    if (const auto* image = ToHTMLImageElementOrNull(element)) {
-      KURL image_url =
-          document.CompleteURL(image->getAttribute(html_names::kSrcAttr));
-      ImageResourceContent* cached_image = image->CachedImage();
-      AddImageToResources(cached_image, image_url);
-    } else if (const auto* input = ToHTMLInputElementOrNull(element)) {
-      if (input->type() == input_type_names::kImage && input->ImageLoader()) {
-        KURL image_url = input->Src();
-        ImageResourceContent* cached_image = input->ImageLoader()->GetContent();
-        AddImageToResources(cached_image, image_url);
-      }
-    } else if (const auto* link = ToHTMLLinkElementOrNull(element)) {
-      if (CSSStyleSheet* sheet = link->sheet()) {
-        KURL sheet_url =
-            document.CompleteURL(link->getAttribute(html_names::kHrefAttr));
-        SerializeCSSStyleSheet(*sheet, sheet_url);
-      }
-    } else if (const auto* style = ToHTMLStyleElementOrNull(element)) {
-      if (CSSStyleSheet* sheet = style->sheet())
-        SerializeCSSStyleSheet(*sheet, NullURL());
-    }
-  }
   if (should_collect_problem_metric_) {
     // Report detectors through UMA.
     // We're having exact 21 buckets for percentage because we want to have 5%
@@ -350,6 +350,39 @@
   }
 }
 
+void FrameSerializer::AddResourceForElement(Document& document,
+                                            const Element& element) {
+  // We have to process in-line style as it might contain some resources
+  // (typically background images).
+  if (element.IsStyledElement()) {
+    RetrieveResourcesForProperties(element.InlineStyle(), document);
+    RetrieveResourcesForProperties(
+        const_cast<Element&>(element).PresentationAttributeStyle(), document);
+  }
+
+  if (const auto* image = ToHTMLImageElementOrNull(element)) {
+    KURL image_url =
+        document.CompleteURL(image->getAttribute(html_names::kSrcAttr));
+    ImageResourceContent* cached_image = image->CachedImage();
+    AddImageToResources(cached_image, image_url);
+  } else if (const auto* input = ToHTMLInputElementOrNull(element)) {
+    if (input->type() == input_type_names::kImage && input->ImageLoader()) {
+      KURL image_url = input->Src();
+      ImageResourceContent* cached_image = input->ImageLoader()->GetContent();
+      AddImageToResources(cached_image, image_url);
+    }
+  } else if (const auto* link = ToHTMLLinkElementOrNull(element)) {
+    if (CSSStyleSheet* sheet = link->sheet()) {
+      KURL sheet_url =
+          document.CompleteURL(link->getAttribute(html_names::kHrefAttr));
+      SerializeCSSStyleSheet(*sheet, sheet_url);
+    }
+  } else if (const auto* style = ToHTMLStyleElementOrNull(element)) {
+    if (CSSStyleSheet* sheet = style->sheet())
+      SerializeCSSStyleSheet(*sheet, NullURL());
+  }
+}
+
 void FrameSerializer::SerializeCSSStyleSheet(CSSStyleSheet& style_sheet,
                                              const KURL& url) {
   // If the URL is invalid or if it is a data URL this means that this CSS is
diff --git a/third_party/blink/renderer/core/frame/frame_serializer.h b/third_party/blink/renderer/core/frame/frame_serializer.h
index 28491e7..ea240648 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer.h
+++ b/third_party/blink/renderer/core/frame/frame_serializer.h
@@ -56,10 +56,23 @@
 
 struct SerializedResource;
 
+class FrameSerializerResourceDelegate {
+ public:
+  virtual ~FrameSerializerResourceDelegate() = default;
+
+  // Adds the resource needed to serialize an element.
+  virtual void AddResourceForElement(Document&, const Element&) = 0;
+
+  // Serializes the stylesheet back to text and adds it to the resources if
+  // URL is not-empty.  It also adds any resources included in that stylesheet
+  // (including any imported stylesheets and their own resources).
+  virtual void SerializeCSSStyleSheet(CSSStyleSheet&, const KURL&) = 0;
+};
+
 // This class is used to serialize frame's contents back to text (typically
 // HTML).  It serializes frame's document and resources such as images and CSS
 // stylesheets.
-class CORE_EXPORT FrameSerializer final {
+class CORE_EXPORT FrameSerializer : public FrameSerializerResourceDelegate {
   STACK_ALLOCATED();
 
  public:
@@ -123,10 +136,8 @@
   static String MarkOfTheWebDeclaration(const KURL&);
 
  private:
-  // Serializes the stylesheet back to text and adds it to the resources if URL
-  // is not-empty.  It also adds any resources included in that stylesheet
-  // (including any imported stylesheets and their own resources).
-  void SerializeCSSStyleSheet(CSSStyleSheet&, const KURL&);
+  void AddResourceForElement(Document&, const Element&) override;
+  void SerializeCSSStyleSheet(CSSStyleSheet&, const KURL&) override;
 
   // Serializes the css rule (including any imported stylesheets), adding
   // referenced resources.
diff --git a/third_party/blink/renderer/core/frame/frame_serializer_test.cc b/third_party/blink/renderer/core/frame/frame_serializer_test.cc
index c8728b4a..77f2276 100644
--- a/third_party/blink/renderer/core/frame/frame_serializer_test.cc
+++ b/third_party/blink/renderer/core/frame/frame_serializer_test.cc
@@ -369,7 +369,9 @@
 
   Serialize("css_test_page.html");
 
-  EXPECT_EQ(16U, GetResources().size());
+  // 16 resoucres added by RegisterURL + 3 resources added due to converting
+  // style elements to link elements.
+  EXPECT_EQ(19U, GetResources().size());
 
   EXPECT_FALSE(IsSerialized("do_not_serialize.png", "image/png"));
   EXPECT_FALSE(IsSerialized("included_in_another_frame.css", "text/css"));
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
index 34f0c28..72d92475 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
@@ -58,10 +58,11 @@
 
 }  // namespace
 
-void LazyLoadImageObserver::StartMonitoring(Element* element) {
+void LazyLoadImageObserver::StartMonitoring(Element* element,
+                                            bool is_for_intervention) {
   if (Document* document = GetRootDocumentOrNull(element)) {
     document->EnsureLazyLoadImageObserver().StartMonitoringNearViewport(
-        document, element);
+        document, element, is_for_intervention);
   }
 }
 
@@ -93,16 +94,13 @@
 
 LazyLoadImageObserver::LazyLoadImageObserver() = default;
 
-void LazyLoadImageObserver::StartMonitoringNearViewport(Document* root_document,
-                                                        Element* element) {
+void LazyLoadImageObserver::StartMonitoringNearViewport(
+    Document* root_document,
+    Element* element,
+    bool is_for_intervention) {
   DCHECK(RuntimeEnabledFeatures::LazyImageLoadingEnabled());
 
   if (!lazy_load_intersection_observer_) {
-    root_document->AddConsoleMessage(ConsoleMessage::Create(
-        mojom::ConsoleMessageSource::kIntervention,
-        mojom::ConsoleMessageLevel::kInfo,
-        "Images loaded lazily and replaced with placeholders. Load events are "
-        "deferred. See https://crbug.com/846170"));
     lazy_load_intersection_observer_ = IntersectionObserver::Create(
         {Length::Fixed(
             GetLazyImageLoadingViewportDistanceThresholdPx(*root_document))},
@@ -111,6 +109,15 @@
                            WrapWeakPersistent(this)));
   }
   lazy_load_intersection_observer_->observe(element);
+
+  if (is_for_intervention && !is_load_event_deferred_intervention_shown_) {
+    is_load_event_deferred_intervention_shown_ = true;
+    root_document->AddConsoleMessage(ConsoleMessage::Create(
+        mojom::ConsoleMessageSource::kIntervention,
+        mojom::ConsoleMessageLevel::kInfo,
+        "Images loaded lazily and replaced with placeholders. Load events are "
+        "deferred. See https://crbug.com/846170"));
+  }
 }
 
 void LazyLoadImageObserver::LoadIfNearViewport(
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer.h b/third_party/blink/renderer/core/html/lazy_load_image_observer.h
index 806ee5df..4e79100a 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer.h
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer.h
@@ -35,7 +35,7 @@
 
   LazyLoadImageObserver();
 
-  static void StartMonitoring(Element*);
+  static void StartMonitoring(Element*, bool is_for_intervention);
   static void StopMonitoring(Element*);
 
   static void StartTrackingVisibilityMetrics(HTMLImageElement*);
@@ -44,7 +44,9 @@
   void Trace(Visitor*);
 
  private:
-  void StartMonitoringNearViewport(Document*, Element*);
+  void StartMonitoringNearViewport(Document*,
+                                   Element*,
+                                   bool is_for_intervention);
   void LoadIfNearViewport(const HeapVector<Member<IntersectionObserverEntry>>&);
 
   void StartMonitoringVisibility(Document*, HTMLImageElement*);
@@ -59,6 +61,9 @@
 
   // The intersection observer used to track when the image becomes visible.
   Member<IntersectionObserver> visibility_metrics_observer_;
+
+  // Used to show the intervention console message one time only.
+  bool is_load_event_deferred_intervention_shown_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
index be795514..01498a4 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
@@ -34,6 +34,10 @@
 
 namespace {
 
+const char* kLazyLoadEventsDeferredMessage =
+    "Images loaded lazily and replaced with placeholders. Load events are "
+    "deferred. See https://crbug.com/846170";
+
 Vector<char> ReadTestImage() {
   return test::ReadFromFile(test::CoreTestDataPath("notifications/500x500.png"))
       ->CopyAs<Vector<char>>();
@@ -83,6 +87,7 @@
       }
     }
     EXPECT_TRUE(is_background_image_found);
+    EXPECT_FALSE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
   }
 
   void VerifyCSSBackgroundImageInPseudoStyleDeferred(
@@ -128,6 +133,7 @@
                                               false);
       }
     }
+    EXPECT_FALSE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
   }
 
   void VerifyImageElementWithDimensionDeferred(const char* img_attribute) {
@@ -162,6 +168,8 @@
       test::RunPendingTasks();
       EXPECT_TRUE(ConsoleMessages().Contains("deferred_image onload"));
     }
+    EXPECT_EQ(is_lazyload_image_enabled,
+              ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
   }
 
  private:
@@ -803,6 +811,7 @@
 
     EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
     EXPECT_TRUE(ConsoleMessages().Contains("image onload"));
+    EXPECT_TRUE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
   }
 
   void TestLoadImageExpectingFullImageLoad(const char* image_attributes) {
@@ -823,6 +832,7 @@
 
     EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
     EXPECT_TRUE(ConsoleMessages().Contains("image onload"));
+    EXPECT_FALSE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
   }
 
  private:
@@ -854,6 +864,7 @@
 
   EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
   EXPECT_TRUE(ConsoleMessages().Contains("image onload"));
+  EXPECT_FALSE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
 }
 
 TEST_F(LazyLoadAutomaticImagesTest, AttributeChangedFromAutoToEager) {
@@ -877,6 +888,7 @@
 
   EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
   EXPECT_TRUE(ConsoleMessages().Contains("image onload"));
+  EXPECT_TRUE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
 }
 
 TEST_F(LazyLoadAutomaticImagesTest, AttributeChangedFromUnsetToEager) {
@@ -900,15 +912,18 @@
 
   EXPECT_TRUE(ConsoleMessages().Contains("main body onload"));
   EXPECT_TRUE(ConsoleMessages().Contains("image onload"));
+  EXPECT_TRUE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
 }
 
 TEST_F(LazyLoadAutomaticImagesTest, TinyImageWithLazyAttr) {
   TestLoadImageExpectingLazyLoad("loading='lazy' width='1px' height='1px'");
+  EXPECT_FALSE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
 }
 
 TEST_F(LazyLoadAutomaticImagesTest, TinyImageViaStyleWithLazyAttr) {
   TestLoadImageExpectingLazyLoad(
       "loading='lazy' style='width:1px;height:1px;'");
+  EXPECT_FALSE(ConsoleMessages().Contains(kLazyLoadEventsDeferredMessage));
 }
 
 TEST_F(LazyLoadAutomaticImagesTest, TinyImageWidth1Height1) {
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 812bbd1..7a020824 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -6922,6 +6922,9 @@
       AuthenticatorTransport transport
       boolean hasResidentKey
       boolean hasUserVerification
+      # If set to true, tests of user presence will succeed immediately.
+      # Otherwise, they will not be resolved. Defaults to true.
+      optional boolean automaticPresenceSimulation
 
   type Credential extends object
     properties
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 5df3768..e95416eb 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -77,6 +77,18 @@
   kEnabledAutomatic
 };
 
+enum class LoadingAttrValue { kAuto, kLazy, kEager };
+
+LoadingAttrValue GetLoadingAttrValue(const HTMLImageElement& html_image) {
+  const auto& attribute_value =
+      html_image.FastGetAttribute(html_names::kLoadingAttr);
+  return EqualIgnoringASCIICase(attribute_value, "eager")
+             ? LoadingAttrValue::kEager
+             : EqualIgnoringASCIICase(attribute_value, "lazy")
+                   ? LoadingAttrValue::kLazy
+                   : LoadingAttrValue::kAuto;
+}
+
 LazyLoadImageEligibility DetermineLazyLoadImageEligibility(
     const LocalFrame& frame,
     const HTMLImageElement& html_image,
@@ -84,11 +96,10 @@
   if (!url.ProtocolIsInHTTPFamily())
     return LazyLoadImageEligibility::kDisabled;
 
-  const String& loading_attr =
-      html_image.FastGetAttribute(html_names::kLoadingAttr);
-  if (EqualIgnoringASCIICase(loading_attr, "lazy"))
+  LoadingAttrValue loading_attr = GetLoadingAttrValue(html_image);
+  if (loading_attr == LoadingAttrValue::kLazy)
     return LazyLoadImageEligibility::kEnabledExplicit;
-  if (EqualIgnoringASCIICase(loading_attr, "eager") &&
+  if (loading_attr == LoadingAttrValue::kEager &&
       !frame.GetDocument()->IsLazyLoadPolicyEnforced()) {
     return LazyLoadImageEligibility::kDisabled;
   }
@@ -484,8 +495,13 @@
     }
   } else {
     image_complete_ = false;
-    if (lazy_image_load_state_ == LazyImageLoadState::kDeferred)
-      LazyLoadImageObserver::StartMonitoring(GetElement());
+    if (lazy_image_load_state_ == LazyImageLoadState::kDeferred) {
+      if (auto* html_image = ToHTMLImageElementOrNull(GetElement())) {
+        LazyLoadImageObserver::StartMonitoring(
+            html_image,
+            GetLoadingAttrValue(*html_image) != LoadingAttrValue::kLazy);
+      }
+    }
   }
   delay_until_image_notify_finished_ = nullptr;
 }
diff --git a/third_party/blink/renderer/core/paint/text_element_timing.cc b/third_party/blink/renderer/core/paint/text_element_timing.cc
index 99fed4b..a556064 100644
--- a/third_party/blink/renderer/core/paint/text_element_timing.cc
+++ b/third_party/blink/renderer/core/paint/text_element_timing.cc
@@ -6,8 +6,12 @@
 
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/paint/text_paint_timing_detector.h"
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
+#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/float_clip_rect.h"
+#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
@@ -33,6 +37,24 @@
       GetSupplementable()->document()));
 }
 
+// static
+FloatRect TextElementTiming::ComputeIntersectionRect(
+    Node* node,
+    const IntRect& aggregated_visual_rect,
+    const PropertyTreeState& property_tree_state,
+    LocalFrameView* frame_view) {
+  if (!NeededForElementTiming(node))
+    return FloatRect();
+
+  FloatClipRect float_clip_visual_rect =
+      FloatClipRect(FloatRect(aggregated_visual_rect));
+  GeometryMapper::LocalToAncestorVisualRect(
+      property_tree_state,
+      frame_view->GetLayoutView()->FirstFragment().LocalBorderBoxProperties(),
+      float_clip_visual_rect);
+  return float_clip_visual_rect.Rect();
+}
+
 void TextElementTiming::OnTextNodesPainted(
     const Deque<base::WeakPtr<TextRecord>>& text_nodes_painted) {
   DCHECK(performance_);
@@ -57,10 +79,9 @@
 
     const AtomicString& id = element->GetIdAttribute();
     DEFINE_STATIC_LOCAL(const AtomicString, kTextPaint, ("text-paint"));
-    // TODO(npm): Add the rect once these are stored in TextRecord.
-    performance_->AddElementTiming(kTextPaint, g_empty_string, FloatRect(),
-                                   record->paint_time, TimeTicks(), attr,
-                                   IntSize(), id, element);
+    performance_->AddElementTiming(
+        kTextPaint, g_empty_string, record->element_timing_rect_,
+        record->paint_time, TimeTicks(), attr, IntSize(), id, element);
   }
 }
 
diff --git a/third_party/blink/renderer/core/paint/text_element_timing.h b/third_party/blink/renderer/core/paint/text_element_timing.h
index 741504c..1754f87 100644
--- a/third_party/blink/renderer/core/paint/text_element_timing.h
+++ b/third_party/blink/renderer/core/paint/text_element_timing.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TEXT_ELEMENT_TIMING_H_
 
 #include "base/memory/weak_ptr.h"
+#include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
@@ -13,6 +14,9 @@
 
 namespace blink {
 
+class IntRect;
+class LocalFrameView;
+class PropertyTreeState;
 class TextRecord;
 
 // TextElementTiming is responsible for tracking the paint timings for groups of
@@ -29,6 +33,19 @@
 
   static TextElementTiming& From(LocalDOMWindow&);
 
+  static inline bool NeededForElementTiming(Node* node) {
+    return !node->IsInShadowTree() && node->IsElementNode() &&
+           !ToElement(node)
+                ->FastGetAttribute(html_names::kElementtimingAttr)
+                .IsEmpty();
+  }
+
+  static FloatRect ComputeIntersectionRect(
+      Node*,
+      const IntRect& aggregated_visual_rect,
+      const PropertyTreeState&,
+      LocalFrameView*);
+
   // Called when the swap promise queued by TextPaintTimingDetector has been
   // resolved. Dispatches PerformanceElementTiming entries to WindowPerformance.
   void OnTextNodesPainted(const Deque<base::WeakPtr<TextRecord>>&);
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
index d179191..8b7bd52 100644
--- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -24,12 +24,14 @@
 
 namespace blink {
 
+namespace {
+
 // Calculate metrics candidate every 1 second after the first text pre-paint.
-static constexpr TimeDelta kTimerDelay = TimeDelta::FromSeconds(1);
+constexpr TimeDelta kTimerDelay = TimeDelta::FromSeconds(1);
 constexpr size_t kTextNodeNumberLimit = 5000;
 
-static bool LargeTextFirst(const base::WeakPtr<TextRecord>& a,
-                           const base::WeakPtr<TextRecord>& b) {
+bool LargeTextFirst(const base::WeakPtr<TextRecord>& a,
+                    const base::WeakPtr<TextRecord>& b) {
   DCHECK(a);
   DCHECK(b);
   if (a->first_size != b->first_size)
@@ -39,6 +41,8 @@
   return a->node_id > b->node_id;
 }
 
+}  // namespace
+
 TextPaintTimingDetector::TextPaintTimingDetector(LocalFrameView* frame_view)
     : records_manager_(),
       timer_(frame_view->GetFrame().GetTaskRunner(TaskType::kInternalDefault),
@@ -182,14 +186,9 @@
   // If we have finished recording Largest Text Paint and the element is a
   // shadow element or has no elementtiming attribute, then we should not record
   // its text.
-  if (!is_recording_ltp_) {
-    if (node->IsInShadowTree() || !node->IsElementNode() ||
-        ToElement(node)
-            ->FastGetAttribute(html_names::kElementtimingAttr)
-            .IsEmpty()) {
-      return false;
-    }
-  }
+  if (!is_recording_ltp_ && !TextElementTiming::NeededForElementTiming(node))
+    return false;
+
   DOMNodeId node_id = DOMNodeIds::ExistingIdForNode(node);
   if (node_id == kInvalidDOMNodeId)
     return true;
@@ -221,7 +220,11 @@
   if (aggregated_size == 0) {
     records_manager_.RecordInvisibleNode(node_id);
   } else {
-    records_manager_.RecordVisibleNode(node_id, aggregated_size, aggregator);
+    records_manager_.RecordVisibleNode(
+        node_id, aggregated_size,
+        TextElementTiming::ComputeIntersectionRect(
+            node, aggregated_visual_rect, property_tree_state, frame_view_),
+        aggregator);
   }
 
   if (records_manager_.HasTooManyNodes()) {
@@ -301,11 +304,12 @@
 
 void TextRecordsManager::RecordVisibleNode(const DOMNodeId& node_id,
                                            const uint64_t& visual_size,
+                                           const FloatRect& element_timing_rect,
                                            const LayoutObject& text_object) {
   DCHECK(!HasTooManyNodes());
   DCHECK_GT(visual_size, 0u);
   std::unique_ptr<TextRecord> record =
-      std::make_unique<TextRecord>(node_id, visual_size);
+      std::make_unique<TextRecord>(node_id, visual_size, element_timing_rect);
 #ifndef NDEBUG
   String text;
   if (text_object.IsText()) {
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
index c6d325b..b9d483788 100644
--- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
+++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -28,11 +28,16 @@
 
 class TextRecord : public base::SupportsWeakPtr<TextRecord> {
  public:
-  TextRecord(DOMNodeId new_node_id, uint64_t new_first_size)
-      : node_id(new_node_id), first_size(new_first_size) {}
+  TextRecord(DOMNodeId new_node_id,
+             uint64_t new_first_size,
+             const FloatRect& element_timing_rect)
+      : node_id(new_node_id),
+        first_size(new_first_size),
+        element_timing_rect_(element_timing_rect) {}
 
   DOMNodeId node_id = kInvalidDOMNodeId;
   uint64_t first_size = 0;
+  FloatRect element_timing_rect_;
   // The time of the first paint after fully loaded.
   base::TimeTicks paint_time = base::TimeTicks();
 #ifndef NDEBUG
@@ -61,6 +66,7 @@
   }
   void RecordVisibleNode(const DOMNodeId&,
                          const uint64_t& visual_size,
+                         const FloatRect& element_timing_rect,
                          const LayoutObject&);
   bool NeedMeausuringPaintTime() const {
     return !texts_queued_for_paint_time_.IsEmpty();
diff --git a/third_party/blink/renderer/core/testing/data/frameserialization/style_element_with_dynamic_css.html b/third_party/blink/renderer/core/testing/data/frameserialization/style_element_with_dynamic_css.html
new file mode 100644
index 0000000..1464da5
--- /dev/null
+++ b/third_party/blink/renderer/core/testing/data/frameserialization/style_element_with_dynamic_css.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<meta charset="utf8">
+<title>Test style element with dynamically updated CSS</title>
+<style id="style1" type="text/css"></style>
+<style id="style2" type="text/css">h1: {color: green;}</style>
+<script>
+function Run() {
+  document.getElementById("style1").sheet.insertRule("div { color: blue; }", 0);
+  document.getElementById("style2").sheet.insertRule("p { color: red; }", 0);
+}
+</script>
+</head>
+<body onload="Run()">
+  <h1>Title</h1>
+  <div>Hello</div>
+  <p>World</p>
+</body>
+</html>
+
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 6e39dc5..4e8ac7d2 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -950,6 +950,7 @@
           "remoteplayback/html_media_element_remote_playback.idl",
           "screen_orientation/screen_screen_orientation.idl",
           "service_worker/navigator_service_worker.idl",
+          "sms/navigator_sms.idl",
           "speech/window_speech.idl",
           "speech/window_speech_synthesis.idl",
           "srcobject/html_media_element_src_object.idl",
diff --git a/third_party/blink/renderer/modules/sms/BUILD.gn b/third_party/blink/renderer/modules/sms/BUILD.gn
index ab4552d..f9ef335 100644
--- a/third_party/blink/renderer/modules/sms/BUILD.gn
+++ b/third_party/blink/renderer/modules/sms/BUILD.gn
@@ -6,6 +6,8 @@
 
 blink_modules_sources("sms") {
   sources = [
+    "navigator_sms.cc",
+    "navigator_sms.h",
     "sms.cc",
     "sms.h",
     "sms_receiver.cc",
diff --git a/third_party/blink/renderer/modules/sms/navigator_sms.cc b/third_party/blink/renderer/modules/sms/navigator_sms.cc
new file mode 100644
index 0000000..f248494
--- /dev/null
+++ b/third_party/blink/renderer/modules/sms/navigator_sms.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 "third_party/blink/renderer/modules/sms/navigator_sms.h"
+
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/modules/sms/sms_receiver.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+
+namespace blink {
+
+NavigatorSMS::NavigatorSMS(Navigator& navigator)
+    : Supplement<Navigator>(navigator) {}
+
+const char NavigatorSMS::kSupplementName[] = "NavigatorSMS";
+
+NavigatorSMS& NavigatorSMS::From(Navigator& navigator) {
+  NavigatorSMS* supplement =
+      Supplement<Navigator>::From<NavigatorSMS>(navigator);
+  if (!supplement) {
+    supplement = MakeGarbageCollected<NavigatorSMS>(navigator);
+    Supplement<Navigator>::ProvideTo(navigator, supplement);
+  }
+  return *supplement;
+}
+
+SMSReceiver* NavigatorSMS::GetSMSReceiver(ScriptState* script_state) {
+  if (!sms_receiver_) {
+    sms_receiver_ =
+        MakeGarbageCollected<SMSReceiver>(ExecutionContext::From(script_state));
+  }
+  return sms_receiver_.Get();
+}
+
+SMSReceiver* NavigatorSMS::sms(ScriptState* script_state,
+                               Navigator& navigator) {
+  return NavigatorSMS::From(navigator).GetSMSReceiver(script_state);
+}
+
+void NavigatorSMS::Trace(blink::Visitor* visitor) {
+  visitor->Trace(sms_receiver_);
+  Supplement<Navigator>::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/sms/navigator_sms.h b/third_party/blink/renderer/modules/sms/navigator_sms.h
new file mode 100644
index 0000000..91f595e5
--- /dev/null
+++ b/third_party/blink/renderer/modules/sms/navigator_sms.h
@@ -0,0 +1,41 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SMS_NAVIGATOR_SMS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SMS_NAVIGATOR_SMS_H_
+
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class Navigator;
+class ScriptState;
+class SMSReceiver;
+
+class NavigatorSMS final : public GarbageCollected<NavigatorSMS>,
+                           public Supplement<Navigator> {
+  USING_GARBAGE_COLLECTED_MIXIN(NavigatorSMS);
+
+ public:
+  static const char kSupplementName[];
+
+  static NavigatorSMS& From(Navigator&);
+
+  static SMSReceiver* sms(ScriptState*, Navigator&);
+
+  explicit NavigatorSMS(Navigator&);
+
+  void Trace(blink::Visitor*) override;
+
+ private:
+  SMSReceiver* GetSMSReceiver(ScriptState*);
+
+  Member<SMSReceiver> sms_receiver_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SMS_NAVIGATOR_SMS_H_
diff --git a/third_party/blink/renderer/modules/sms/navigator_sms.idl b/third_party/blink/renderer/modules/sms/navigator_sms.idl
new file mode 100644
index 0000000..b979116
--- /dev/null
+++ b/third_party/blink/renderer/modules/sms/navigator_sms.idl
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/samuelgoto/sms-receiver
+
+[
+  SecureContext,
+  Exposed=Window,
+  ImplementedAs=NavigatorSMS,
+  RuntimeEnabled=SmsReceiver
+] partial interface Navigator {
+  [CallWith=ScriptState] readonly attribute SMSReceiver sms;
+};
diff --git a/third_party/blink/renderer/modules/sms/sms_receiver.cc b/third_party/blink/renderer/modules/sms/sms_receiver.cc
index f153a99c..62cee53 100644
--- a/third_party/blink/renderer/modules/sms/sms_receiver.cc
+++ b/third_party/blink/renderer/modules/sms/sms_receiver.cc
@@ -9,6 +9,7 @@
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/mojom/sms/sms_manager.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/sms/sms.h"
@@ -26,50 +27,10 @@
 
 }  // namespace
 
-SMSReceiver* SMSReceiver::Create(ScriptState* script_state,
-                                 const SMSReceiverOptions* options,
-                                 ExceptionState& exception_state) {
-  int32_t timeout_seconds =
-      options->hasTimeout() ? options->timeout() : kDefaultTimeoutSeconds;
+SMSReceiver::SMSReceiver(ExecutionContext* context) : ContextClient(context) {}
 
-  if (timeout_seconds <= 0) {
-    exception_state.ThrowTypeError("Invalid timeout");
-    return nullptr;
-  }
-
-  base::TimeDelta timeout = base::TimeDelta::FromSeconds(timeout_seconds);
-
-  return MakeGarbageCollected<SMSReceiver>(ExecutionContext::From(script_state),
-                                           timeout);
-}
-
-// static
-SMSReceiver* SMSReceiver::Create(ScriptState* script_state,
-                                 ExceptionState& exception_state) {
-  return Create(script_state, SMSReceiverOptions::Create(), exception_state);
-}
-
-SMSReceiver::SMSReceiver(ExecutionContext* context, base::TimeDelta timeout)
-    : ContextClient(context), timeout_(timeout) {}
-
-SMSReceiver::~SMSReceiver() = default;
-
-const AtomicString& SMSReceiver::InterfaceName() const {
-  return event_target_names::kSMSReceiver;
-}
-
-ExecutionContext* SMSReceiver::GetExecutionContext() const {
-  return ContextClient::GetExecutionContext();
-}
-
-bool SMSReceiver::HasPendingActivity() const {
-  // This object should be considered active as long as there are registered
-  // event listeners.
-  return GetExecutionContext() && HasEventListeners();
-}
-
-ScriptPromise SMSReceiver::start(ScriptState* script_state) {
-  // Validate options.
+ScriptPromise SMSReceiver::receive(ScriptState* script_state,
+                                   const SMSReceiverOptions* options) {
   ExecutionContext* context = ExecutionContext::From(script_state);
   DCHECK(context->IsContextThread());
 
@@ -81,12 +42,19 @@
                           "Must be in top-level browsing context."));
   }
 
-  StartMonitoring();
+  int32_t timeout_seconds =
+      options->hasTimeout() ? options->timeout() : kDefaultTimeoutSeconds;
 
-  return ScriptPromise::CastUndefined(script_state);
-}
+  if (timeout_seconds <= 0) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state,
+        MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
+                                           "Invalid timeout."));
+  }
 
-void SMSReceiver::StartMonitoring() {
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  requests_.insert(resolver);
+
   // See https://bit.ly/2S0zRAS for task types.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       GetExecutionContext()->GetTaskRunner(TaskType::kInternalIPC);
@@ -94,30 +62,45 @@
   if (!service_) {
     GetExecutionContext()->GetInterfaceProvider()->GetInterface(
         mojo::MakeRequest(&service_, task_runner));
+    service_.set_connection_error_handler(WTF::Bind(
+        &SMSReceiver::OnSMSReceiverConnectionError, WrapWeakPersistent(this)));
   }
 
-  service_->GetNextMessage(timeout_, WTF::Bind(&SMSReceiver::OnGetNextMessage,
-                                               WrapPersistent(this)));
+  service_->GetNextMessage(
+      base::TimeDelta::FromSeconds(timeout_seconds),
+      WTF::Bind(&SMSReceiver::OnGetNextMessage, WrapPersistent(this),
+                WrapPersistent(resolver)));
+
+  return resolver->Promise();
 }
 
-void SMSReceiver::OnGetNextMessage(mojom::blink::SmsMessagePtr sms) {
+SMSReceiver::~SMSReceiver() = default;
+
+void SMSReceiver::OnGetNextMessage(ScriptPromiseResolver* resolver,
+                                   mojom::blink::SmsMessagePtr sms) {
+  requests_.erase(resolver);
+
   if (sms->status == mojom::blink::SmsStatus::kTimeout) {
-    DispatchEvent(*Event::Create(event_type_names::kTimeout));
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kTimeoutError, "SMSReceiver timed out."));
     return;
   }
-  sms_ = MakeGarbageCollected<blink::SMS>(std::move(sms->content));
-  DispatchEvent(*Event::Create(event_type_names::kChange));
+  resolver->Resolve(MakeGarbageCollected<blink::SMS>(std::move(sms->content)));
 }
 
-SMS* SMSReceiver::sms() const {
-  return sms_;
+void SMSReceiver::OnSMSReceiverConnectionError() {
+  service_.reset();
+  for (ScriptPromiseResolver* request : requests_) {
+    request->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kNotFoundError, "SMSReceiver not available."));
+  }
+  requests_.clear();
 }
 
 void SMSReceiver::Trace(Visitor* visitor) {
-  EventTargetWithInlineData::Trace(visitor);
-  ActiveScriptWrappable::Trace(visitor);
+  ScriptWrappable::Trace(visitor);
   ContextClient::Trace(visitor);
-  visitor->Trace(sms_);
+  visitor->Trace(requests_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/sms/sms_receiver.h b/third_party/blink/renderer/modules/sms/sms_receiver.h
index b4b70f2c..dc8380d0 100644
--- a/third_party/blink/renderer/modules/sms/sms_receiver.h
+++ b/third_party/blink/renderer/modules/sms/sms_receiver.h
@@ -7,59 +7,37 @@
 
 #include "base/macros.h"
 #include "third_party/blink/public/mojom/sms/sms_manager.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
-#include "third_party/blink/renderer/modules/event_modules.h"
-#include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 
 namespace blink {
 
-class SMS;
 class SMSReceiverOptions;
+class ScriptPromiseResolver;
 
-class SMSReceiver final : public EventTargetWithInlineData,
-                          public ActiveScriptWrappable<SMSReceiver>,
-                          public ContextClient {
+class SMSReceiver final : public ScriptWrappable, public ContextClient {
   USING_GARBAGE_COLLECTED_MIXIN(SMSReceiver);
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static SMSReceiver* Create(ScriptState*,
-                             const SMSReceiverOptions*,
-                             ExceptionState&);
-  static SMSReceiver* Create(ScriptState*, ExceptionState&);
-
-  SMSReceiver(ExecutionContext*, base::TimeDelta threshold);
+  explicit SMSReceiver(ExecutionContext*);
 
   ~SMSReceiver() override;
 
-  // EventTarget implementation.
-  const AtomicString& InterfaceName() const override;
-  ExecutionContext* GetExecutionContext() const override;
-
-  // ActiveScriptWrappable implementation.
-  bool HasPendingActivity() const final;
-
   // SMSReceiver IDL interface.
-  ScriptPromise start(ScriptState*);
-  void stop();
-  SMS* sms() const;
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(change, kChange)
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(timeout, kTimeout)
-
-  void OnGetNextMessage(mojom::blink::SmsMessagePtr sms);
+  ScriptPromise receive(ScriptState*, const SMSReceiverOptions*);
 
   void Trace(blink::Visitor*) override;
 
  private:
-  Member<SMS> sms_;
+  HeapHashSet<Member<ScriptPromiseResolver>> requests_;
 
-  const base::TimeDelta timeout_;
+  void OnGetNextMessage(ScriptPromiseResolver* resolver,
+                        mojom::blink::SmsMessagePtr sms);
 
-  void StartMonitoring();
+  void OnSMSReceiverConnectionError();
 
   mojom::blink::SmsManagerPtr service_;
 
diff --git a/third_party/blink/renderer/modules/sms/sms_receiver.idl b/third_party/blink/renderer/modules/sms/sms_receiver.idl
index 6515294..ee89a03 100644
--- a/third_party/blink/renderer/modules/sms/sms_receiver.idl
+++ b/third_party/blink/renderer/modules/sms/sms_receiver.idl
@@ -6,14 +6,9 @@
 
 [
   SecureContext,
-  Exposed=(Window,DedicatedWorker),
-  ActiveScriptWrappable,
-  Constructor(optional SMSReceiverOptions options),
-  ConstructorCallWith=ScriptState,
-  RaisesException=Constructor,
+  Exposed=Window,
   RuntimeEnabled=SmsReceiver
-] interface SMSReceiver : EventTarget {
-  readonly attribute SMS sms;
-  attribute EventHandler onchange;
-  [CallWith=ScriptState, MeasureAs=SMSReceiverStart] Promise<void> start();
+] interface SMSReceiver {
+  [CallWith=ScriptState, MeasureAs=SMSReceiverStart]
+  Promise<SMS> receive(optional SMSReceiverOptions options);
 };
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 6f61023..b0a6ed86a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -378,6 +378,8 @@
 
 # ====== Layout team owned tests from here ======
 
+crbug.com/974853 external/wpt/css/CSS2/abspos/hypothetical-box-dynamic.html [ Failure ]
+
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule3-outside-left-002.xht [ Failure ]
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule3-outside-right-002.xht [ Failure ]
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule7-outside-left-001.xht [ Failure ]
@@ -3324,7 +3326,6 @@
 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/699040 external/wpt/svg/text/reftests/text-xml-space-001.svg [ 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 ]
 crbug.com/626703 virtual/blink-cors/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ]
diff --git a/third_party/blink/web_tests/WebDriverExpectations b/third_party/blink/web_tests/WebDriverExpectations
index f2c4922..d944a75 100644
--- a/third_party/blink/web_tests/WebDriverExpectations
+++ b/third_party/blink/web_tests/WebDriverExpectations
@@ -924,7 +924,6 @@
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/element_click/bubbling.py>>test_spin_event_loop [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/take_screenshot/user_prompts.py>>test_ignore[capabilities0-confirm] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/permissions/set.py>>test_set_to_state[realmSetting2-denied] [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/element_send_keys/content_editable.py>>test_sets_insertion_point_to_after_last_text_node [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/take_screenshot/user_prompts.py>>test_ignore[capabilities0-prompt] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/new_session/create_alwaysMatch.py>>test_valid[pageLoadStrategy-eager] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/permissions/set.py>>test_invalid_parameters[parameters7] [ Failure ]
@@ -952,7 +951,6 @@
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/element_send_keys/scroll_into_view.py>>test_option_stays_outside_of_scrollable_viewport [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/permissions/set.py>>test_set_to_state[realmSetting1-granted] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/perform_actions/key_events.py>>test_special_key_sends_keydown[META-expected11] [ Failure ]
-crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/element_send_keys/content_editable.py>>test_sets_insertion_point_to_end [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/permissions/set.py>>test_invalid_parameters[parameters0] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/take_screenshot/user_prompts.py>>test_accept_and_notify[capabilities0-alert] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/perform_actions/key_special_keys.py>>test_codepoint_keys_behave_correctly[\u1100\u1161\u11a8] [ 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 197bd6b..8407a01 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
@@ -24385,6 +24385,18 @@
      {}
     ]
    ],
+   "css/CSS2/positioning/abspos-negative-margin-001.html": [
+    [
+     "css/CSS2/positioning/abspos-negative-margin-001.html",
+     [
+      [
+       "/css/CSS2/positioning/abspos-negative-margin-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/CSS2/positioning/abspos-overflow-001.xht": [
     [
      "css/CSS2/positioning/abspos-overflow-001.xht",
@@ -127646,6 +127658,9 @@
    "css/CSS2/positioning/abspos-inline-007-ref.xht": [
     []
    ],
+   "css/CSS2/positioning/abspos-negative-margin-001-ref.html": [
+    []
+   ],
    "css/CSS2/positioning/abspos-overflow-001-ref.xht": [
     []
    ],
@@ -210719,6 +210734,12 @@
      {}
     ]
    ],
+   "css/cssom/cssstyledeclaration-setter-form-controls.html": [
+    [
+     "css/cssom/cssstyledeclaration-setter-form-controls.html",
+     {}
+    ]
+   ],
    "css/cssom/cssstyledeclaration-setter-logical.html": [
     [
      "css/cssom/cssstyledeclaration-setter-logical.html",
@@ -331871,6 +331892,14 @@
    "9233b4373e5e4dc5beb6713a9af1de861c5cf4d9",
    "reftest"
   ],
+  "css/CSS2/positioning/abspos-negative-margin-001-ref.html": [
+   "e6f9bd6f9ad302edca80f34b70ebfcaf1d22e68c",
+   "support"
+  ],
+  "css/CSS2/positioning/abspos-negative-margin-001.html": [
+   "6b6246eb195d102e23b8d4c7a9407235b6cc14c1",
+   "reftest"
+  ],
   "css/CSS2/positioning/abspos-overflow-001-ref.xht": [
    "ba7e87c6a7c18a9335b51e07052ab47631299c9b",
    "support"
@@ -394731,6 +394760,10 @@
    "e66466e7a11b7883f9ad9de84d9cedc27ac3ea61",
    "testharness"
   ],
+  "css/cssom/cssstyledeclaration-setter-form-controls.html": [
+   "ae556ed1cbec68c757188518e2cf6cd4ebd5cd05",
+   "testharness"
+  ],
   "css/cssom/cssstyledeclaration-setter-logical-expected.txt": [
    "34394c9c2d9879db31a4abe34f828c5502e9cda6",
    "support"
@@ -435568,7 +435601,7 @@
    "testharness"
   ],
   "lint.whitelist": [
-   "be52aa67c00b9484180e316d6594e31d4918087d",
+   "9966d7c307b5520ab251d69f231526df762dc4ba",
    "support"
   ],
   "loading/preloader-css-import-no-quote.tentative.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-setter-form-controls.html b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-setter-form-controls.html
new file mode 100644
index 0000000..ae556ed1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/cssstyledeclaration-setter-form-controls.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<title>CSSOM test: no side effects from setting "height"</title>
+<link rel="help" href="https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-setproperty">
+<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=107380">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<p>
+Historically, the Apple Safari web browser has added an "intrinsic margin" to
+form controls which do not specify a `height`. It removed this margin following
+modification of the `height`. <a
+href="https://bugs.webkit.org/show_bug.cgi?id=107380">This non-standard
+behavior was identified as a source of confusion for web developers.</a>
+</p>
+
+<script>
+function makeElement(tagName) {
+  var element = document.createElement(tagName);
+  document.body.appendChild(element);
+  return element;
+}
+function makeInputElement(type) {
+  var element = makeElement('input');
+  element.setAttribute('type', type);
+  return element;
+}
+function measure(element) {
+  var computed = getComputedStyle(element);
+  return [computed.marginTop, computed.marginBottom];
+}
+
+test(function() {
+  var element = makeInputElement('text');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'text input element');
+
+test(function() {
+  var element = makeInputElement('button');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'button input element');
+
+test(function() {
+  var element = makeInputElement('submit');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'submit input element');
+
+test(function() {
+  var element = makeInputElement('radio');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'radio input element');
+
+test(function() {
+  var element = makeInputElement('checkbox');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'checkbox input element');
+
+test(function() {
+  var element = makeElement('textarea');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'textarea element');
+
+test(function() {
+  var element = makeElement('select');
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'select element');
+
+test(function() {
+  var element = makeElement('button')
+  var initial = measure(element);
+
+  element.style.setProperty('height', '12px');
+
+  assert_array_equals(measure(element), initial);
+}, 'button element');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/background-image-multiple-elements.html b/third_party/blink/web_tests/external/wpt/element-timing/background-image-multiple-elements.html
index 24f72a6..084bb9c 100644
--- a/third_party/blink/web_tests/external/wpt/element-timing/background-image-multiple-elements.html
+++ b/third_party/blink/web_tests/external/wpt/element-timing/background-image-multiple-elements.html
@@ -61,6 +61,8 @@
               observedDiv2Txt = true;
               checkTextElement(entry, 'et2', 'div2', beforeRender,
                 document.getElementById('div2'));
+              assert_greater_than_equal(entry.intersectionRect.right - entry.intersectionRect.left, 50);
+              assert_greater_than_equal(entry.intersectionRect.bottom - entry.intersectionRect.top, 10);
             }
           }
           else {
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/observe-text.html b/third_party/blink/web_tests/external/wpt/element-timing/observe-text.html
index a9a0e30a..16382eda 100644
--- a/third_party/blink/web_tests/external/wpt/element-timing/observe-text.html
+++ b/third_party/blink/web_tests/external/wpt/element-timing/observe-text.html
@@ -2,6 +2,14 @@
 <meta charset=utf-8>
 <title>Element Timing: observe text</title>
 <body>
+<style>
+body {
+  margin: 20px;
+}
+p {
+  font-size: 12px;
+}
+</style>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/element-timing-helpers.js"></script>
@@ -15,7 +23,14 @@
     const observer = new PerformanceObserver(
       t.step_func_done((entryList) => {
         assert_equals(entryList.getEntries().length, 1);
-        checkTextElement(entryList.getEntries()[0], 'my_text', 'text_id', beforeRender, paragraph);
+        const entry = entryList.getEntries()[0];
+        checkTextElement(entry, 'my_text', 'text_id', beforeRender, paragraph);
+        assert_equals(entry.intersectionRect.left, 20);
+        // Text box size will vary from device to device, so try lower bounding height by 12, width by 100.
+        assert_greater_than_equal(entry.intersectionRect.right, 120);
+
+        assert_equals(entry.intersectionRect.top, 20);
+        assert_greater_than_equal(entry.intersectionRect.bottom, 32);
       })
     );
     observer.observe({entryTypes: ['element']});
diff --git a/third_party/blink/web_tests/external/wpt/sms/constructor.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/sms/constructor.tentative.https.any.js
deleted file mode 100644
index a624934c..0000000
--- a/third_party/blink/web_tests/external/wpt/sms/constructor.tentative.https.any.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// META: title=SMS Receiver API: Constructor
-
-'use strict';
-
-test(function() {
-  let used = false;
-
-  new SMSReceiver({
-    get timeout() {
-      used = true;
-      return 60;
-    }
-  });
-
-  assert_true(used, 'constructor options "timeout" member was used');
-}, 'constructor uses timeout property');
-
-test(function() {
-  assert_throws(new TypeError(), function () {
-    new SMSReceiver({timeout: 0});
-    assert_unreached('Timeout 0 should reject');
-  });
-}, 'constructor throws with invalid timeout (0)');
-
-test(function() {
-  assert_throws(new TypeError(), function () {
-    new SMSReceiver({timeout: null});
-    assert_unreached('Timeout of null should reject');
-  });
-}, 'constructor throws with invalid timeout (null)');
-
-test(function() {
-  assert_throws(new TypeError(), function () {
-    new SMSReceiver({timeout: -1});
-    assert_unreached('Timeout negative numbers should reject');
-  });
-}, 'constructor throws with invalid timeout (-1)');
-
-test(function() {
-  assert_throws(new TypeError(), function () {
-    new SMSReceiver({timeout: NaN});
-    assert_unreached('Timeout of NaN should reject');
-  });
-}, 'constructor throws with invalid timeout (NaN)');
-
-test(function() {
-  new SMSReceiver();
-}, 'constructor uses a default value for the timeout when none is passed');
-
-test(function() {
-  new SMSReceiver({timeout: undefined});
-}, 'constructor uses a default value for the timeout');
diff --git a/third_party/blink/web_tests/external/wpt/sms/idlharness.https.any.js b/third_party/blink/web_tests/external/wpt/sms/idlharness.https.any.js
index c030a50..0c31744 100644
--- a/third_party/blink/web_tests/external/wpt/sms/idlharness.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/sms/idlharness.https.any.js
@@ -19,12 +19,12 @@
   idl_array.add_dependency_idls(dom);
   idl_array.add_dependency_idls(html);
 
-  self.receiver = new SMSReceiver({timeout: 60});
-
   idl_array.add_objects({
-    SmsReceiver: ['receiver'],
+    SmsReceiver: ['navigator.sms'],
   });
 
+  idl_array.add_objects({ Navigator: ['navigator'] })
+
   idl_array.test();
 }, 'Test IDL implementation of the SMS Receiver API');
 
diff --git a/third_party/blink/web_tests/external/wpt/sms/interceptor.https.html b/third_party/blink/web_tests/external/wpt/sms/interceptor.https.html
index 417120a1..4a6772f 100644
--- a/third_party/blink/web_tests/external/wpt/sms/interceptor.https.html
+++ b/third_party/blink/web_tests/external/wpt/sms/interceptor.https.html
@@ -15,7 +15,7 @@
   await expect(getNextMessage).andReturn((timeout) => {
     // mock behavior
   })
- 3) Call new SMSReceiver().start();
+ 3) Call navigator.sms.receive()
  4) Verify results
 
  The mocking API is browser agnostic and is designed such that other engines
@@ -25,7 +25,7 @@
  per engine:
 
  - function getNextMessage(): the main/only function that can be mocked.
- - function expect(): the main/only function that enables us to mock it.
+ - function expect(): the main/only function that enables us to mock it
  - enum State {kSuccess, kTimeout}: allows you to mock success/failures.
 
   -->
@@ -43,37 +43,140 @@
       });
   });
 
-  let receiver = new SMSReceiver();
+  let sms = await navigator.sms.receive();
 
-  let watcher = new EventWatcher(t, receiver, ["change"]);
-
-  await receiver.start();
-
-  // Waits for the first event.
-  await watcher.wait_for("change");
-
-  assert_equals(receiver.sms.content, "hello");
+  assert_equals(sms.content, "hello");
 }, 'Basic usage');
 
 promise_test(async t => {
   await expect(getNextMessage).andReturn((timeout) => {
       return Promise.resolve({
         sms: {
-          content: "",
+          content: "hello1",
+          status: Status.kSuccess,
+        }
+      });
+  });
+  await expect(getNextMessage).andReturn((timeout) => {
+      return Promise.resolve({
+        sms: {
+          content: "hello2",
+          status: Status.kSuccess,
+        }
+      });
+  });
+
+  let sms1 = navigator.sms.receive();
+  let sms2 = navigator.sms.receive();
+
+  let msg2 = await sms2;
+  let msg1 = await sms1;
+
+  assert_equals(msg1.content, "hello1");
+  assert_equals(msg2.content, "hello2");
+}, 'Handle multiple requests in different order.');
+
+promise_test(async t => {
+  await expect(getNextMessage).andReturn((timeout) => {
+      return Promise.resolve({
+        sms: {
+          status: Status.kTimeout
+        }
+      });
+  });
+  await expect(getNextMessage).andReturn((timeout) => {
+      return Promise.resolve({
+        sms: {
+          content: "success",
+          status: Status.kSuccess
+        }
+      });
+  });
+
+  let timeout_sms = navigator.sms.receive();
+  let successful_sms = navigator.sms.receive();
+
+  let successful_msg = await successful_sms;
+  assert_equals(successful_msg.content, "success");
+
+  try {
+    await timeout_sms;
+    assert_unreached('Expected TimeoutError to be thrown.');
+  } catch (error) {
+    assert_equals(error.name, "TimeoutError");
+    assert_equals(error.message, "SMSReceiver timed out.");
+  }
+}, 'Handle multiple requests with success and error.');
+
+promise_test(async t => {
+  await expect(getNextMessage).andReturn((timeout) => {
+      return Promise.resolve({
+        sms: {
           status: Status.kTimeout,
         }
       });
   });
 
-  let receiver = new SMSReceiver();
-
-  let watcher = new EventWatcher(t, receiver, ["timeout"]);
-
-  await receiver.start();
-
-  // Waits for the first event.
-  await watcher.wait_for("timeout");
+  try {
+    await navigator.sms.receive();
+    assert_unreached('Expected TimeoutError to be thrown.');
+  } catch (error) {
+    assert_equals(error.name, "TimeoutError");
+    assert_equals(error.message, "SMSReceiver timed out.");
+  }
 }, 'Deal with timeouts');
 
+promise_test(async t => {
+  try {
+    await navigator.sms.receive({timeout: 0});
+    assert_unreached('Expected NotSupportedError to be thrown.');
+  } catch (error) {
+    assert_equals(error.name, "NotSupportedError");
+    assert_equals(error.message, "Invalid timeout.");
+  }
+}, 'Should throw error with invalid timeout (0)');
 
-</script>
\ No newline at end of file
+promise_test(async t => {
+  try {
+    await navigator.sms.receive({timeout: null});
+    assert_unreached('Expected NotSupportedError to be thrown.');
+  } catch (error) {
+    assert_equals(error.name, "NotSupportedError");
+    assert_equals(error.message, "Invalid timeout.");
+  }
+}, 'Should throw error with invalid timeout (null)');
+
+promise_test(async t => {
+  try {
+    await navigator.sms.receive({timeout: -1});
+    assert_unreached('Expected NotSupportedError to be thrown.');
+  } catch (error) {
+    assert_equals(error.name, "NotSupportedError");
+    assert_equals(error.message, "Invalid timeout.");
+  }
+}, 'Should throw error with invalid timeout (-1)');
+
+promise_test(async t => {
+  try {
+    await navigator.sms.receive({timeout: NaN});
+    assert_unreached('Expected NotSupportedError to be thrown.');
+  } catch (error) {
+    assert_equals(error.name, "NotSupportedError");
+    assert_equals(error.message, "Invalid timeout.");
+  }
+}, 'Should throw error with invalid timeout (NaN)');
+
+promise_test(async t => {
+  await expect(getNextMessage).andReturn((timeout) => {
+      return Promise.resolve({
+        sms: {
+          content: "hello",
+          status: Status.kSuccess,
+        }
+      });
+  });
+
+  let sms = await navigator.sms.receive({timeout: undefined});
+  assert_equals(sms.content, "hello");
+}, 'Should use default value for timeout (undefined)');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/sms/resources/iframe.html b/third_party/blink/web_tests/external/wpt/sms/resources/iframe.html
index 44410e8..9a00e84 100644
--- a/third_party/blink/web_tests/external/wpt/sms/resources/iframe.html
+++ b/third_party/blink/web_tests/external/wpt/sms/resources/iframe.html
@@ -1,7 +1,7 @@
 <script>
 'use strict';
 
-new SMSReceiver().start().catch(error => {
+navigator.sms.receive().catch(error => {
   window.parent.postMessage({errorType: error.name}, '*');
 });
 
diff --git a/third_party/blink/web_tests/external/wpt/sms/sms_provider.js b/third_party/blink/web_tests/external/wpt/sms/sms_provider.js
index dd3af9b..a475941 100644
--- a/third_party/blink/web_tests/external/wpt/sms/sms_provider.js
+++ b/third_party/blink/web_tests/external/wpt/sms/sms_provider.js
@@ -20,38 +20,34 @@
 })();
 
 class SmsProvider {
+  constructor() {
+    this.returnValues = {}
+  }
+
   getNextMessage(timeout) {
-    return this.handler.getNextMessage(timeout);
+    let call = this.returnValues.getNextMessage.shift();
+    if (!call) {
+      throw new Error("Unexpected call.");
+    }
+    return call(timeout);
   }
-  setHandler(handler) {
-    this.handler = handler;
+
+  pushReturnValues(callName, returnValues) {
+    this.returnValues[callName] = this.returnValues[callName] || [];
+    this.returnValues[callName].push(returnValues);
     return this;
   }
-  setBinding(binding) {
-    this.binding = binding;
-    return this;
-  }
-  close() {
-    this.binding.close();
-  }
 }
 
 function getNextMessage(timeout, callback) {
   throw new Error("expected to be overriden by tests");
 }
 
-async function close() {
-  let provider = await interceptor;
-  provider.close();
-}
-
 function expect(call) {
   return {
     async andReturn(callback) {
-      let handler = {};
-      handler[call.name] = callback;
       let provider = await interceptor;
-      provider.setHandler(handler);
+      provider.pushReturnValues(call.name, callback);
     }
   }
 }
@@ -61,7 +57,8 @@
 function intercept() {
   let provider = new SmsProvider();
 
-  let interceptor = new MojoInterfaceInterceptor(blink.mojom.SmsManager.$interfaceName);
+  let interceptor = new MojoInterfaceInterceptor(
+      blink.mojom.SmsManager.$interfaceName);
   interceptor.oninterfacerequest = (e) => {
     let impl = new blink.mojom.SmsManager(provider);
     impl.bindHandle(e.handle);
diff --git a/third_party/blink/web_tests/external/wpt/sms/sms_receiver.idl b/third_party/blink/web_tests/external/wpt/sms/sms_receiver.idl
index bc6fb1d..b71b6a3 100644
--- a/third_party/blink/web_tests/external/wpt/sms/sms_receiver.idl
+++ b/third_party/blink/web_tests/external/wpt/sms/sms_receiver.idl
@@ -1,3 +1,10 @@
+[SecureContext]
+interface mixin NavigatorSMS {
+  readonly attribute SMSReceiver sms;
+};
+
+Navigator includes NavigatorSMS;
+
 [
   SecureContext,
   Exposed=(Window,DedicatedWorker)]
@@ -11,10 +18,7 @@
 
 [
   SecureContext,
-  Exposed=(Window,DedicatedWorker),
-  Constructor(optional SMSReceiverOptions options)
-] interface SMSReceiver : EventTarget {
-  readonly attribute SMS sms;
-  attribute EventHandler onchange;
-  Promise<void> start();
+  Exposed=Window
+] interface SMSReceiver {
+  Promise<SMS> receive(optional SMSReceiverOptions options);
 };
diff --git a/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt b/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt
index a0aaff4..42879893 100644
--- a/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt
@@ -17,16 +17,18 @@
 Requiring audits
 Runner setup
 Connecting to browser
-Getting browser version
 Resetting state with about:blank
+Getting browser version
 Benchmarking machine
 Initializing…
+Resetting state with about:blank
+Setting up network for the pass trace
+Cleaning browser cache
 Running beforePass methods
 Gathering setup: CSSUsage
 Gathering setup: ViewportDimensions
 Gathering setup: RuntimeExceptions
-Gathering setup: ChromeConsoleMessages
-Gathering setup: Accessibility
+Gathering setup: ConsoleMessages
 Gathering setup: AnchorElements
 Gathering setup: ImageElements
 Gathering setup: LinkElements
@@ -35,7 +37,6 @@
 Gathering setup: AppCacheManifest
 Gathering setup: Doctype
 Gathering setup: DOMStats
-Gathering setup: JSLibraries
 Gathering setup: OptimizedImages
 Gathering setup: PasswordInputsWithPreventedPaste
 Gathering setup: ResponseCompression
@@ -44,14 +45,15 @@
 Gathering setup: EmbeddedContent
 Gathering setup: RobotsTxt
 Gathering setup: TapTargets
-Loading page & waiting for onload
+Gathering setup: Accessibility
+Beginning devtoolsLog and trace
 Getting browser version
+Loading page & waiting for onload
 Running pass methods
 Gathering in-page: CSSUsage
 Gathering in-page: ViewportDimensions
 Gathering in-page: RuntimeExceptions
-Gathering in-page: ChromeConsoleMessages
-Gathering in-page: Accessibility
+Gathering in-page: ConsoleMessages
 Gathering in-page: AnchorElements
 Gathering in-page: ImageElements
 Gathering in-page: LinkElements
@@ -60,7 +62,6 @@
 Gathering in-page: AppCacheManifest
 Gathering in-page: Doctype
 Gathering in-page: DOMStats
-Gathering in-page: JSLibraries
 Gathering in-page: OptimizedImages
 Gathering in-page: PasswordInputsWithPreventedPaste
 Gathering in-page: ResponseCompression
@@ -69,14 +70,14 @@
 Gathering in-page: EmbeddedContent
 Gathering in-page: RobotsTxt
 Gathering in-page: TapTargets
+Gathering in-page: Accessibility
 Gathering trace
 Gathering devtoolsLog & network records
 Running afterPass methods
 Gathering: CSSUsage
 Gathering: ViewportDimensions
 Gathering: RuntimeExceptions
-Gathering: ChromeConsoleMessages
-Gathering: Accessibility
+Gathering: ConsoleMessages
 Gathering: AnchorElements
 Gathering: ImageElements
 Gathering: LinkElements
@@ -85,7 +86,6 @@
 Gathering: AppCacheManifest
 Gathering: Doctype
 Gathering: DOMStats
-Gathering: JSLibraries
 Gathering: OptimizedImages
 Gathering: PasswordInputsWithPreventedPaste
 Gathering: ResponseCompression
@@ -94,11 +94,14 @@
 Gathering: EmbeddedContent
 Gathering: RobotsTxt
 Gathering: TapTargets
+Gathering: Accessibility
 Resetting state with about:blank
+Setting up network for the pass trace
 Running beforePass methods
 Gathering setup: ServiceWorker
 Gathering setup: Offline
 Gathering setup: StartUrl
+Beginning devtoolsLog and trace
 Loading page & waiting for onload
 Running pass methods
 Gathering in-page: ServiceWorker
@@ -110,9 +113,11 @@
 Gathering: Offline
 Gathering: StartUrl
 Resetting state with about:blank
+Setting up network for the pass trace
 Running beforePass methods
 Gathering setup: HTTPRedirect
 Gathering setup: HTMLWithoutJavaScript
+Beginning devtoolsLog and trace
 Loading page & waiting for onload
 Running pass methods
 Gathering in-page: HTTPRedirect
@@ -143,10 +148,9 @@
 Auditing: Screenshot Thumbnails
 Computing artifact: Speedline
 Auditing: Final Screenshot
-Computing artifact: Screenshots
 Auditing: Estimated Input Latency
 Computing artifact: EstimatedInputLatency
-Auditing: Max Potential FID
+Auditing: Max Potential First Input Delay
 Computing artifact: MaxPotentialFID
 Auditing: No browser errors logged to the console
 Auditing: Server response times are low (TTFB)
@@ -161,6 +165,7 @@
 Auditing: Avoid multiple page redirects
 Auditing: Web app manifest meets the installability requirements
 Computing artifact: ManifestValues
+Auditing: Provides a valid `apple-touch-icon`
 Auditing: Configured for a custom splash screen
 Auditing: Sets an address-bar theme color
 Auditing: Content is sized correctly for the viewport
@@ -183,6 +188,9 @@
 Auditing: Tasks
 Auditing: Metrics
 Auditing: start_url responds with a 200 when offline
+Auditing: Performance budget
+Computing artifact: ResourceSummary
+Auditing: Keep request counts low and transfer sizes small
 Auditing: Site works cross-browser
 Auditing: Page transitions don't feel like they block on the network
 Auditing: Each page has a URL
@@ -276,6 +284,7 @@
 
 accesskeys: notApplicable
 appcache-manifest: pass
+apple-touch-icon: fail
 aria-allowed-attr: notApplicable
 aria-required-attr: notApplicable
 aria-required-children: notApplicable
@@ -299,13 +308,13 @@
 dlitem: notApplicable
 doctype: fail
 document-title: fail
-dom-size: numeric
+dom-size: ERROR Required DOMStats gatherer encountered an error: Cannot read property 'localName' of null
 duplicate-id: notApplicable
 efficient-animated-content: flaky
 errors-in-console: pass
 estimated-input-latency: flaky
 external-anchors-use-rel-noopener: pass
-final-screenshot: ERROR Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse. (NO_SCREENSHOTS)
+final-screenshot: ERROR Something went wrong with recording the trace over your page load. Please run Lighthouse again. (NO_FCP)
 first-contentful-paint: flaky
 first-cpu-idle: flaky
 first-meaningful-paint: flaky
@@ -356,6 +365,7 @@
 offscreen-content-hidden: manual
 offscreen-images: flaky
 password-inputs-can-be-pasted-into: pass
+performance-budget: notApplicable
 plugins: pass
 pwa-cross-browser: manual
 pwa-each-page-has-url: manual
@@ -363,6 +373,7 @@
 redirects: flaky
 redirects-http: fail
 render-blocking-resources: flaky
+resource-summary: informative
 robots-txt: notApplicable
 screenshot-thumbnails: flaky
 service-worker: fail
@@ -398,5 +409,5 @@
 without-javascript: fail
 works-offline: fail
 
-# of .lh-audit divs: 111
+# of .lh-audit divs: 114
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential-errors.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential-errors.js
index 07c37dfc..40ffd7b 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential-errors.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential-errors.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startURL(
           "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
           "Check that the WebAuthn command addCredential validates parameters");
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential.js
index b83497b..83d98b58 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-credential.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startURL(
           "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
           "Check that the WebAuthn command addCredential works");
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator-errors.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator-errors.js
index aa4509ef..182bf3e 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator-errors.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator-errors.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startBlank(
           "Check that the WebAuthn addVirtualAuthenticator command validates parameters");
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator.js
index 8d164d75..29469902 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-add-virtual-authenticator.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startURL(
           "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
           "Check that the WebAuthn command addVirtualAuthenticator works");
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials-errors.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials-errors.js
index eea7b99..58a0385 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials-errors.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials-errors.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startBlank(
           "Check that the WebAuthn command clearCredentials validates parameters");
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials.js
index 7812884a..d98b5c1 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-clear-credentials.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startURL(
           "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
           "Check that the WebAuthn command clearCredentials works");
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-enables-virtual-environment.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-enables-virtual-environment.js
index b8c1a16..483985d 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-enables-virtual-environment.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-enables-virtual-environment.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startURL(
           "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
           "Check that calling WebAuthn.enable starts the WebAuthn virtual " +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials-errors.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials-errors.js
index 896ad37..95070dc6 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials-errors.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials-errors.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startBlank(
           "Check that the WebAuthn command getCredentials validates parameters");
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials.js
index 0d8d8bf..76d7655c8 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-get-credentials.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startURL(
           "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
           "Check that the WebAuthn command getCredentials works");
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-presence-simulation-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-presence-simulation-expected.txt
new file mode 100644
index 0000000..3e46d0d
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-presence-simulation-expected.txt
@@ -0,0 +1,6 @@
+Check that the WebAuthn command addVirtualAuthenticator simulates user presence
+OK
+[
+    [0] : ble
+]
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-presence-simulation.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-presence-simulation.js
new file mode 100644
index 0000000..c1122d4
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-presence-simulation.js
@@ -0,0 +1,38 @@
+(async function(testRunner) {
+  const {page, session, dp} =
+      await testRunner.startURL(
+          "https://devtools.test:8443/inspector-protocol/webauthn/resources/webauthn-test.https.html",
+          "Check that the WebAuthn command addVirtualAuthenticator simulates user presence");
+
+  // Create an authenticator that will not simulate user presence.
+  await dp.WebAuthn.enable();
+  await dp.WebAuthn.addVirtualAuthenticator({
+    options: {
+      protocol: "ctap2",
+      transport: "nfc",
+      hasResidentKey: false,
+      hasUserVerification: false,
+      automaticPresenceSimulation: false,
+    },
+  });
+
+  // Registering a credential should wait until an authenticator that verifies
+  // user presence is plugged.
+  session.evaluateAsync("registerCredential()").then(result => {
+    testRunner.log(result.status);
+    testRunner.log(result.credential.transports);
+    testRunner.completeTest();
+  });
+
+  // Plug in an authenticator that does simulate user presence. The credential
+  // creation promise should resolve with transport == ble then.
+  await dp.WebAuthn.addVirtualAuthenticator({
+    options: {
+      protocol: "u2f",
+      transport: "ble",
+      hasResidentKey: false,
+      hasUserVerification: false,
+      automaticPresenceSimulation: true,
+    },
+  });
+})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-remove-virtual-authenticator.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-remove-virtual-authenticator.js
index 8cf95fd..f451c19 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-remove-virtual-authenticator.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webauthn/webauthn-remove-virtual-authenticator.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} =
+  const {page, session, dp} =
       await testRunner.startBlank(
           "Check that the WebAuthn removeVirtualAuthenticator command works");
 
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index b7060e3..353c3ee7 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1126,13 +1126,6 @@
 [Worker]     attribute @@toStringTag
 [Worker]     getter content
 [Worker]     method constructor
-[Worker] interface SMSReceiver : EventTarget
-[Worker]     attribute @@toStringTag
-[Worker]     getter onchange
-[Worker]     getter sms
-[Worker]     method constructor
-[Worker]     method start
-[Worker]     setter onchange
 [Worker] interface SecurityPolicyViolationEvent : Event
 [Worker]     attribute @@toStringTag
 [Worker]     getter blockedURI
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 6e3f19e..4f43ebf 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -4936,6 +4936,7 @@
     getter scheduling
     getter serial
     getter serviceWorker
+    getter sms
     getter storage
     getter usb
     getter userActivation
@@ -6117,13 +6118,10 @@
     attribute @@toStringTag
     getter content
     method constructor
-interface SMSReceiver : EventTarget
+interface SMSReceiver
     attribute @@toStringTag
-    getter onchange
-    getter sms
     method constructor
-    method start
-    setter onchange
+    method receive
 interface SVGAElement : SVGGraphicsElement
     attribute @@toStringTag
     getter href
diff --git a/tools/android/audio_focus_grabber/java/AndroidManifest.xml b/tools/android/audio_focus_grabber/java/AndroidManifest.xml
index 677bc976..8255ea4 100644
--- a/tools/android/audio_focus_grabber/java/AndroidManifest.xml
+++ b/tools/android/audio_focus_grabber/java/AndroidManifest.xml
@@ -8,8 +8,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.tools.audio_focus_grabber" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
-
     <application
         android:label="@string/app_name" >
 
diff --git a/tools/android/customtabs_benchmark/BUILD.gn b/tools/android/customtabs_benchmark/BUILD.gn
index eaf2db7..27cf5e0 100644
--- a/tools/android/customtabs_benchmark/BUILD.gn
+++ b/tools/android/customtabs_benchmark/BUILD.gn
@@ -15,6 +15,8 @@
     "java/src/org/chromium/customtabs/test/WebViewActivity.java",
   ]
   android_manifest = "java/AndroidManifest.xml"
+  min_sdk_version = 21
+  target_sdk_version = 22
   apk_name = "CustomTabsBenchmark"
   deps = [
     ":customtabs_benchmark_apk_resources",
diff --git a/tools/android/customtabs_benchmark/java/AndroidManifest.xml b/tools/android/customtabs_benchmark/java/AndroidManifest.xml
index f0db60e..72e8087 100644
--- a/tools/android/customtabs_benchmark/java/AndroidManifest.xml
+++ b/tools/android/customtabs_benchmark/java/AndroidManifest.xml
@@ -7,7 +7,6 @@
     package="org.chromium.customtabs.test"
     android:versionCode="1"
     android:versionName="1.0">
-    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="22" />
 
     <uses-permission android:name="android.permission.INTERNET" />
 
diff --git a/tools/android/kerberos/SpnegoAuthenticator/AndroidManifest.xml b/tools/android/kerberos/SpnegoAuthenticator/AndroidManifest.xml
index bb48308..ec14dc35 100644
--- a/tools/android/kerberos/SpnegoAuthenticator/AndroidManifest.xml
+++ b/tools/android/kerberos/SpnegoAuthenticator/AndroidManifest.xml
@@ -7,8 +7,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.chromium.tools.spnegoauthenticator" >
 
-    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="23" />
-
     <!--
       Deprecated permissions. Normal protection level, autogranted. Needed
       for API level 22 and before.
diff --git a/tools/android/kerberos/SpnegoAuthenticator/BUILD.gn b/tools/android/kerberos/SpnegoAuthenticator/BUILD.gn
index ab93ad6..c30702c1 100644
--- a/tools/android/kerberos/SpnegoAuthenticator/BUILD.gn
+++ b/tools/android/kerberos/SpnegoAuthenticator/BUILD.gn
@@ -8,6 +8,7 @@
 android_apk("spnego_authenticator_apk") {
   testonly = true
   android_manifest = "AndroidManifest.xml"
+  min_sdk_version = 21
   apk_name = "SpnegoAuthenticator"
 
   deps = [
diff --git a/tools/android/memconsumer/BUILD.gn b/tools/android/memconsumer/BUILD.gn
index da69770..73be9a1 100644
--- a/tools/android/memconsumer/BUILD.gn
+++ b/tools/android/memconsumer/BUILD.gn
@@ -12,6 +12,8 @@
 android_apk("memconsumer_apk") {
   apk_name = "MemConsumer"
   android_manifest = "java/AndroidManifest.xml"
+  min_sdk_version = 16
+  target_sdk_version = 16
   java_files = [
     "java/src/org/chromium/memconsumer/MemConsumer.java",
     "java/src/org/chromium/memconsumer/ResidentService.java",
diff --git a/tools/android/memconsumer/java/AndroidManifest.xml b/tools/android/memconsumer/java/AndroidManifest.xml
index f886d7b..c7f12e42 100644
--- a/tools/android/memconsumer/java/AndroidManifest.xml
+++ b/tools/android/memconsumer/java/AndroidManifest.xml
@@ -9,8 +9,6 @@
     package="org.chromium.memconsumer" android:versionCode="1"
     android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="16"/>
-
     <application
             android:label="MemConsumer">
         <activity android:name=".MemConsumer" android:icon="@drawable/icon" android:launchMode="singleTop">
diff --git a/tools/android/push_apps_to_background/AndroidManifest.xml b/tools/android/push_apps_to_background/AndroidManifest.xml
index 45a0cda9..64c3ebcd 100644
--- a/tools/android/push_apps_to_background/AndroidManifest.xml
+++ b/tools/android/push_apps_to_background/AndroidManifest.xml
@@ -10,8 +10,6 @@
     android:versionCode="1"
     android:versionName="1.0" >
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
-
     <application
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 36c0fb74..ff4cbd1 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -280,6 +280,7 @@
       'linux-blink-heap-verification': 'release_bot_enable_blink_heap_verification_dcheck_always_on',
       'linux-chromium-tests-staging-builder': 'release_bot',
       'linux-code-coverage': 'clang_code_coverage',
+      'linux-password-manager-captured-sites-rel': 'release_bot',
       'Mac deterministic': 'release_bot_mac_strip_minimal_symbols',
       'Mac deterministic (dbg)': 'debug_bot',
       'mac-autofill-captured-sites-rel': 'release_bot',
@@ -297,6 +298,7 @@
       'Win 10 Fast Ring': 'release_trybot',
       'win-annotator-rel': 'release_bot',
       'win-autofill-captured-sites-rel': 'release_bot',
+      'win-password-manager-captured-sites-rel': 'release_bot',
       'win-pixel-builder-rel': 'release_bot',
       'win32-arm64-rel': 'win32_arm64_release_bot',
     },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2d3ac57..e4d2405 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -33846,6 +33846,7 @@
   <int value="-1386966873" label="disable-mac-views-native-app-windows"/>
   <int value="-1385221197"
       label="AllowSignedHTTPExchangeCertsWithoutExtension:enabled"/>
+  <int value="-1384426209" label="SharingDeviceRegistration:disabled"/>
   <int value="-1383597259" label="SyncUserConsentSeparateType:disabled"/>
   <int value="-1383145700"
       label="AutofillDoNotMigrateUnsupportedLocalCards:enabled"/>
@@ -34269,6 +34270,7 @@
   <int value="-787426248" label="ChromeHomeSurvey:disabled"/>
   <int value="-780798969" label="disable-single-click-autofill"/>
   <int value="-778126349" label="DownloadsLocationChange:enabled"/>
+  <int value="-777126951" label="FontSrcLocalMatching:enabled"/>
   <int value="-776686417" label="SiteExplorationUi:disabled"/>
   <int value="-775321548" label="UseNewDoodleApi:disabled"/>
   <int value="-773238824" label="AutoplayWhitelistSettings:disabled"/>
@@ -34626,6 +34628,7 @@
   <int value="-234966279" label="PointerEvent:disabled"/>
   <int value="-234687894"
       label="NonValidatingReloadOnRefreshContentV2:disabled"/>
+  <int value="-234231190" label="SharingDeviceRegistration:enabled"/>
   <int value="-231922000" label="enable-renderer-mojo-channel"/>
   <int value="-231426350" label="AutofillEnableToolbarStatusChip:enabled"/>
   <int value="-230824955" label="NTPMostLikelyFaviconsFromServer:enabled"/>
@@ -36025,6 +36028,7 @@
   <int value="1866963423" label="SyncPseudoUSSThemes:enabled"/>
   <int value="1867085340" label="brotli-encoding:enabled"/>
   <int value="1870973833" label="AssistantEnableStereoAudioInput:enabled"/>
+  <int value="1871938175" label="FontSrcLocalMatching:disabled"/>
   <int value="1872185826" label="LocationHardReload:enabled"/>
   <int value="1874195462" label="ChromeHomeMenuItemsExpandSheet:disabled"/>
   <int value="1874604540" label="UseSuggestionsEvenIfFew:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 55758cd..ca0ee6b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -15441,7 +15441,7 @@
 </histogram>
 
 <histogram base="true" name="Browser.Tabs.TabSwitchResult"
-    units="TabSwitchResult" expires_after="2019-08-31">
+    enum="TabSwitchResult" expires_after="2019-08-31">
 <!-- Name completed by histogram_suffixes name="TabSwitchingType" -->
 
   <owner>fdoray@chromium.org</owner>
@@ -115981,6 +115981,9 @@
 
 <histogram name="ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time"
     units="ms">
+  <obsolete>
+    No longer recorded since NetS13nSW shipped on Dec 2018.
+  </obsolete>
   <owner>horo@chromium.org</owner>
   <summary>
     The time taken for the browser to find and possibly start an active worker
@@ -116015,9 +116018,6 @@
     active worker to dispatch a FetchEvent for a main frame resource request.
     See details at ServiceWorker.ActivatedWorkerPreparationForMainFrame.Time.
     The suffixed histograms for .Time record the time required for each type.
-
-    This is recorded regardless of whether NetS13nSW (https://crbug.com/715640)
-    is enabled or disabled.
   </summary>
 </histogram>
 
@@ -116257,9 +116257,6 @@
     recorded when response has no body. Note that this is recorded on every
     write operation, and can there can be multiple write operations for the same
     response if it is large enough.
-
-    This is recorded regardless of whether NetS13nSW (https://crbug.com/715640)
-    is enabled or disabled.
   </summary>
 </histogram>
 
@@ -116396,9 +116393,6 @@
   <summary>
     The result of dispatching a fetch event to a Service Worker for a main
     resource request (i.e., a request for a navigation or a shared worker).
-
-    This is recorded regardless of whether NetS13nSW (https://crbug.com/715640)
-    is enabled or disabled.
   </summary>
 </histogram>
 
@@ -116408,9 +116402,6 @@
   <summary>
     The result of dispatching a fetch event to a Service Worker for a
     subresource request (i.e., not a navigation or a shared worker request).
-
-    This is recorded regardless of whether NetS13nSW (https://crbug.com/715640)
-    is enabled or disabled.
   </summary>
 </histogram>
 
@@ -116938,9 +116929,6 @@
     The size of Service-Worker-Navigation-Preload header when the navigation
     preload request is to be sent. The default value of the header is
     &quot;true&quot;, so the default size is 4.
-
-    This is recorded regardless of whether NetS13nSW (https://crbug.com/715640)
-    is enabled or disabled.
   </summary>
 </histogram>
 
@@ -117002,6 +116990,9 @@
 </histogram>
 
 <histogram name="ServiceWorker.NavPreload.ConcurrentTime" units="ms">
+  <obsolete>
+    No longer recorded since NetS13nSW shipped on Dec 2018.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <summary>
     The duration of time when both (1) a service worker is being found and
@@ -117021,6 +117012,9 @@
 
 <histogram name="ServiceWorker.NavPreload.FinishedFirst"
     enum="BooleanNavPreloadFinishedFirst">
+  <obsolete>
+    No longer recorded since NetS13nSW shipped on Dec 2018.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <summary>
     Whether the navigation preload response arrived before the activated and
@@ -117035,6 +117029,9 @@
 </histogram>
 
 <histogram name="ServiceWorker.NavPreload.ResponseTime" units="ms">
+  <obsolete>
+    No longer recorded since NetS13nSW shipped on Dec 2018.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <summary>
     The time taken for the navigation preload response to start, i.e., when
@@ -117050,6 +117047,9 @@
 
 <histogram name="ServiceWorker.NavPreload.WorkerPreparationType"
     enum="ServiceWorkerPreparationType">
+  <obsolete>
+    No longer recorded since NetS13nSW shipped on Dec 2018.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <summary>
     The type of preparation needed for the browser to find and possibly start an
@@ -117290,6 +117290,9 @@
 
 <histogram name="ServiceWorker.StartNewWorker.Status"
     enum="ServiceWorkerStatusCode" expires_after="M77">
+  <obsolete>
+    Removed June 2019.
+  </obsolete>
   <owner>falken@chromium.org</owner>
   <summary>
     The result of trying to start a Service Worker that has not yet installed.
@@ -127397,7 +127400,7 @@
 </histogram>
 
 <histogram name="SubresourceRedirect.CompressionAttempt.Status"
-    enum="HttpResponseCode" expires_after="M77">
+    enum="HttpResponseCode" expires_after="M80">
   <owner>harrisonsean@chromium.org</owner>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
@@ -127409,8 +127412,19 @@
   </summary>
 </histogram>
 
+<histogram name="SubresourceRedirect.DidCompress.BytesSaved" units="bytes"
+    expires_after="M80">
+  <owner>harrisonsean@chromium.org</owner>
+  <owner>robertogden@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The bytes of data saved from the SubresourceRedirect. Recorded every time a
+    SubresourceRedirect returns with a 200 HTTP response code.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceRedirect.DidCompress.CompressionPercent" units="%"
-    expires_after="M77">
+    expires_after="M80">
   <owner>harrisonsean@chromium.org</owner>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
@@ -161866,6 +161880,9 @@
       label="The time from the input timestamp on a tab switch, until the
              frame is presented on the screen when there is no saved frame in
              the cache."/>
+  <suffix name="NoSavedFrames_Loaded"
+      label="Same as NoSavedFrames with the destination tab being loaded
+             (frozen or not frozen)"/>
   <suffix name="NoSavedFrames_Loaded_Frozen"
       label="Same as NoSavedFrames with the destination tab being loaded and
              frozen."/>
@@ -161877,6 +161894,7 @@
   <suffix name="WithSavedFrames"
       label="There is a saved frame in the cache when the tab switch starts."/>
   <affected-histogram name="Browser.Tabs.TabSwitchResult"/>
+  <affected-histogram name="Browser.Tabs.TotalIncompleteSwitchDuration"/>
   <affected-histogram name="Browser.Tabs.TotalSwitchDuration"/>
 </histogram_suffixes>
 
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index ca07d5b..31eb507 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -2729,6 +2729,15 @@
       a given scroll gesture event sequence. If no swap was induced by the
       event, no recording is made.
     </summary>
+    <aggregation>
+      <history>
+        <index fields="profile.country"/>
+        <index fields="profile.country,profile.system_ram"/>
+        <statistics>
+          <quantiles type="std-percentiles"/>
+        </statistics>
+      </history>
+    </aggregation>
   </metric>
 </event>
 
@@ -2796,6 +2805,15 @@
       the event, no recording is made. The first GSU of every scrolling sequence
       is excluded from this metric.
     </summary>
+    <aggregation>
+      <history>
+        <index fields="profile.country"/>
+        <index fields="profile.country,profile.system_ram"/>
+        <statistics>
+          <quantiles type="std-percentiles"/>
+        </statistics>
+      </history>
+    </aggregation>
   </metric>
 </event>
 
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn
index e1853f94..0818db84 100644
--- a/tools/perf/chrome_telemetry_build/BUILD.gn
+++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -50,7 +50,7 @@
   if (is_mac) {
     data_deps += [
       "//chrome:chrome_framework",
-      "//chrome:chrome_helper_app",
+      "//chrome:chrome_helper_app_default",
       "//third_party/breakpad:dump_syms",
       "//third_party/crashpad/crashpad/tools:crashpad_database_util",
     ]
diff --git a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
index c0d6dfd9..a24b02e 100644
--- a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
+++ b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
@@ -91,6 +91,8 @@
   def __init__(self, test, finder_options, story_set, possible_browser=None):
     super(AndroidSharedVrPageState, self).__init__(
         test, finder_options, story_set, possible_browser)
+    if self._finder_options.remove_system_vrcore:
+      self._RemoveSystemVrCore()
     if not self._finder_options.disable_vrcore_install:
       self._InstallVrCore()
     self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(),
@@ -99,6 +101,9 @@
     if not self._finder_options.disable_keyboard_install:
       self._InstallKeyboardApk()
 
+  def _RemoveSystemVrCore(self):
+    self.platform.RemoveSystemPackages(['com.google.vr.vrcore'])
+
   def _InstallVrCore(self):
     """Installs the VrCore APK."""
     self.platform.InstallApplication(
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
index f3ea4db..129b1140 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
@@ -63,6 +63,13 @@
              'to use whatever version is already installed on the device '
              'instead of installing whatever is in the test APKs directory.')
     parser.add_option(
+        '--remove-system-vrcore',
+        action='store_true',
+        default=False,
+        help='Removes the system version of VrCore if it is installed. This '
+             'is required if the system version is not already removed and '
+             '--disable-vrcore-install is not passed.')
+    parser.add_option(
         '--recording-wpr',
         action='store_true',
         default=False,
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 659b21d..cb5df3b3 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -117,10 +117,6 @@
     auto* gl = static_cast<InProcessContextProvider*>(context_provider());
     return gl->GetCopyTextureInternalFormat();
   }
-  std::unique_ptr<viz::OverlayCandidateValidator>
-  TakeOverlayCandidateValidator() override {
-    return nullptr;
-  }
   bool IsDisplayedAsOverlayPlane() const override { return false; }
   unsigned GetOverlayTextureId() const override { return 0; }
   gfx::BufferFormat GetOverlayBufferFormat() const override {
diff --git a/ui/ozone/platform/scenic/scenic_gpu_host.cc b/ui/ozone/platform/scenic/scenic_gpu_host.cc
index 25bbb30e..25ef0f9 100644
--- a/ui/ozone/platform/scenic/scenic_gpu_host.cc
+++ b/ui/ozone/platform/scenic/scenic_gpu_host.cc
@@ -57,16 +57,15 @@
 
 void ScenicGpuHost::AttachSurfaceToWindow(
     int32_t window_id,
-    mojo::ScopedHandle surface_view_holder_token_mojo) {
+    mojo::ScopedHandle export_token_mojo) {
   DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
   ScenicWindow* scenic_window = scenic_window_manager_->GetWindow(window_id);
   if (!scenic_window)
     return;
-  fuchsia::ui::views::ViewHolderToken surface_view_holder_token;
-  surface_view_holder_token.value = zx::eventpair(
-      mojo::UnwrapPlatformHandle(std::move(surface_view_holder_token_mojo))
-          .TakeHandle());
-  scenic_window->AttachSurfaceView(std::move(surface_view_holder_token));
+  fuchsia::ui::gfx::ExportToken export_token;
+  export_token.value = zx::eventpair(
+      mojo::UnwrapPlatformHandle(std::move(export_token_mojo)).TakeHandle());
+  scenic_window->AttachSurface(std::move(export_token));
 }
 
 void ScenicGpuHost::OnGpuProcessLaunched(
diff --git a/ui/ozone/platform/scenic/scenic_gpu_host.h b/ui/ozone/platform/scenic/scenic_gpu_host.h
index 14f2a1a..69d4148 100644
--- a/ui/ozone/platform/scenic/scenic_gpu_host.h
+++ b/ui/ozone/platform/scenic/scenic_gpu_host.h
@@ -37,9 +37,8 @@
   mojom::ScenicGpuHostPtr CreateHostProcessSelfBinding();
 
   // mojom::ScenicGpuHost:
-  void AttachSurfaceToWindow(
-      int32_t window_id,
-      mojo::ScopedHandle surface_view_holder_token_mojo) override;
+  void AttachSurfaceToWindow(int32_t window_id,
+                             mojo::ScopedHandle export_token_mojo) override;
 
   // GpuPlatformSupportHost:
   void OnGpuProcessLaunched(
diff --git a/ui/ozone/platform/scenic/scenic_surface.cc b/ui/ozone/platform/scenic/scenic_surface.cc
index 9f92823..73fd5b9 100644
--- a/ui/ozone/platform/scenic/scenic_surface.cc
+++ b/ui/ozone/platform/scenic/scenic_surface.cc
@@ -5,7 +5,6 @@
 #include "ui/ozone/platform/scenic/scenic_surface.h"
 
 #include <lib/ui/scenic/cpp/commands.h>
-#include <lib/ui/scenic/cpp/view_token_pair.h>
 #include <lib/zx/eventpair.h>
 
 #include "mojo/public/cpp/system/platform_handle.h"
@@ -19,6 +18,7 @@
     gfx::AcceleratedWidget window,
     scenic::SessionPtrAndListenerRequest sesion_and_listener_request)
     : scenic_session_(std::move(sesion_and_listener_request)),
+      parent_(&scenic_session_),
       shape_(&scenic_session_),
       material_(&scenic_session_),
       scenic_surface_factory_(scenic_surface_factory),
@@ -50,21 +50,15 @@
   material_.SetTexture(image);
 }
 
-mojo::ScopedHandle ScenicSurface::CreateView() {
+mojo::ScopedHandle ScenicSurface::CreateExportToken() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  // Scenic will associate the View and ViewHolder regardless of which it
-  // learns about first, so we don't need to synchronize View creation with
-  // attachment into the scene graph by the caller.
-  auto tokens = scenic::ViewTokenPair::New();
-  parent_ = std::make_unique<scenic::View>(
-      &scenic_session_, std::move(tokens.view_token), "chromium surface");
-  parent_->AddChild(shape_);
-
+  zx::eventpair export_token;
+  parent_.BindAsRequest(&export_token);
+  parent_.AddChild(shape_);
   scenic_session_.Present(
       /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
   return mojo::WrapPlatformHandle(
-      mojo::PlatformHandle(std::move(tokens.view_holder_token.value)));
+      mojo::PlatformHandle(std::move(export_token)));
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/scenic/scenic_surface.h b/ui/ozone/platform/scenic/scenic_surface.h
index 693ee49..475892b 100644
--- a/ui/ozone/platform/scenic/scenic_surface.h
+++ b/ui/ozone/platform/scenic/scenic_surface.h
@@ -41,9 +41,9 @@
   // Sets the texture of the surface to an image resource.
   void SetTextureToImage(const scenic::Image& image);
 
-  // Creates a View for this surface, and returns a ViewHolderToken handle
-  // that can be used to attach it into a scene graph.
-  mojo::ScopedHandle CreateView();
+  // Returns an export token used to associated this surface with a window in
+  // the browser process.
+  mojo::ScopedHandle CreateExportToken();
 
   void AssertBelongsToCurrentThread() {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -56,7 +56,7 @@
 
  private:
   scenic::Session scenic_session_;
-  std::unique_ptr<scenic::View> parent_;
+  scenic::ImportNode parent_;
   scenic::ShapeNode shape_;
   scenic::Material material_;
 
diff --git a/ui/ozone/platform/scenic/scenic_surface_factory.cc b/ui/ozone/platform/scenic/scenic_surface_factory.cc
index 6e892e3..af49373 100644
--- a/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -107,7 +107,7 @@
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&ScenicSurfaceFactory::AttachSurfaceToWindow,
                                 weak_ptr_factory_.GetWeakPtr(), window,
-                                surface->CreateView()));
+                                surface->CreateExportToken()));
   return surface;
 }
 
@@ -207,10 +207,10 @@
 
 void ScenicSurfaceFactory::AttachSurfaceToWindow(
     gfx::AcceleratedWidget window,
-    mojo::ScopedHandle surface_view_holder_token_mojo) {
+    mojo::ScopedHandle surface_export_token_mojo) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   gpu_host_->AttachSurfaceToWindow(window,
-                                   std::move(surface_view_holder_token_mojo));
+                                   std::move(surface_export_token_mojo));
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/scenic/scenic_surface_factory.h b/ui/ozone/platform/scenic/scenic_surface_factory.h
index fe8a193..9417f0d 100644
--- a/ui/ozone/platform/scenic/scenic_surface_factory.h
+++ b/ui/ozone/platform/scenic/scenic_surface_factory.h
@@ -78,7 +78,7 @@
 
   // Links a surface to its parent window in the host process.
   void AttachSurfaceToWindow(gfx::AcceleratedWidget window,
-                             mojo::ScopedHandle surface_view_holder_token_mojo);
+                             mojo::ScopedHandle surface_export_token_mojo);
 
   base::flat_map<gfx::AcceleratedWidget, ScenicSurface*> surface_map_
       GUARDED_BY(surface_lock_);
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc
index 10a6a01..9f3e5d1 100644
--- a/ui/ozone/platform/scenic/scenic_window.cc
+++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -58,14 +58,14 @@
   manager_->RemoveWindow(window_id_, this);
 }
 
-void ScenicWindow::AttachSurfaceView(
-    fuchsia::ui::views::ViewHolderToken token) {
-  scenic::ViewHolder surface_view_holder(&scenic_session_, std::move(token),
-                                         "chromium window surface");
+void ScenicWindow::AttachSurface(
+    fuchsia::ui::gfx::ExportToken surface_export_token) {
+  scenic::EntityNode export_node(&scenic_session_);
 
   render_node_.DetachChildren();
-  render_node_.Attach(surface_view_holder);
+  render_node_.AddChild(export_node);
 
+  export_node.Export(std::move(surface_export_token.value));
   scenic_session_.Present(
       /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
 }
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h
index b4f07cfd..9b2003e 100644
--- a/ui/ozone/platform/scenic/scenic_window.h
+++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -40,9 +40,7 @@
 
   scenic::Session* scenic_session() { return &scenic_session_; }
 
-  // Embeds the View identified by |token| into the render node,
-  // causing its contents to be displayed in this window.
-  void AttachSurfaceView(fuchsia::ui::views::ViewHolderToken token);
+  void AttachSurface(fuchsia::ui::gfx::ExportToken surface_export_token);
 
   // PlatformWindow implementation.
   gfx::Rect GetBounds() override;
diff --git a/ui/ozone/public/interfaces/scenic_gpu_host.mojom b/ui/ozone/public/interfaces/scenic_gpu_host.mojom
index 6218943..886ba36 100644
--- a/ui/ozone/public/interfaces/scenic_gpu_host.mojom
+++ b/ui/ozone/public/interfaces/scenic_gpu_host.mojom
@@ -6,7 +6,7 @@
 
 // Browser process interface that enables the GPU process to present to Scenic.
 interface ScenicGpuHost {
-  // Attaches the surface View identified by |view_holder_token| to the scene
-  // graph for |window_id|.
-  AttachSurfaceToWindow(int32 window_id, handle view_holder_token);
+  // Attaches the surface identified by |surface_export_token| as an import
+  // node in the scene graph for |window_id|.
+  AttachSurfaceToWindow(int32 window_id, handle surface_export_token);
 };
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 5fc12209..ab33751 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -185,16 +185,8 @@
 
 display::Display DesktopScreenX11::GetDisplayMatching(
     const gfx::Rect& match_rect) const {
-  int max_area = 0;
-  const display::Display* matching = nullptr;
-  for (const auto& display : displays_) {
-    gfx::Rect intersect = gfx::IntersectRects(display.bounds(), match_rect);
-    int area = intersect.width() * intersect.height();
-    if (area > max_area) {
-      max_area = area;
-      matching = &display;
-    }
-  }
+  const display::Display* matching =
+      display::FindDisplayWithBiggestIntersection(displays_, match_rect);
   // Fallback to the primary display if there is no matching display.
   return matching ? *matching : GetPrimaryDisplay();
 }
diff --git a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
index 92effd9..47f3122 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
+++ b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
@@ -55,6 +55,7 @@
 
   js_library("cr_network_listener_behavior") {
     deps = [
+      "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider",
       "//ui/webui/resources/js:assert",
     ]
     externs_list = [ "$externs_path/networking_private.js" ]
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.html b/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.html
index 6f8d242..929b810c 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.html
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.html
@@ -1 +1,2 @@
+<link rel="import" href="chrome://resources/cr_components/chromeos/network/mojo_interface_provider.html">
 <script src="cr_network_listener_behavior.js"></script>
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js b/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
index dfc2c38..91c2c23 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
@@ -3,98 +3,36 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Polymer behavior for alerting specified child elements of
- * changes to the devices network data.
+ * @fileoverview Polymer behavior for observing CrosNetworkConfigObserver
+ * events.
  */
 
 /** @polymerBehavior */
 const CrNetworkListenerBehavior = {
-  properties: {
-    /**
-     * Array of selectors specifying all children to alert of changes to the
-     * network list.
-     * @private {!Array<string>}
-     */
-    networkListChangeSubscriberSelectors_: Array,
-
-    /**
-     * Array of selectors specifying all children to alert of important changes
-     * to the specific networks.
-     * @private {!Array<string>}
-     */
-    networksChangeSubscriberSelectors_: Array,
-
-    /** @type {!NetworkingPrivate} */
-    networkingPrivate: Object,
-  },
-
-  /** @private {?function(!Array<string>)} */
-  networkListChangedListener_: null,
-
-  /** @private {?function(!Array<string>)} */
-  networksChangedListener_: null,
+  /** @private {?chromeos.networkConfig.mojom.CrosNetworkConfigObserver} */
+  observer_: null,
 
   /** @override */
   attached: function() {
-    this.networkListChangedListener_ = this.networkListChangedListener_ ||
-        this.onNetworkListChanged_.bind(this);
-    this.networkingPrivate.onNetworkListChanged.addListener(
-        this.networkListChangedListener_);
-
-    this.networksChangedListener_ =
-        this.networksChangedListener_ || this.onNetworksChanged_.bind(this);
-    this.networkingPrivate.onNetworksChanged.addListener(
-        this.networksChangedListener_);
+    this.observer_ =
+        new chromeos.networkConfig.mojom.CrosNetworkConfigObserver(this);
+    network_config.MojoInterfaceProviderImpl.getInstance()
+        .getMojoServiceProxy()
+        .addObserver(this.observer_.createProxy());
   },
 
-  /** @override */
-  detached: function() {
-    this.networkingPrivate.onNetworkListChanged.removeListener(
-        assert(this.networkListChangedListener_));
-    this.networkingPrivate.onNetworksChanged.removeListener(
-        assert(this.networksChangedListener_));
-  },
+  // CrosNetworkConfigObserver methods. Override these in the implementation.
 
   /**
-   * This event is triggered when the list of networks changes.
-   * |networkIds| contains the ids for all visible or configured networks.
-   * networkingPrivate.onNetworkListChanged event callback.
-   * @param {!Array<string>} networkIds
-   * @private
+   * CrosNetworkConfigObserver impl
+   * @param {!Array<chromeos.networkConfig.mojom.NetworkStateProperties>}
+   *     activeNetworks
    */
-  onNetworkListChanged_: function(networkIds) {
-    const event = new CustomEvent('network-list-changed', {detail: networkIds});
-    for (let i = 0; i < this.networkListChangeSubscriberSelectors_.length;
-         i++) {
-      this.maybeDispatchEvent_(
-          this.networkListChangeSubscriberSelectors_[i], event);
-    }
-  },
+  onActiveNetworksChanged: function(activeNetworks) {},
 
-  /**
-   * This event is triggered when interesting properties of a network change.
-   * |networkIds| contains the ids for networks whose properties have changed.
-   * networkingPrivate.onNetworksChanged event callback.
-   * @param {!Array<string>} networkIds
-   * @private
-   */
-  onNetworksChanged_: function(networkIds) {
-    const event = new CustomEvent('networks-changed', {detail: networkIds});
-    for (let i = 0; i < this.networksChangeSubscriberSelectors_.length; i++) {
-      this.maybeDispatchEvent_(
-          this.networksChangeSubscriberSelectors_[i], event);
-    }
-  },
+  /** CrosNetworkConfigObserver impl */
+  onNetworkStateListChanged: function() {},
 
-  /**
-   * @param {!Event} event
-   * @private
-   */
-  maybeDispatchEvent_: function(selectors, event) {
-    const element = this.$$(selectors);
-    if (!element) {
-      return;
-    }
-    element.dispatchEvent(event);
-  },
+  /** CrosNetworkConfigObserver impl */
+  onDeviceStateListChanged: function() {},
 };
diff --git a/ui/webui/resources/js/cr/ui/focus_outline_manager.js b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
index 3432f1e6..3071ba8d 100644
--- a/ui/webui/resources/js/cr/ui/focus_outline_manager.js
+++ b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
@@ -9,6 +9,9 @@
    */
   const CLASS_NAME = 'focus-outline-visible';
 
+  /** @type {!Map<!Document, !cr.ui.FocusOutlineManager>} */
+  const docsToManager = new Map();
+
   /**
    * This class sets a CSS class name on the HTML element of |doc| when the user
    * presses the tab key. It removes the class name when the user clicks
@@ -23,46 +26,47 @@
    * And the outline will only be shown if the user uses the keyboard to get to
    * it.
    *
-   * @param {Document} doc The document to attach the focus outline manager to.
-   * @constructor
    */
-  function FocusOutlineManager(doc) {
-    this.classList_ = doc.documentElement.classList;
-
-    const onEvent = function(focusByKeyboard, e) {
-      if (this.focusByKeyboard_ === focusByKeyboard) {
-        return;
-      }
-      this.focusByKeyboard_ = focusByKeyboard;
-      this.updateVisibility();
-    };
-
-    doc.addEventListener('keydown', onEvent.bind(this, true), true);
-    doc.addEventListener('mousedown', onEvent.bind(this, false), true);
-
-    doc.addEventListener('focusout', function(event) {
-      window.setTimeout(function() {
-        if (!doc.hasFocus()) {
-          this.focusByKeyboard_ = true;
-          this.updateVisibility();
-        }
-      }.bind(this), 0);
-    }.bind(this));
-
-    this.updateVisibility();
-  }
-
-  FocusOutlineManager.prototype = {
+  class FocusOutlineManager {
     /**
-     * Whether focus change is triggered by TAB key.
-     * @type {boolean}
-     * @private
+     * @param {Document} doc The document to attach the focus outline manager
+     *     to.
      */
-    focusByKeyboard_: true,
+    constructor(doc) {
+      /**
+       * Whether focus change is triggered by TAB key.
+       * @private {boolean}
+       */
+      this.focusByKeyboard_ = true;
 
-    updateVisibility: function() {
+      this.classList_ = doc.documentElement.classList;
+
+      const onEvent = function(focusByKeyboard, e) {
+        if (this.focusByKeyboard_ === focusByKeyboard) {
+          return;
+        }
+        this.focusByKeyboard_ = focusByKeyboard;
+        this.updateVisibility();
+      };
+
+      doc.addEventListener('keydown', onEvent.bind(this, true), true);
+      doc.addEventListener('mousedown', onEvent.bind(this, false), true);
+
+      doc.addEventListener('focusout', event => {
+        window.setTimeout(() => {
+          if (!doc.hasFocus()) {
+            this.focusByKeyboard_ = true;
+            this.updateVisibility();
+          }
+        }, 0);
+      });
+
+      this.updateVisibility();
+    }
+
+    updateVisibility() {
       this.visible = this.focusByKeyboard_;
-    },
+    }
 
     /**
      * Whether the focus outline should be visible.
@@ -70,29 +74,27 @@
      */
     set visible(visible) {
       this.classList_.toggle(CLASS_NAME, visible);
-    },
+    }
+
     get visible() {
       return this.classList_.contains(CLASS_NAME);
     }
-  };
 
-  /** @type {!Map<!Document, !cr.ui.FocusOutlineManager>} */
-  const docsToManager = new Map();
-
-  /**
-   * Gets a per document singleton focus outline manager.
-   * @param {!Document} doc The document to get the |FocusOutlineManager| for.
-   * @return {!cr.ui.FocusOutlineManager} The per document singleton focus
-   *     outline manager.
-   */
-  FocusOutlineManager.forDocument = function(doc) {
-    let manager = docsToManager.get(doc);
-    if (!manager) {
-      manager = new FocusOutlineManager(doc);
-      docsToManager.set(doc, manager);
+    /**
+     * Gets a per document singleton focus outline manager.
+     * @param {!Document} doc The document to get the |FocusOutlineManager| for.
+     * @return {!cr.ui.FocusOutlineManager} The per document singleton focus
+     *     outline manager.
+     */
+    static forDocument(doc) {
+      let manager = docsToManager.get(doc);
+      if (!manager) {
+        manager = new FocusOutlineManager(doc);
+        docsToManager.set(doc, manager);
+      }
+      return manager;
     }
-    return manager;
-  };
+  }
 
   return {FocusOutlineManager: FocusOutlineManager};
 });
diff --git a/ui/webui/resources/js/promise_resolver.js b/ui/webui/resources/js/promise_resolver.js
index d19f7f73..93a1164 100644
--- a/ui/webui/resources/js/promise_resolver.js
+++ b/ui/webui/resources/js/promise_resolver.js
@@ -16,63 +16,65 @@
  *  resolver.resolve({hello: 'world'});
  */
 
-/**
- * @constructor @struct
- * @template T
- */
-function PromiseResolver() {
-  /** @private {function(T=): void} */
-  this.resolve_;
+// eslint-disable-next-line no-var
+var PromiseResolver = class {
+  /** @template T */
+  constructor() {
+    /** @private {function(T=): void} */
+    this.resolve_;
 
-  /** @private {function(*=): void} */
-  this.reject_;
+    /** @private {function(*=): void} */
+    this.reject_;
 
-  /** @private {boolean} */
-  this.isFulfilled_ = false;
+    /** @private {boolean} */
+    this.isFulfilled_ = false;
 
-  /** @private {!Promise<T>} */
-  this.promise_ = new Promise(function(resolve, reject) {
-    this.resolve_ = /** @param {T=} resolution */ function(resolution) {
-      resolve(resolution);
-      this.isFulfilled_ = true;
-    };
-    this.reject_ = /** @param {*=} reason */ function(reason) {
-      reject(reason);
-      this.isFulfilled_ = true;
-    };
-  }.bind(this));
-}
+    /** @private {!Promise<T>} */
+    this.promise_ = new Promise((resolve, reject) => {
+      this.resolve_ = /** @param {T=} resolution */ (resolution) => {
+        resolve(resolution);
+        this.isFulfilled_ = true;
+      };
+      this.reject_ = /** @param {*=} reason */ (reason) => {
+        reject(reason);
+        this.isFulfilled_ = true;
+      };
+    });
+  }
 
-PromiseResolver.prototype = {
   /** @return {boolean} Whether this resolver has been resolved or rejected. */
   get isFulfilled() {
     return this.isFulfilled_;
-  },
+  }
+
   set isFulfilled(i) {
     assertNotReached();
-  },
+  }
 
   /** @return {!Promise<T>} */
   get promise() {
     return this.promise_;
-  },
+  }
+
   set promise(p) {
     assertNotReached();
-  },
+  }
 
   /** @return {function(T=): void} */
   get resolve() {
     return this.resolve_;
-  },
+  }
+
   set resolve(r) {
     assertNotReached();
-  },
+  }
 
   /** @return {function(*=): void} */
   get reject() {
     return this.reject_;
-  },
+  }
+
   set reject(s) {
     assertNotReached();
-  },
+  }
 };