diff --git a/BUILD.gn b/BUILD.gn
index 6cc7dae..379cc811c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -757,15 +757,13 @@
       "//chrome/browser/vr:vr_common_perftests",
       "//chrome/browser/vr:vr_common_unittests",
       "//chrome/browser/vr:vr_pixeltests",
+      "//tools/perf/contrib/vr_benchmarks:vr_perf_tests",
     ]
     if (is_desktop_linux && use_ozone) {
       deps += [ "//chrome/browser/vr/testapp:vr_testapp" ]
     }
     if (is_android) {
-      deps += [
-        "//chrome/browser/android/vr:vr_android_unittests",
-        "//tools/perf/contrib/vr_benchmarks:vr_perf_tests",
-      ]
+      deps += [ "//chrome/browser/android/vr:vr_android_unittests" ]
     }
   }
 
@@ -1159,7 +1157,7 @@
     ]
 
     if (is_android) {
-      data += [ "//third_party/android_tools/sdk/platform-tools/adb" ]
+      data += [ "//third_party/android_sdk/public/platform-tools/adb" ]
     }
 
     if (!is_chromeos) {
diff --git a/DEPS b/DEPS
index 58447bf7..45d6ffd 100644
--- a/DEPS
+++ b/DEPS
@@ -58,10 +58,6 @@
   # build ARC++ support libraries.
   'checkout_android_native_support': 'checkout_android or checkout_chromeos',
 
-  # By default, do not check out android sdk sources. This can be overridden
-  # e.g. with custom_vars.
-  'checkout_android_sdk_sources': False,
-
   # By default, do not check out Chromium autofill captured sites test
   # dependencies. These dependencies include very large numbers of very
   # large web capture files. Captured sites test dependencies are also
@@ -133,11 +129,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': '252996c72d2ce55a7d29505d1db926600bca11f6',
+  'skia_revision': '4a20dbeaf31a549c0ae857beb3b163962f9aa325',
   # 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': '9157bb60b80b4ceffb3c199ac447783f64cf0d9e',
+  'v8_revision': '36585c1b6b1fd69d093706a6c4ad9775506a7885',
   # 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.
@@ -196,7 +192,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': 'd8c847c11680377ddb0e65aee74fb8533f54d43a',
+  'catapult_revision': '93bbf937f83835ceb3d858e383a165afdeeae802',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -216,35 +212,39 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
-  'android_sdk_build-tools_version': '125a2abaa0393cd68a2414ec79e514d5d0a80b58',
+  'android_sdk_build-tools_version': 'DLK621q5_Bga5EsOr7cp6bHWWxFKx6UHLu_Ix_m3AckC',
   # 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': 'qQXmM5spNs2IKBD_7Y_2a5ondRnb3LGHbqfm39aXmGgC',
+  'android_sdk_emulator_version': 'ki7EDQRAiZAUYlnTWR1XmI6cJTk65fJ-DNZUU1zrtS8C',
   # 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': '2f33032ef348e2ff37d90d53563f4cb030a879bf',
+  'android_sdk_extras_version': 'iIwhhDox5E-mHgwUhCz8JACWQCpUjdqt5KTY9VLugKQC',
+  # 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.
+  'android_sdk_patcher_version': 'I6FNMhrXlpB-E1lOhMlvld7xt9lBVNOO83KIluXDyA0C',
   # 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': 'nVZAgkiZjKzmtiTSu70dJWaxpN4NzrPbfsGP7FjCe9UC',
+  'android_sdk_platform-tools_version': '4Y2Cb2LGzoc-qt-oIUIlhySotJaKeE3ELFedSVe6Uk8C',
   # 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.
-  'android_sdk_platforms_version': 'Yz02ywwHGz649rWbTjLJ_XBR8DmwIpxDCx4lkrBiMuQC',
+  'android_sdk_platforms_version': 'Kg2t9p0YnQk8bldUv4VA3o156uPXLUfIFAmVZ-Gm5ewC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_sources_version
   # and whatever else without interference from each other.
-  'android_sdk_sources_version': 'WRJ021tx-HAI9-nepe2OosHLCxifKbIWBWQvH1z42aYC',
+  'android_sdk_sources_version': 'K9uEn3JvNELEVjjVK_GQD3ZQD3rqAnJSxCWxjmUmRkgC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_tools_version
   # and whatever else without interference from each other.
-  'android_sdk_tools_version': '1a659d51804abb9461cd19aeffc2102e47a15a25',
+  'android_sdk_tools_version': 'wYcRQC2WHsw2dKWs4EA7fw9Qsyzu1ds1_fRjKmGxe5QC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_tools-lint_version
   # and whatever else without interference from each other.
-  'android_sdk_tools-lint_version': 'T3QcNurqwJht09OjR9slC7SdKHO0ojTQWjJZPfuYl4EC',
+  'android_sdk_tools-lint_version': '89hXqZYzCum3delB5RV7J_QyWkaRodqdtQS0s3LMh3wC',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -671,6 +671,10 @@
               'version': Var('android_sdk_extras_version'),
           },
           {
+              'package': 'chromium/third_party/android_sdk/public/patcher',
+              'version': Var('android_sdk_patcher_version'),
+          },
+          {
               'package': 'chromium/third_party/android_sdk/public/platform-tools',
               'version': Var('android_sdk_platform-tools_version'),
           },
@@ -679,6 +683,10 @@
               'version': Var('android_sdk_platforms_version'),
           },
           {
+              'package': 'chromium/third_party/android_sdk/public/sources',
+              'version': Var('android_sdk_sources_version'),
+          },
+          {
               'package': 'chromium/third_party/android_sdk/public/tools',
               'version': Var('android_sdk_tools_version'),
           },
@@ -687,18 +695,7 @@
               'version': Var('android_sdk_tools-lint_version'),
           },
       ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_sdk/sources': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_sdk/sources',
-              'version': Var('android_sdk_sources_version'),
-          },
-      ],
-      'condition': 'checkout_android_sdk_sources',
+      'condition': 'checkout_android_native_support',
       'dep_type': 'cipd',
   },
 
@@ -829,7 +826,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'efe902b20b6ae0d367b354bdaa2e10c19349f880',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b542cca266972d6f78afe52d9a9a1a56a3f90d7d',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -917,7 +914,7 @@
   },
 
   'src/third_party/googletest/src':
-    Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + 'efecb0bfa687cf87836494f5d62868485c00fb66',
+    Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '8b6d3f9c4a774bef3081195d422993323b6bb2e0',
 
   # GNU binutils assembler for x86-32.
   'src/third_party/gnu_binutils': {
@@ -1171,7 +1168,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '16626dc4501d57eda15b0a829043cd09bf1d1cfc',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '7b0c9453e8d31c03d16cd1d94bd17a96fb9fe3ef',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1383,7 +1380,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@28645ae1d8fb2c6418b2614db64ef653a720b63b',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6abdbc905c1403fdfb224151fc771eaed28bfe8c',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index e7c16ac..0fad10a 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -585,8 +585,6 @@
     "browser/aw_web_contents_view_delegate.h",
     "browser/aw_web_ui_controller_factory.cc",
     "browser/aw_web_ui_controller_factory.h",
-    "browser/command_line_helper.cc",
-    "browser/command_line_helper.h",
     "browser/cookie_manager.cc",
     "browser/cookie_manager.h",
     "browser/find_helper.cc",
@@ -659,6 +657,8 @@
     "browser/safe_browsing/aw_safe_browsing_whitelist_manager.h",
     "browser/safe_browsing/aw_url_checker_delegate_impl.cc",
     "browser/safe_browsing/aw_url_checker_delegate_impl.h",
+    "browser/scoped_add_feature_flags.cc",
+    "browser/scoped_add_feature_flags.h",
     "browser/state_serializer.cc",
     "browser/state_serializer.h",
     "browser/tracing/aw_trace_event_args_whitelist.cc",
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 8dc38b91..8e076bb 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -19,6 +19,7 @@
 #include "android_webview/browser/safe_browsing/aw_safe_browsing_whitelist_manager.h"
 #include "base/base_paths_posix.h"
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/path_service.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/post_task.h"
@@ -36,6 +37,7 @@
 #include "content/public/browser/web_contents.h"
 #include "net/proxy_resolution/proxy_config_service_android.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
+#include "services/network/public/cpp/features.h"
 #include "services/preferences/tracked/segregated_pref_store.h"
 
 using base::FilePath;
@@ -151,12 +153,11 @@
 void AwBrowserContext::PreMainMessageLoopRun(net::NetLog* net_log) {
   FilePath cache_path = GetCacheDir();
 
-  // TODO(ntfschr): set this to nullptr when the NetworkService is disabled,
-  // once we remove a dependency on url_request_context_getter_
-  // (http://crbug.com/887538).
-  url_request_context_getter_ =
-      new AwURLRequestContextGetter(cache_path, CreateProxyConfigService(),
-                                    user_pref_service_.get(), net_log);
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    url_request_context_getter_ =
+        new AwURLRequestContextGetter(cache_path, CreateProxyConfigService(),
+                                      user_pref_service_.get(), net_log);
+  }
 
   scoped_refptr<base::SequencedTaskRunner> db_task_runner =
       base::CreateSequencedTaskRunnerWithTraits(
@@ -310,6 +311,7 @@
 net::URLRequestContextGetter* AwBrowserContext::CreateRequestContext(
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector request_interceptors) {
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
   // This function cannot actually create the request context because
   // there is a reentrant dependency on GetResourceContext() via
   // content::StoragePartitionImplMap::Create(). This is not fixable
@@ -332,6 +334,7 @@
 }
 
 net::URLRequestContextGetter* AwBrowserContext::CreateMediaRequestContext() {
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
   return url_request_context_getter_.get();
 }
 
diff --git a/android_webview/browser/aw_proxy_controller.cc b/android_webview/browser/aw_proxy_controller.cc
index add6746b..087ca95 100644
--- a/android_webview/browser/aw_proxy_controller.cc
+++ b/android_webview/browser/aw_proxy_controller.cc
@@ -9,10 +9,12 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/message_loop/message_loop_current.h"
 #include "content/public/browser/browser_thread.h"
 #include "jni/AwProxyController_jni.h"
 #include "net/proxy_resolution/proxy_config_service_android.h"
+#include "services/network/public/cpp/features.h"
 
 using base::android::AttachCurrentThread;
 using base::android::HasException;
@@ -69,15 +71,21 @@
   base::android::AppendJavaStringArrayToStringVector(env, jbypass_rules,
                                                      &bypass_rules);
 
-  std::string result =
-      AwBrowserContext::GetDefault()
-          ->GetAwURLRequestContext()
-          ->SetProxyOverride(
-              proxy_rules, bypass_rules,
-              base::BindOnce(&ProxyOverrideChanged,
-                             ScopedJavaGlobalRef<jobject>(env, obj),
-                             ScopedJavaGlobalRef<jobject>(env, listener),
-                             ScopedJavaGlobalRef<jobject>(env, executor)));
+  std::string result;
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    // TODO(laisminchillo): implement the Network Service code path
+    // (http://crbug.com/902658).
+  } else {
+    result =
+        AwBrowserContext::GetDefault()
+            ->GetAwURLRequestContext()
+            ->SetProxyOverride(
+                proxy_rules, bypass_rules,
+                base::BindOnce(&ProxyOverrideChanged,
+                               ScopedJavaGlobalRef<jobject>(env, obj),
+                               ScopedJavaGlobalRef<jobject>(env, listener),
+                               ScopedJavaGlobalRef<jobject>(env, executor)));
+  }
   return base::android::ConvertUTF8ToJavaString(env, result);
 }
 
@@ -86,11 +94,17 @@
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jobject>& listener,
     const JavaParamRef<jobject>& executor) {
-  AwBrowserContext::GetDefault()->GetAwURLRequestContext()->ClearProxyOverride(
-      base::BindOnce(&ProxyOverrideChanged,
-                     ScopedJavaGlobalRef<jobject>(env, obj),
-                     ScopedJavaGlobalRef<jobject>(env, listener),
-                     ScopedJavaGlobalRef<jobject>(env, executor)));
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    // TODO(laisminchillo): implement the Network Service code path
+    // (http://crbug.com/902658).
+  } else {
+    AwBrowserContext::GetDefault()
+        ->GetAwURLRequestContext()
+        ->ClearProxyOverride(base::BindOnce(
+            &ProxyOverrideChanged, ScopedJavaGlobalRef<jobject>(env, obj),
+            ScopedJavaGlobalRef<jobject>(env, listener),
+            ScopedJavaGlobalRef<jobject>(env, executor)));
+  }
 }
 
-}  // namespace android_webview
\ No newline at end of file
+}  // namespace android_webview
diff --git a/android_webview/browser/command_line_helper.cc b/android_webview/browser/command_line_helper.cc
deleted file mode 100644
index 81aea03..0000000
--- a/android_webview/browser/command_line_helper.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2016 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 "android_webview/browser/command_line_helper.h"
-
-#include <vector>
-
-#include "base/base_switches.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-
-using std::string;
-using std::vector;
-
-namespace {
-
-// Adds |feature_name| to the list of features in |feature_list_name|, but only
-// if the |feature_name| is absent from the list of features in both
-// |feature_list_name| and |other_feature_list_name|.
-void AddFeatureToList(base::CommandLine& command_line,
-                      const string& feature_name,
-                      const char* feature_list_name,
-                      const char* other_feature_list_name) {
-  const string features_list =
-      command_line.GetSwitchValueASCII(feature_list_name);
-  const string other_features_list =
-      command_line.GetSwitchValueASCII(other_feature_list_name);
-
-  if (features_list.empty() && other_features_list.empty()) {
-    command_line.AppendSwitchASCII(feature_list_name, feature_name);
-    return;
-  }
-
-  vector<base::StringPiece> features =
-      base::FeatureList::SplitFeatureListString(features_list);
-  vector<base::StringPiece> other_features =
-      base::FeatureList::SplitFeatureListString(other_features_list);
-
-  if (!base::ContainsValue(features, feature_name) &&
-      !base::ContainsValue(other_features, feature_name)) {
-    features.push_back(feature_name);
-    command_line.AppendSwitchASCII(feature_list_name,
-                                   base::JoinString(features, ","));
-  }
-}
-
-}  // namespace
-
-// static
-void CommandLineHelper::AddEnabledFeature(base::CommandLine& command_line,
-                                          const string& feature_name) {
-  AddFeatureToList(command_line, feature_name, switches::kEnableFeatures,
-                   switches::kDisableFeatures);
-}
-
-// static
-void CommandLineHelper::AddDisabledFeature(base::CommandLine& command_line,
-                                           const string& feature_name) {
-  AddFeatureToList(command_line, feature_name, switches::kDisableFeatures,
-                   switches::kEnableFeatures);
-}
diff --git a/android_webview/browser/command_line_helper.h b/android_webview/browser/command_line_helper.h
deleted file mode 100644
index 9ad4326..0000000
--- a/android_webview/browser/command_line_helper.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 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 ANDROID_WEBVIEW_BROWSER_COMMAND_LINE_HELPER_H_
-#define ANDROID_WEBVIEW_BROWSER_COMMAND_LINE_HELPER_H_
-
-#include <string>
-
-#include "base/macros.h"
-
-namespace base {
-class CommandLine;
-}  // namespace base
-
-class CommandLineHelper {
- public:
-  // Add a feature to the --enabled-features list, but only if it's not
-  // already enabled or disabled.
-  static void AddEnabledFeature(base::CommandLine& command_line,
-                                const std::string& feature_name);
-
-  // Add a feature to the --disabled-features list, but only if it's not already
-  // enabled or disabled.
-  static void AddDisabledFeature(base::CommandLine& command_line,
-                                 const std::string& feature_name);
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(CommandLineHelper);
-};
-
-#endif  // ANDROID_WEBVIEW_BROWSER_COMMAND_LINE_HELPER_H_
diff --git a/android_webview/browser/command_line_helper_unittest.cc b/android_webview/browser/command_line_helper_unittest.cc
deleted file mode 100644
index c2710a9..0000000
--- a/android_webview/browser/command_line_helper_unittest.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2016 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 "android_webview/browser/command_line_helper.h"
-
-#include "base/base_switches.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/files/file_path.h"
-#include "base/stl_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Test;
-using base::CommandLine;
-
-const base::Feature kSomeSpecialFeature{"SomeSpecialFeature",
-                                        base::FEATURE_DISABLED_BY_DEFAULT};
-
-class CommandLineHelperTest : public Test {
- public:
-  CommandLineHelperTest() {}
-
-  void EnableFeatureAndVerify(CommandLine& command_line,
-                              const std::string& enabled_expected,
-                              const std::string& disabled_expected) {
-    CommandLineHelper::AddEnabledFeature(command_line,
-                                         kSomeSpecialFeature.name);
-    Verify(command_line, enabled_expected, disabled_expected);
-  }
-
-  void DisableFeatureAndVerify(CommandLine& command_line,
-                               const std::string& enabled_expected,
-                               const std::string& disabled_expected) {
-    CommandLineHelper::AddDisabledFeature(command_line,
-                                          kSomeSpecialFeature.name);
-    Verify(command_line, enabled_expected, disabled_expected);
-  }
-
-  void Verify(const CommandLine& command_line,
-              const std::string& enabled_expected,
-              const std::string& disabled_expected) {
-    EXPECT_EQ(enabled_expected,
-              command_line.GetSwitchValueASCII(switches::kEnableFeatures));
-    EXPECT_EQ(disabled_expected,
-              command_line.GetSwitchValueASCII(switches::kDisableFeatures));
-  }
-};
-
-TEST_F(CommandLineHelperTest, EnableForEmptyCommandLine) {
-  CommandLine command_line(CommandLine::NO_PROGRAM);
-  EnableFeatureAndVerify(command_line, "SomeSpecialFeature", "");
-}
-
-TEST_F(CommandLineHelperTest, EnableForNoEnabledFeatures) {
-  const CommandLine::CharType* argv[] = {FILE_PATH_LITERAL("program")};
-  CommandLine command_line(base::size(argv), argv);
-  EnableFeatureAndVerify(command_line, "SomeSpecialFeature", "");
-}
-
-TEST_F(CommandLineHelperTest, EnableForEnabledTestFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--enable-features=TestFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  EnableFeatureAndVerify(command_line, "TestFeature,SomeSpecialFeature", "");
-}
-
-TEST_F(CommandLineHelperTest, EnableForEnabledSomeSpecialFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--enable-features=SomeSpecialFeature,TestFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  EnableFeatureAndVerify(command_line, "SomeSpecialFeature,TestFeature", "");
-}
-
-TEST_F(CommandLineHelperTest, EnableForDisabledSomeSpecialFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--disable-features=SomeSpecialFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  EnableFeatureAndVerify(command_line, "", "SomeSpecialFeature");
-}
-
-TEST_F(CommandLineHelperTest, EnableForDisabledTestFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--disable-features=TestFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  EnableFeatureAndVerify(command_line, "SomeSpecialFeature", "TestFeature");
-}
-
-TEST_F(CommandLineHelperTest, DisableForEmptyCommandLine) {
-  CommandLine command_line(CommandLine::NO_PROGRAM);
-  DisableFeatureAndVerify(command_line, "", "SomeSpecialFeature");
-}
-
-TEST_F(CommandLineHelperTest, DisableForNoDisabledFeatures) {
-  const CommandLine::CharType* argv[] = {FILE_PATH_LITERAL("program")};
-  CommandLine command_line(base::size(argv), argv);
-  DisableFeatureAndVerify(command_line, "", "SomeSpecialFeature");
-}
-
-TEST_F(CommandLineHelperTest, DisableForDisabledTestFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--disable-features=TestFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  DisableFeatureAndVerify(command_line, "", "TestFeature,SomeSpecialFeature");
-}
-
-TEST_F(CommandLineHelperTest, DisableForDisabledSomeSpecialFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--disable-features=SomeSpecialFeature,TestFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  DisableFeatureAndVerify(command_line, "", "SomeSpecialFeature,TestFeature");
-}
-
-TEST_F(CommandLineHelperTest, DisableForEnabledSomeSpecialFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--enable-features=SomeSpecialFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  DisableFeatureAndVerify(command_line, "SomeSpecialFeature", "");
-}
-
-TEST_F(CommandLineHelperTest, DisableForEnabledTestFeature) {
-  const CommandLine::CharType* argv[] = {
-      FILE_PATH_LITERAL("program"),
-      FILE_PATH_LITERAL("--enable-features=TestFeature")};
-  CommandLine command_line(base::size(argv), argv);
-  DisableFeatureAndVerify(command_line, "TestFeature", "SomeSpecialFeature");
-}
diff --git a/android_webview/browser/cookie_manager.cc b/android_webview/browser/cookie_manager.cc
index fd49c7fd..526a88f 100644
--- a/android_webview/browser/cookie_manager.cc
+++ b/android_webview/browser/cookie_manager.cc
@@ -14,6 +14,7 @@
 #include "android_webview/browser/aw_cookie_access_policy.h"
 #include "android_webview/browser/net/init_native_callback.h"
 #include "android_webview/browser/net_network_service/aw_cookie_manager_wrapper.h"
+#include "base/android/callback_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/path_utils.h"
 #include "base/bind.h"
@@ -73,13 +74,11 @@
  public:
   BoolCookieCallbackHolder(JNIEnv* env, jobject callback) {
     callback_.Reset(env, callback);
+    DCHECK(callback_);
   }
 
   void Invoke(bool result) {
-    if (!callback_.is_null()) {
-      JNIEnv* env = base::android::AttachCurrentThread();
-      Java_AwCookieManager_invokeBooleanCookieCallback(env, callback_, result);
-    }
+    base::android::RunBooleanCallbackAndroid(callback_, result);
   }
 
   static base::RepeatingCallback<void(bool)> ConvertToCallback(
@@ -347,12 +346,10 @@
     // *cc.get() is safe, because network::CookieManager::SetCanonicalCookie
     // will make a copy before our smart pointer goes out of scope.
     GetCookieManagerWrapper()->SetCanonicalCookie(*cc.get(), new_host.scheme(),
-                                                  !options.exclude_httponly(),
-                                                  std::move(callback));
+                                                  options, std::move(callback));
   } else {
     GetCookieStore()->SetCanonicalCookieAsync(std::move(cc), new_host.scheme(),
-                                              !options.exclude_httponly(),
-                                              StatusToBool(callback));
+                                              options, StatusToBool(callback));
   }
 }
 
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.cc b/android_webview/browser/net/aw_cookie_store_wrapper.cc
index 2fdb2392..2b9e280 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.cc
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.cc
@@ -28,11 +28,11 @@
 void SetCanonicalCookieAsyncOnCookieThread(
     std::unique_ptr<net::CanonicalCookie> cookie,
     std::string source_scheme,
-    bool modify_http_only,
+    const net::CookieOptions& options,
     net::CookieStore::SetCookiesCallback callback) {
-  GetCookieStore()->SetCanonicalCookieAsync(
-      std::move(cookie), std::move(source_scheme), modify_http_only,
-      std::move(callback));
+  GetCookieStore()->SetCanonicalCookieAsync(std::move(cookie),
+                                            std::move(source_scheme), options,
+                                            std::move(callback));
 }
 
 void GetCookieListWithOptionsAsyncOnCookieThread(
@@ -104,12 +104,12 @@
 void AwCookieStoreWrapper::SetCanonicalCookieAsync(
     std::unique_ptr<net::CanonicalCookie> cookie,
     std::string source_scheme,
-    bool modify_http_only,
+    const net::CookieOptions& options,
     SetCookiesCallback callback) {
   DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
   PostTaskToCookieStoreTaskRunner(base::BindOnce(
       &SetCanonicalCookieAsyncOnCookieThread, std::move(cookie),
-      std::move(source_scheme), modify_http_only,
+      std::move(source_scheme), options,
       CreateWrappedCallback<net::CanonicalCookie::CookieInclusionStatus>(
           std::move(callback))));
 }
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.h b/android_webview/browser/net/aw_cookie_store_wrapper.h
index 7436105..77f96e1 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.h
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.h
@@ -49,7 +49,7 @@
                                  SetCookiesCallback callback) override;
   void SetCanonicalCookieAsync(std::unique_ptr<net::CanonicalCookie> cookie,
                                std::string source_scheme,
-                               bool modify_http_only,
+                               const net::CookieOptions& options,
                                SetCookiesCallback callback) override;
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const net::CookieOptions& options,
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index acc4483..0dfc0d4 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -255,6 +255,7 @@
 void AwURLRequestContextGetter::InitializeURLRequestContext() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!url_request_context_);
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
 
   net::URLRequestContextBuilder builder;
 
@@ -292,13 +293,8 @@
   builder.SetCookieStore(std::make_unique<AwCookieStoreWrapper>());
 
   net::URLRequestContextBuilder::HttpCacheParams cache_params;
-  // Note: we create this as IN_MEMORY when the network service is enabled
-  // only as a temporary measure, to avoid accessing the same HTTP cache from
-  // two spots in the code.
   cache_params.type =
-      base::FeatureList::IsEnabled(network::features::kNetworkService)
-          ? net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY
-          : net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
+      net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
   cache_params.max_size = GetHttpCacheSize();
   cache_params.path = cache_path_;
   builder.EnableHttpCache(cache_params);
diff --git a/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.cc b/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.cc
index 7984c76..096a60f 100644
--- a/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.cc
+++ b/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.cc
@@ -33,12 +33,12 @@
 void AwCookieManagerWrapper::SetCanonicalCookie(
     const net::CanonicalCookie& cc,
     std::string source_scheme,
-    bool modify_http_only,
+    const net::CookieOptions& cookie_options,
     SetCanonicalCookieCallback callback) {
   // TODO(ntfschr): handle the case where content layer isn't initialized yet
   // (http://crbug.com/933461).
   cookie_manager_->SetCanonicalCookie(cc, std::move(source_scheme),
-                                      modify_http_only, std::move(callback));
+                                      cookie_options, std::move(callback));
 }
 
 void AwCookieManagerWrapper::DeleteCookies(
diff --git a/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.h b/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.h
index 65e6b242..81aca263 100644
--- a/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.h
+++ b/android_webview/browser/net_network_service/aw_cookie_manager_wrapper.h
@@ -45,7 +45,7 @@
 
   void SetCanonicalCookie(const net::CanonicalCookie& cc,
                           std::string source_scheme,
-                          bool modify_http_only,
+                          const net::CookieOptions& cookie_options,
                           SetCanonicalCookieCallback);
 
   void DeleteCookies(network::mojom::CookieDeletionFilterPtr filter,
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
index 3fe5025..a6fbda8 100644
--- a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
+++ b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "android_webview/browser/aw_browser_context.h"
-#include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/prefs/pref_service.h"
diff --git a/android_webview/browser/scoped_add_feature_flags.cc b/android_webview/browser/scoped_add_feature_flags.cc
new file mode 100644
index 0000000..03f80fd
--- /dev/null
+++ b/android_webview/browser/scoped_add_feature_flags.cc
@@ -0,0 +1,50 @@
+// 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 "android_webview/browser/scoped_add_feature_flags.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+
+namespace android_webview {
+
+ScopedAddFeatureFlags::ScopedAddFeatureFlags(base::CommandLine* cl)
+    : cl_(cl),
+      enabled_features_(base::FeatureList::SplitFeatureListString(
+          cl->GetSwitchValueASCII(switches::kEnableFeatures))),
+      disabled_features_(base::FeatureList::SplitFeatureListString(
+          cl->GetSwitchValueASCII(switches::kDisableFeatures))) {}
+
+ScopedAddFeatureFlags::~ScopedAddFeatureFlags() {
+  cl_->AppendSwitchASCII(switches::kEnableFeatures,
+                         base::JoinString(enabled_features_, ","));
+  cl_->AppendSwitchASCII(switches::kDisableFeatures,
+                         base::JoinString(disabled_features_, ","));
+}
+
+void ScopedAddFeatureFlags::EnableIfNotSet(const base::Feature& feature) {
+  AddFeatureIfNotSet(feature, true /* enable */);
+}
+
+void ScopedAddFeatureFlags::DisableIfNotSet(const base::Feature& feature) {
+  AddFeatureIfNotSet(feature, false /* enable */);
+}
+
+void ScopedAddFeatureFlags::AddFeatureIfNotSet(const base::Feature& feature,
+                                               bool enable) {
+  const char* feature_name = feature.name;
+  if (base::ContainsValue(enabled_features_, feature_name) ||
+      base::ContainsValue(disabled_features_, feature_name)) {
+    return;
+  }
+  if (enable) {
+    enabled_features_.emplace_back(feature_name);
+  } else {
+    disabled_features_.emplace_back(feature_name);
+  }
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/scoped_add_feature_flags.h b/android_webview/browser/scoped_add_feature_flags.h
new file mode 100644
index 0000000..0b990ec4
--- /dev/null
+++ b/android_webview/browser/scoped_add_feature_flags.h
@@ -0,0 +1,40 @@
+// 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 ANDROID_WEBVIEW_BROWSER_SCOPED_ADD_FEATURE_FLAGS_H_
+#define ANDROID_WEBVIEW_BROWSER_SCOPED_ADD_FEATURE_FLAGS_H_
+
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace android_webview {
+
+class ScopedAddFeatureFlags {
+ public:
+  explicit ScopedAddFeatureFlags(base::CommandLine* cl);
+  ~ScopedAddFeatureFlags();
+
+  // Any existing (user set) enable/disable takes precedence.
+  void EnableIfNotSet(const base::Feature& feature);
+  void DisableIfNotSet(const base::Feature& feature);
+
+ private:
+  void AddFeatureIfNotSet(const base::Feature& feature, bool enable);
+
+  base::CommandLine* const cl_;
+  std::vector<base::StringPiece> enabled_features_;
+  std::vector<base::StringPiece> disabled_features_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAddFeatureFlags);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_SCOPED_ADD_FEATURE_FLAGS_H_
diff --git a/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java b/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
index f6f40aae..6eef540 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwCookieManager.java
@@ -6,9 +6,9 @@
 
 import android.os.Handler;
 import android.os.Looper;
+import android.support.annotation.Nullable;
 
 import org.chromium.base.Callback;
-import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
@@ -79,7 +79,7 @@
     public void setCookie(final String url, final String value, final Callback<Boolean> callback) {
         try {
             UrlValue pair = fixupUrlValue(url, value);
-            nativeSetCookie(pair.mUrl, pair.mValue, CookieCallback.convert(callback));
+            nativeSetCookie(pair.mUrl, pair.mValue, new CookieCallback(callback));
         } catch (IllegalStateException e) {
             throw new IllegalStateException(
                     "SetCookie must be called on a thread with a running Looper.");
@@ -105,7 +105,7 @@
      */
     public void removeSessionCookies(Callback<Boolean> callback) {
         try {
-            nativeRemoveSessionCookies(CookieCallback.convert(callback));
+            nativeRemoveSessionCookies(new CookieCallback(callback));
         } catch (IllegalStateException e) {
             throw new IllegalStateException(
                     "removeSessionCookies must be called on a thread with a running Looper.");
@@ -119,7 +119,7 @@
      */
     public void removeAllCookies(Callback<Boolean> callback) {
         try {
-            nativeRemoveAllCookies(CookieCallback.convert(callback));
+            nativeRemoveAllCookies(new CookieCallback(callback));
         } catch (IllegalStateException e) {
             throw new IllegalStateException(
                     "removeAllCookies must be called on a thread with a running Looper.");
@@ -164,41 +164,36 @@
         nativeSetAcceptFileSchemeCookies(accept);
     }
 
-    @CalledByNative
-    public static void invokeBooleanCookieCallback(CookieCallback<Boolean> callback,
-            boolean result) {
-        callback.onReceiveValue(result);
-    }
-
     /**
      * CookieCallback is a bridge that knows how to call a Callback on its original thread.
      * We need to arrange for the users Callback#onResult to be called on the original
      * thread after the work is done. When the API is called we construct a CookieCallback which
      * remembers the handler of the current thread. Later the native code uses
-     * invokeBooleanCookieCallback to call CookieCallback#onReceiveValue which posts a Runnable
-     * on the handler of the original thread which in turn calls Callback#onResult.
+     * the native method |RunBooleanCallbackAndroid| to call CookieCallback#onResult which posts a
+     * Runnable on the handler of the original thread which in turn calls Callback#onResult.
      */
-    private static class CookieCallback<T> {
-        Callback<T> mCallback;
+    private static class CookieCallback implements Callback<Boolean> {
+        @Nullable
+        Callback<Boolean> mCallback;
+        @Nullable
         Handler mHandler;
 
-        public CookieCallback(Callback<T> callback, Handler handler) {
-            mCallback = callback;
-            mHandler = handler;
-        }
-
-        public static <T> CookieCallback<T> convert(Callback<T> callback)
-                throws IllegalStateException {
-            if (callback == null) return null;
-            if (Looper.myLooper() == null) {
-                throw new IllegalStateException("CookieCallback.convert should be called on "
-                        + "a thread with a running Looper.");
+        public CookieCallback(@Nullable Callback<Boolean> callback) {
+            if (callback != null) {
+                if (Looper.myLooper() == null) {
+                    throw new IllegalStateException("new CookieCallback should be called on "
+                            + "a thread with a running Looper.");
+                }
+                mCallback = callback;
+                mHandler = new Handler();
             }
-            return new CookieCallback<T>(callback, new Handler());
         }
 
-        public void onReceiveValue(final T t) {
-            mHandler.post(() -> mCallback.onResult(t));
+        @Override
+        public void onResult(final Boolean result) {
+            if (mHandler == null) return;
+            assert mCallback != null;
+            mHandler.post(() -> mCallback.onResult(result));
         }
     }
 
@@ -242,14 +237,13 @@
     private native void nativeSetShouldAcceptCookies(boolean accept);
     private native boolean nativeGetShouldAcceptCookies();
 
-    private native void nativeSetCookie(String url, String value,
-            CookieCallback<Boolean> callback);
+    private native void nativeSetCookie(String url, String value, CookieCallback callback);
     private native void nativeSetCookieSync(String url, String value);
     private native String nativeGetCookie(String url);
 
-    private native void nativeRemoveSessionCookies(CookieCallback<Boolean> callback);
+    private native void nativeRemoveSessionCookies(CookieCallback callback);
     private native void nativeRemoveSessionCookiesSync();
-    private native void nativeRemoveAllCookies(CookieCallback<Boolean> callback);
+    private native void nativeRemoveAllCookies(CookieCallback callback);
     private native void nativeRemoveAllCookiesSync();
     private native void nativeRemoveExpiredCookies();
     private native void nativeFlushCookieStore();
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 48ce7bcc..f04f892 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -8,9 +8,9 @@
 
 #include "android_webview/browser/aw_content_browser_client.h"
 #include "android_webview/browser/aw_media_url_interceptor.h"
-#include "android_webview/browser/command_line_helper.h"
 #include "android_webview/browser/gfx/browser_view_renderer.h"
 #include "android_webview/browser/gfx/deferred_gpu_command_service.h"
+#include "android_webview/browser/scoped_add_feature_flags.h"
 #include "android_webview/browser/tracing/aw_trace_event_args_whitelist.h"
 #include "android_webview/common/aw_descriptors.h"
 #include "android_webview/common/aw_paths.h"
@@ -163,46 +163,43 @@
     cl->AppendSwitch(switches::kInProcessGPU);
   }
 
+  {
+    ScopedAddFeatureFlags features(cl);
+
 #if BUILDFLAG(ENABLE_SPELLCHECK)
-  CommandLineHelper::AddEnabledFeature(
-      *cl, spellcheck::kAndroidSpellCheckerNonLowEnd.name);
+    features.EnableIfNotSet(spellcheck::kAndroidSpellCheckerNonLowEnd);
 #endif  // ENABLE_SPELLCHECK
 
-  CommandLineHelper::AddDisabledFeature(*cl, features::kWebPayments.name);
+    features.EnableIfNotSet(
+        autofill::features::kAutofillSkipComparingInferredLabels);
 
-  // WebView does not and should not support WebAuthN.
-  CommandLineHelper::AddDisabledFeature(*cl, features::kWebAuth.name);
+    features.DisableIfNotSet(features::kWebPayments);
 
-  // WebView isn't compatible with OOP-D.
-  CommandLineHelper::AddDisabledFeature(*cl,
-                                        features::kVizDisplayCompositor.name);
+    // WebView does not and should not support WebAuthN.
+    features.DisableIfNotSet(features::kWebAuth);
 
-  // WebView does not support AndroidOverlay yet for video overlays.
-  CommandLineHelper::AddDisabledFeature(*cl, media::kUseAndroidOverlay.name);
+    // WebView isn't compatible with OOP-D.
+    features.DisableIfNotSet(features::kVizDisplayCompositor);
 
-  // WebView doesn't support embedding CompositorFrameSinks which is needed for
-  // UseSurfaceLayerForVideo[PIP] feature. https://crbug.com/853832
-  CommandLineHelper::AddDisabledFeature(*cl,
-                                        media::kUseSurfaceLayerForVideo.name);
-  CommandLineHelper::AddDisabledFeature(
-      *cl, media::kUseSurfaceLayerForVideoPIP.name);
+    // WebView does not support AndroidOverlay yet for video overlays.
+    features.DisableIfNotSet(media::kUseAndroidOverlay);
 
-  // WebView does not support EME persistent license yet, because it's not
-  // clear on how user can remove persistent media licenses from UI.
-  CommandLineHelper::AddDisabledFeature(*cl,
-                                        media::kMediaDrmPersistentLicense.name);
+    // WebView doesn't support embedding CompositorFrameSinks which is needed
+    // for UseSurfaceLayerForVideo[PIP] feature. https://crbug.com/853832
+    features.DisableIfNotSet(media::kUseSurfaceLayerForVideo);
+    features.DisableIfNotSet(media::kUseSurfaceLayerForVideoPIP);
 
-  CommandLineHelper::AddEnabledFeature(
-      *cl, autofill::features::kAutofillSkipComparingInferredLabels.name);
+    // WebView does not support EME persistent license yet, because it's not
+    // clear on how user can remove persistent media licenses from UI.
+    features.DisableIfNotSet(media::kMediaDrmPersistentLicense);
 
-  CommandLineHelper::AddDisabledFeature(
-      *cl, autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout
-               .name);
+    features.DisableIfNotSet(
+        autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
 
-  CommandLineHelper::AddDisabledFeature(*cl, features::kBackgroundFetch.name);
+    features.DisableIfNotSet(features::kBackgroundFetch);
 
-  CommandLineHelper::AddDisabledFeature(*cl,
-                                        features::kAndroidSurfaceControl.name);
+    features.DisableIfNotSet(features::kAndroidSurfaceControl);
+  }
 
   android_webview::RegisterPathProvider();
 
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index dcc850f..56c1a68 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -337,7 +337,6 @@
     "../browser/aw_media_url_interceptor_unittest.cc",
     "../browser/aw_permission_manager_unittest.cc",
     "../browser/aw_static_cookie_policy_unittest.cc",
-    "../browser/command_line_helper_unittest.cc",
     "../browser/gfx/browser_view_renderer_unittest.cc",
     "../browser/gfx/test/fake_window.cc",
     "../browser/gfx/test/fake_window.h",
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py
index ac1e5a0a..ee44c51 100755
--- a/android_webview/tools/apk_merger.py
+++ b/android_webview/tools/apk_merger.py
@@ -45,7 +45,7 @@
 from pylib import constants  # pylint: disable=import-error,wrong-import-position
 
 DEFAULT_ZIPALIGN_PATH = os.path.join(
-    SRC_DIR, 'third_party', 'android_tools', 'sdk', 'build-tools',
+    SRC_DIR, 'third_party', 'android_sdk', 'public', 'build-tools',
     constants.ANDROID_SDK_BUILD_TOOLS_VERSION, 'zipalign')
 
 
diff --git a/ash/app_list/presenter/app_list_presenter_impl.cc b/ash/app_list/presenter/app_list_presenter_impl.cc
index a2a8aaa1..0295641c 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl.cc
@@ -84,11 +84,6 @@
   ~OverviewAnimationMetricsReporter() override = default;
 
   void Start(bool enter) {
-    DCHECK(!started_);
-#if defined(DCHECK)
-    started_ = ui::ScopedAnimationDurationScaleMode::duration_scale_mode() !=
-               ui::ScopedAnimationDurationScaleMode::ZERO_DURATION;
-#endif
     enter_ = enter;
   }
 
@@ -100,16 +95,10 @@
       UMA_HISTOGRAM_PERCENTAGE(
           "Apps.StateTransition.AnimationSmoothness.ExitOverview", value);
     }
-#if defined(DCHECK)
-    started_ = false;
-#endif
   }
 
  private:
   bool enter_ = false;
-#if defined(DCHECK)
-  bool started_ = false;
-#endif
 
   DISALLOW_COPY_AND_ASSIGN(OverviewAnimationMetricsReporter);
 };
diff --git a/ash/app_list/views/assistant/assistant_main_stage.cc b/ash/app_list/views/assistant/assistant_main_stage.cc
index 345f8bb..74b785b 100644
--- a/ash/app_list/views/assistant/assistant_main_stage.cc
+++ b/ash/app_list/views/assistant/assistant_main_stage.cc
@@ -18,6 +18,7 @@
 #include "ui/compositor/layer_animation_element.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/views/border.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
@@ -27,6 +28,10 @@
 
 namespace {
 
+// Appearance.
+constexpr int kSeparatorThicknessDip = 1;
+constexpr int kSeparatorWidthDip = 64;
+
 // Footer animation.
 constexpr int kFooterAnimationTranslationDip = 22;
 constexpr base::TimeDelta kFooterAnimationTranslationDelay =
@@ -71,15 +76,9 @@
   }
 
   void OnPaint(gfx::Canvas* canvas) override {
-    constexpr SkColor kSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x0F);
-    constexpr int kSeparatorThicknessDip = 2;
     gfx::Rect draw_bounds(GetContentsBounds());
-    // TODO(wutao): To be finalized.
-    const int inset_height =
-        (draw_bounds.height() - kSeparatorThicknessDip) / 2;
-    draw_bounds.Inset(0, inset_height);
-    canvas->FillRect(draw_bounds, kSeparatorColor);
-    View::OnPaint(canvas);
+    draw_bounds.Inset(0, (draw_bounds.height() - kSeparatorThicknessDip) / 2);
+    canvas->FillRect(draw_bounds, gfx::kGoogleGrey300);
   }
 
  private:
@@ -155,8 +154,6 @@
   AddChildView(progress_indicator_);
 
   // Horizontal separator.
-  // TODO(wutao): finalize the width.
-  constexpr int kSeparatorWidthDip = 64;
   horizontal_separator_ = new HorizontalSeparator(
       kSeparatorWidthDip, progress_indicator_->GetPreferredSize().height());
   AddChildView(horizontal_separator_);
@@ -220,6 +217,14 @@
   query_view_->SetQuery(query);
 }
 
+void AssistantMainStage::OnPendingQueryCleared() {
+  // When a pending query is cleared, it may be because the interaction was
+  // cancelled, or because the query was committed. If the query was committed,
+  // reseting the query here will have no visible effect. If the interaction was
+  // cancelled, we set the query here to restore the previously committed query.
+  query_view_->SetQuery(delegate_->GetInteractionModel()->committed_query());
+}
+
 void AssistantMainStage::OnResponseChanged(
     const std::shared_ptr<ash::AssistantResponse>& response) {
   // TODO(wutao): Replace the visibility change by animations.
@@ -260,6 +265,8 @@
   progress_indicator_->layer()->SetOpacity(0.f);
   progress_indicator_->layer()->SetTransform(gfx::Transform());
 
+  query_view_->SetQuery(ash::AssistantNullQuery());
+
   UpdateFooter();
 }
 
diff --git a/ash/app_list/views/assistant/assistant_main_stage.h b/ash/app_list/views/assistant/assistant_main_stage.h
index 3cf73f5..87f3f11 100644
--- a/ash/app_list/views/assistant/assistant_main_stage.h
+++ b/ash/app_list/views/assistant/assistant_main_stage.h
@@ -50,6 +50,7 @@
   // AssistantInteractionModelObserver:
   void OnCommittedQueryChanged(const ash::AssistantQuery& query) override;
   void OnPendingQueryChanged(const ash::AssistantQuery& query) override;
+  void OnPendingQueryCleared() override;
   void OnResponseChanged(
       const std::shared_ptr<ash::AssistantResponse>& response) override;
 
diff --git a/ash/app_list/views/assistant/dialog_plate.cc b/ash/app_list/views/assistant/dialog_plate.cc
index b8589db9..ce45255 100644
--- a/ash/app_list/views/assistant/dialog_plate.cc
+++ b/ash/app_list/views/assistant/dialog_plate.cc
@@ -10,7 +10,7 @@
 #include "ash/assistant/ui/base/assistant_button.h"
 #include "ash/assistant/ui/dialog_plate/dialog_plate.h"
 #include "ash/assistant/ui/dialog_plate/mic_view.h"
-#include "ash/assistant/ui/logo_view/base_logo_view.h"
+#include "ash/assistant/ui/logo_view/logo_view.h"
 #include "ash/assistant/util/animation_util.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -34,10 +34,11 @@
 namespace {
 
 // Appearance.
-constexpr int kDialogPaddingDip = 16;
 constexpr int kIconSizeDip = 24;
 constexpr int kButtonSizeDip = 32;
-constexpr int kPreferredHeightDip = 56;
+constexpr int kPaddingBottomDip = 8;
+constexpr int kPaddingHorizontalDip = 16;
+constexpr int kPaddingTopDip = 12;
 
 // Animation.
 constexpr base::TimeDelta kAnimationFadeInDelay =
@@ -83,10 +84,6 @@
   return gfx::Size(INT_MAX, GetHeightForWidth(INT_MAX));
 }
 
-int DialogPlate::GetHeightForWidth(int width) const {
-  return kPreferredHeightDip;
-}
-
 void DialogPlate::ButtonPressed(views::Button* sender, const ui::Event& event) {
   OnButtonPressed(static_cast<ash::AssistantButtonId>(sender->id()));
 }
@@ -245,15 +242,16 @@
   views::BoxLayout* layout_manager =
       SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets(0, kDialogPaddingDip)));
+          gfx::Insets(kPaddingTopDip, kPaddingHorizontalDip, kPaddingBottomDip,
+                      kPaddingHorizontalDip)));
 
   layout_manager->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
 
   // Molecule icon.
-  molecule_icon_ = ash::BaseLogoView::Create();
+  molecule_icon_ = ash::LogoView::Create();
   molecule_icon_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
-  molecule_icon_->SetState(ash::BaseLogoView::State::kMoleculeWavy,
+  molecule_icon_->SetState(ash::LogoView::State::kMoleculeWavy,
                            /*animate=*/false);
   AddChildView(molecule_icon_);
 
diff --git a/ash/app_list/views/assistant/dialog_plate.h b/ash/app_list/views/assistant/dialog_plate.h
index 57d9291..3ad1518 100644
--- a/ash/app_list/views/assistant/dialog_plate.h
+++ b/ash/app_list/views/assistant/dialog_plate.h
@@ -20,7 +20,7 @@
 namespace ash {
 enum class AssistantButtonId;
 class AssistantViewDelegate;
-class BaseLogoView;
+class LogoView;
 class MicView;
 }  // namespace ash
 
@@ -53,7 +53,6 @@
   // views::View:
   const char* GetClassName() const override;
   gfx::Size CalculatePreferredSize() const override;
-  int GetHeightForWidth(int width) const override;
   void RequestFocus() override;
 
   // views::ButtonListener:
@@ -85,7 +84,7 @@
 
   ash::AssistantViewDelegate* const delegate_;
 
-  ash::BaseLogoView* molecule_icon_;              // Owned by view hierarchy.
+  ash::LogoView* molecule_icon_;                  // Owned by view hierarchy.
   views::View* input_modality_layout_container_;  // Owned by view hierarchy.
   views::View* keyboard_layout_container_;        // Owned by view hierarchy.
   views::View* voice_layout_container_;           // Owned by view hierarchy.
diff --git a/ash/assistant/assistant_alarm_timer_controller.cc b/ash/assistant/assistant_alarm_timer_controller.cc
index 6b52c7d..248a0f32 100644
--- a/ash/assistant/assistant_alarm_timer_controller.cc
+++ b/ash/assistant/assistant_alarm_timer_controller.cc
@@ -22,14 +22,22 @@
 
 namespace {
 
-// Grouping key for timer notifications.
+// Grouping key and ID prefix for timer notifications.
 constexpr char kTimerNotificationGroupingKey[] = "assistant/timer";
+constexpr char kTimerNotificationIdPrefix[] = "assistant/timer";
 
 // Interval at which alarms/timers are ticked.
 constexpr base::TimeDelta kTickInterval = base::TimeDelta::FromSeconds(1);
 
 // Helpers ---------------------------------------------------------------------
 
+// Creates a notification ID for the given |alarm_timer_id|. It is guaranteed
+// that this method will always return the same notification ID given the same
+// alarm/timer ID.
+std::string CreateTimerNotificationId(const std::string& alarm_timer_id) {
+  return std::string(kTimerNotificationIdPrefix) + alarm_timer_id;
+}
+
 std::string CreateTimerNotificationMessage(const AlarmTimer& alarm_timer,
                                            base::TimeDelta time_remaining) {
   const int minutes_remaining = time_remaining.InMinutes();
@@ -71,7 +79,7 @@
   notification->title = title;
   notification->message = message;
   notification->action_url = action_url;
-  notification->client_id = alarm_timer.id;
+  notification->client_id = CreateTimerNotificationId(alarm_timer.id);
   notification->grouping_key = kTimerNotificationGroupingKey;
 
   // This notification should be able to wake up the display if it was off.
@@ -126,10 +134,8 @@
 
 // TODO(dmblack): Remove method when the LibAssistant Alarm/Timer API is ready.
 void AssistantAlarmTimerController::OnTimerSoundingStarted() {
-  static constexpr char kIdPrefix[] = "assistant/timer";
-
   AlarmTimer timer;
-  timer.id = kIdPrefix + std::to_string(next_timer_id_++);
+  timer.id = std::to_string(next_timer_id_++);
   timer.type = AlarmTimerType::kTimer;
   timer.end_time = base::TimeTicks::Now();
   model_.AddAlarmTimer(timer);
@@ -168,7 +174,8 @@
   for (auto& pair : times_remaining) {
     auto* notification_controller =
         assistant_controller_->notification_controller();
-    if (notification_controller->model()->HasNotificationForId(pair.first)) {
+    if (notification_controller->model()->HasNotificationForId(
+            CreateTimerNotificationId(/*alarm_timer_id=*/pair.first))) {
       notification_controller->AddOrUpdateNotification(CreateTimerNotification(
           *model_.GetAlarmTimerById(pair.first), pair.second));
     }
diff --git a/ash/assistant/ui/BUILD.gn b/ash/assistant/ui/BUILD.gn
index 883d8d4..72483f9 100644
--- a/ash/assistant/ui/BUILD.gn
+++ b/ash/assistant/ui/BUILD.gn
@@ -62,8 +62,8 @@
     "dialog_plate/dialog_plate.h",
     "dialog_plate/mic_view.cc",
     "dialog_plate/mic_view.h",
-    "logo_view/base_logo_view.cc",
-    "logo_view/base_logo_view.h",
+    "logo_view/logo_view.cc",
+    "logo_view/logo_view.h",
     "main_stage/assistant_card_element_view.cc",
     "main_stage/assistant_card_element_view.h",
     "main_stage/assistant_footer_view.cc",
diff --git a/ash/assistant/ui/assistant_mini_view.cc b/ash/assistant/ui/assistant_mini_view.cc
index 17728d1..00775fe 100644
--- a/ash/assistant/ui/assistant_mini_view.cc
+++ b/ash/assistant/ui/assistant_mini_view.cc
@@ -10,7 +10,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/logo_view/base_logo_view.h"
+#include "ash/assistant/ui/logo_view/logo_view.h"
 #include "ash/assistant/util/assistant_util.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/strings/utf_string_conversions.h"
@@ -75,9 +75,9 @@
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
 
   // Molecule icon.
-  BaseLogoView* molecule_icon = BaseLogoView::Create();
+  LogoView* molecule_icon = LogoView::Create();
   molecule_icon->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
-  molecule_icon->SetState(BaseLogoView::State::kMoleculeWavy,
+  molecule_icon->SetState(LogoView::State::kMoleculeWavy,
                           /*animate=*/false);
   AddChildView(molecule_icon);
 
diff --git a/ash/assistant/ui/dialog_plate/mic_view.cc b/ash/assistant/ui/dialog_plate/mic_view.cc
index 46dd2fe..fd44dff 100644
--- a/ash/assistant/ui/dialog_plate/mic_view.cc
+++ b/ash/assistant/ui/dialog_plate/mic_view.cc
@@ -8,7 +8,7 @@
 
 #include "ash/assistant/model/assistant_ui_model.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
-#include "ash/assistant/ui/logo_view/base_logo_view.h"
+#include "ash/assistant/ui/logo_view/logo_view.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 
@@ -17,10 +17,10 @@
 namespace {
 
 // Appearance.
-// The desired height for the action view icon is 24dip in mic state to match
-// the static mic button in DialogPlate. The |kMicIcon| resource used for the
-// static button has different internal padding than does that of the icon drawn
-// by LogoView, so we add 2dip for visual consistency.
+// The desired height for the LogoView icon is 24dip in mic state to match the
+// static mic button in DialogPlate. The |kMicIcon| resource used for the static
+// button has different internal padding than does that of the icon drawn by
+// LogoView, so we add 2dip for visual consistency.
 constexpr int kIconSizeDip = 26;
 constexpr int kPreferredSizeDip = 32;
 
@@ -32,7 +32,8 @@
     : AssistantButton(listener, button_id), delegate_(delegate) {
   InitLayout();
 
-  // The AssistantViewDelegate should outlive ActionView.
+  // The AssistantViewDelegate is owned by AssistantController which is
+  // guaranteed to outlive the Assistant view hierarchy.
   delegate_->AddInteractionModelObserver(this);
 }
 
@@ -55,13 +56,13 @@
 void MicView::InitLayout() {
   SetLayoutManager(std::make_unique<views::FillLayout>());
 
-  // Voice action container.
-  views::View* voice_action_container_ = new views::View();
-  voice_action_container_->set_can_process_events_within_subtree(false);
-  AddChildView(voice_action_container_);
+  // Logo view container.
+  views::View* logo_view_container = new views::View();
+  logo_view_container->set_can_process_events_within_subtree(false);
+  AddChildView(logo_view_container);
 
-  views::BoxLayout* layout_manager = voice_action_container_->SetLayoutManager(
-      std::make_unique<views::BoxLayout>(
+  views::BoxLayout* layout_manager =
+      logo_view_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kVertical));
 
   layout_manager->set_cross_axis_alignment(
@@ -70,10 +71,10 @@
   layout_manager->set_main_axis_alignment(
       views::BoxLayout::MainAxisAlignment::MAIN_AXIS_ALIGNMENT_CENTER);
 
-  // Voice action.
-  voice_action_view_ = BaseLogoView::Create();
-  voice_action_view_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
-  voice_action_container_->AddChildView(voice_action_view_);
+  // Logo view.
+  logo_view_ = LogoView::Create();
+  logo_view_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
+  logo_view_container->AddChildView(logo_view_);
 
   // Initialize state.
   UpdateState(/*animate=*/false);
@@ -90,7 +91,7 @@
   if (speech_level_db < kSpeechLevelThreshold)
     return;
 
-  voice_action_view_->SetSpeechLevel(speech_level_db);
+  logo_view_->SetSpeechLevel(speech_level_db);
   if (!is_user_speaking_) {
     is_user_speaking_ = true;
     UpdateState(/*animate=*/true);
@@ -108,17 +109,17 @@
     animate = ui_model->visibility() == AssistantVisibility::kVisible;
   }
 
-  BaseLogoView::State mic_state;
+  LogoView::State mic_state;
   switch (interaction_model->mic_state()) {
     case MicState::kClosed:
-      mic_state = BaseLogoView::State::kMic;
+      mic_state = LogoView::State::kMic;
       break;
     case MicState::kOpen:
-      mic_state = is_user_speaking_ ? BaseLogoView::State::kUserSpeaks
-                                    : BaseLogoView::State::kListening;
+      mic_state = is_user_speaking_ ? LogoView::State::kUserSpeaks
+                                    : LogoView::State::kListening;
       break;
   }
-  voice_action_view_->SetState(mic_state, animate);
+  logo_view_->SetState(mic_state, animate);
 }
 
 }  // namespace ash
diff --git a/ash/assistant/ui/dialog_plate/mic_view.h b/ash/assistant/ui/dialog_plate/mic_view.h
index 2ac945d3..56fc48e 100644
--- a/ash/assistant/ui/dialog_plate/mic_view.h
+++ b/ash/assistant/ui/dialog_plate/mic_view.h
@@ -14,10 +14,10 @@
 
 enum class AssistantButtonId;
 class AssistantViewDelegate;
-class BaseLogoView;
+class LogoView;
 
-// A stateful view belonging to DialogPlate which indicates current user input
-// modality and delivers notification of press events.
+// A stateful view belonging to DialogPlate which indicates current mic state
+// and delivers notification of press events.
 class COMPONENT_EXPORT(ASSISTANT_UI) MicView
     : public AssistantButton,
       public AssistantInteractionModelObserver {
@@ -47,7 +47,7 @@
 
   AssistantViewDelegate* const delegate_;
 
-  BaseLogoView* voice_action_view_;  // Owned by view hierarchy.
+  LogoView* logo_view_;  // Owned by view hierarchy.
 
   // True when speech level goes above a threshold and sets LogoView in
   // kUserSpeaks state.
diff --git a/ash/assistant/ui/logo_view/base_logo_view.cc b/ash/assistant/ui/logo_view/logo_view.cc
similarity index 70%
rename from ash/assistant/ui/logo_view/base_logo_view.cc
rename to ash/assistant/ui/logo_view/logo_view.cc
index c4eff12..b6603c2 100644
--- a/ash/assistant/ui/logo_view/base_logo_view.cc
+++ b/ash/assistant/ui/logo_view/logo_view.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 "ash/assistant/ui/logo_view/base_logo_view.h"
+#include "ash/assistant/ui/logo_view/logo_view.h"
 
 #include "build/buildflag.h"
 #include "chromeos/assistant/buildflags.h"
@@ -13,16 +13,16 @@
 
 namespace ash {
 
-BaseLogoView::BaseLogoView() = default;
+LogoView::LogoView() = default;
 
-BaseLogoView::~BaseLogoView() = default;
+LogoView::~LogoView() = default;
 
 // static
-BaseLogoView* BaseLogoView::Create() {
+LogoView* LogoView::Create() {
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
   return new LogoViewImpl();
 #else
-  return new BaseLogoView();
+  return new LogoView();
 #endif
 }
 
diff --git a/ash/assistant/ui/logo_view/base_logo_view.h b/ash/assistant/ui/logo_view/logo_view.h
similarity index 68%
rename from ash/assistant/ui/logo_view/base_logo_view.h
rename to ash/assistant/ui/logo_view/logo_view.h
index 1554a3f..18634e0 100644
--- a/ash/assistant/ui/logo_view/base_logo_view.h
+++ b/ash/assistant/ui/logo_view/logo_view.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 ASH_ASSISTANT_UI_LOGO_VIEW_BASE_LOGO_VIEW_H_
-#define ASH_ASSISTANT_UI_LOGO_VIEW_BASE_LOGO_VIEW_H_
+#ifndef ASH_ASSISTANT_UI_LOGO_VIEW_LOGO_VIEW_H_
+#define ASH_ASSISTANT_UI_LOGO_VIEW_LOGO_VIEW_H_
 
 #include "base/component_export.h"
 #include "base/macros.h"
@@ -11,7 +11,7 @@
 
 namespace ash {
 
-class COMPONENT_EXPORT(ASSISTANT_UI) BaseLogoView : public views::View {
+class COMPONENT_EXPORT(ASSISTANT_UI) LogoView : public views::View {
  public:
   enum class State {
     kUndefined,
@@ -21,8 +21,8 @@
     kUserSpeaks,
   };
 
-  BaseLogoView();
-  ~BaseLogoView() override;
+  LogoView();
+  ~LogoView() override;
 
   // If |animate| is true, animates to the |state|.
   virtual void SetState(State state, bool animate) {}
@@ -32,12 +32,12 @@
   virtual void SetSpeechLevel(float speech_level) {}
 
   // Creates LogoView based on the build flag ENABLE_CROS_LIBASSISTANT.
-  static BaseLogoView* Create();
+  static LogoView* Create();
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(BaseLogoView);
+  DISALLOW_COPY_AND_ASSIGN(LogoView);
 };
 
 }  // namespace ash
 
-#endif  // ASH_ASSISTANT_UI_LOGO_VIEW_BASE_LOGO_VIEW_H_
+#endif  // ASH_ASSISTANT_UI_LOGO_VIEW_LOGO_VIEW_H_
diff --git a/ash/assistant/ui/logo_view/logo_view_impl.cc b/ash/assistant/ui/logo_view/logo_view_impl.cc
index 4856cf2c..9a707ec 100644
--- a/ash/assistant/ui/logo_view/logo_view_impl.cc
+++ b/ash/assistant/ui/logo_view/logo_view_impl.cc
@@ -49,22 +49,22 @@
   return "LogoViewImpl";
 }
 
-void LogoViewImpl::SetState(BaseLogoView::State state, bool animate) {
+void LogoViewImpl::SetState(LogoView::State state, bool animate) {
   StateModel::State animator_state;
   switch (state) {
-    case BaseLogoView::State::kUndefined:
+    case LogoView::State::kUndefined:
       animator_state = StateModel::State::kUndefined;
       break;
-    case BaseLogoView::State::kListening:
+    case LogoView::State::kListening:
       animator_state = StateModel::State::kListening;
       break;
-    case BaseLogoView::State::kMic:
+    case LogoView::State::kMic:
       animator_state = StateModel::State::kMic;
       break;
-    case BaseLogoView::State::kMoleculeWavy:
+    case LogoView::State::kMoleculeWavy:
       animator_state = StateModel::State::kMoleculeWavy;
       break;
-    case BaseLogoView::State::kUserSpeaks:
+    case LogoView::State::kUserSpeaks:
       animator_state = StateModel::State::kUserSpeaks;
       break;
   }
diff --git a/ash/assistant/ui/logo_view/logo_view_impl.h b/ash/assistant/ui/logo_view/logo_view_impl.h
index da7be86..1cf434f9 100644
--- a/ash/assistant/ui/logo_view/logo_view_impl.h
+++ b/ash/assistant/ui/logo_view/logo_view_impl.h
@@ -8,7 +8,7 @@
 #include <cstdint>
 #include <memory>
 
-#include "ash/assistant/ui/logo_view/base_logo_view.h"
+#include "ash/assistant/ui/logo_view/logo_view.h"
 #include "ash/assistant/ui/logo_view/shape/mic_part_shape.h"
 #include "base/macros.h"
 #include "chromeos/assistant/internal/logo_view/input_value_provider/sound_level_input_value_provider.h"
@@ -43,7 +43,7 @@
 
 // Displays the GLIF (Google Logo and Identity Family). It displays the dots and
 // the google logo. It does not display the Super G.
-class LogoViewImpl : public BaseLogoView,
+class LogoViewImpl : public LogoView,
                      public chromeos::assistant::StateAnimatorTimerDelegate,
                      public ui::CompositorAnimationObserver {
  public:
@@ -55,7 +55,7 @@
   LogoViewImpl();
   ~LogoViewImpl() override;
 
-  // BaseLogoView:
+  // LogoView:
   const char* GetClassName() const override;
   void SetState(State state, bool animate) override;
   void SetSpeechLevel(float speech_level) override;
diff --git a/ash/assistant/ui/main_stage/assistant_header_view.cc b/ash/assistant/ui/main_stage/assistant_header_view.cc
index 085b7b36..08f6b24 100644
--- a/ash/assistant/ui/main_stage/assistant_header_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_header_view.cc
@@ -10,7 +10,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/logo_view/base_logo_view.h"
+#include "ash/assistant/ui/logo_view/logo_view.h"
 #include "ash/assistant/util/animation_util.h"
 #include "ash/assistant/util/assistant_util.h"
 #include "base/time/time.h"
@@ -80,9 +80,9 @@
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
 
   // Molecule icon.
-  molecule_icon_ = BaseLogoView::Create();
+  molecule_icon_ = LogoView::Create();
   molecule_icon_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
-  molecule_icon_->SetState(BaseLogoView::State::kMoleculeWavy,
+  molecule_icon_->SetState(LogoView::State::kMoleculeWavy,
                            /*animate=*/false);
 
   // The molecule icon will be animated on its own layer.
diff --git a/ash/assistant/ui/main_stage/assistant_header_view.h b/ash/assistant/ui/main_stage/assistant_header_view.h
index 40c049c..c6d7530 100644
--- a/ash/assistant/ui/main_stage/assistant_header_view.h
+++ b/ash/assistant/ui/main_stage/assistant_header_view.h
@@ -20,7 +20,7 @@
 namespace ash {
 
 class AssistantViewDelegate;
-class BaseLogoView;
+class LogoView;
 
 // AssistantHeaderView is the child of UiElementContainerView which provides
 // the Assistant icon.
@@ -53,7 +53,7 @@
   AssistantViewDelegate* const delegate_;  // Owned by Shell.
 
   views::BoxLayout* layout_manager_;  // Owned by view hierarchy.
-  BaseLogoView* molecule_icon_;       // Owned by view hierarchy.
+  LogoView* molecule_icon_;           // Owned by view hierarchy.
 
   // True if this is the first query response received for the current Assistant
   // UI session, false otherwise.
diff --git a/ash/assistant/ui/main_stage/assistant_progress_indicator.cc b/ash/assistant/ui/main_stage/assistant_progress_indicator.cc
index c2012ce..ac172e7 100644
--- a/ash/assistant/ui/main_stage/assistant_progress_indicator.cc
+++ b/ash/assistant/ui/main_stage/assistant_progress_indicator.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "ash/assistant/util/animation_util.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/bind.h"
 #include "base/time/time.h"
 #include "ui/compositor/layer_animation_element.h"
@@ -24,6 +25,7 @@
 constexpr int kDotCount = 3;
 constexpr float kDotLargeSizeDip = 9.f;
 constexpr float kDotSmallSizeDip = 6.f;
+constexpr int kEmbeddedUiPreferredHeightDip = 9;
 constexpr int kSpacingDip = 4;
 
 // Animation.
@@ -73,28 +75,21 @@
 
 AssistantProgressIndicator::~AssistantProgressIndicator() = default;
 
-void AssistantProgressIndicator::InitLayout() {
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), kSpacingDip));
-
-  // Initialize dots.
-  for (int i = 0; i < kDotCount; ++i) {
-    views::View* dot_view = new views::View();
-    dot_view->SetBackground(std::make_unique<DotBackground>());
-    dot_view->SetPreferredSize(gfx::Size(kDotSmallSizeDip, kDotSmallSizeDip));
-
-    // Dots will animate on their own layers.
-    dot_view->SetPaintToLayer();
-    dot_view->layer()->SetFillsBoundsOpaquely(false);
-
-    AddChildView(dot_view);
-  }
-}
-
 const char* AssistantProgressIndicator::GetClassName() const {
   return "AssistantProgressIndicator";
 }
 
+gfx::Size AssistantProgressIndicator::CalculatePreferredSize() const {
+  const int preferred_width = views::View::CalculatePreferredSize().width();
+  return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
+}
+
+int AssistantProgressIndicator::GetHeightForWidth(int width) const {
+  return app_list_features::IsEmbeddedAssistantUIEnabled()
+             ? kEmbeddedUiPreferredHeightDip
+             : views::View::GetHeightForWidth(width);
+}
+
 void AssistantProgressIndicator::AddedToWidget() {
   VisibilityChanged(/*starting_from=*/this, /*is_visible=*/visible());
 }
@@ -161,4 +156,27 @@
   }
 }
 
+void AssistantProgressIndicator::InitLayout() {
+  views::BoxLayout* layout_manager =
+      SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+          kSpacingDip));
+
+  layout_manager->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
+
+  // Initialize dots.
+  for (int i = 0; i < kDotCount; ++i) {
+    views::View* dot_view = new views::View();
+    dot_view->SetBackground(std::make_unique<DotBackground>());
+    dot_view->SetPreferredSize(gfx::Size(kDotSmallSizeDip, kDotSmallSizeDip));
+
+    // Dots will animate on their own layers.
+    dot_view->SetPaintToLayer();
+    dot_view->layer()->SetFillsBoundsOpaquely(false);
+
+    AddChildView(dot_view);
+  }
+}
+
 }  // namespace ash
diff --git a/ash/assistant/ui/main_stage/assistant_progress_indicator.h b/ash/assistant/ui/main_stage/assistant_progress_indicator.h
index b13ce27..aecf343 100644
--- a/ash/assistant/ui/main_stage/assistant_progress_indicator.h
+++ b/ash/assistant/ui/main_stage/assistant_progress_indicator.h
@@ -21,6 +21,8 @@
 
   // views::View:
   const char* GetClassName() const override;
+  gfx::Size CalculatePreferredSize() const override;
+  int GetHeightForWidth(int width) const override;
   void AddedToWidget() override;
   void RemovedFromWidget() override;
   void OnLayerOpacityChanged(ui::PropertyChangeReason reason) override;
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 9b716f5..f31a3a4a 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -20,7 +20,7 @@
     "EnableOverviewRoundedCorners", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kLockScreenNotifications{"LockScreenNotifications",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kLockScreenInlineReply{"LockScreenInlineReply",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/system/message_center/notification_swipe_control_view.cc b/ash/system/message_center/notification_swipe_control_view.cc
index a4943e2..519626b 100644
--- a/ash/system/message_center/notification_swipe_control_view.cc
+++ b/ash/system/message_center/notification_swipe_control_view.cc
@@ -121,7 +121,7 @@
     settings_button_->SetBackground(
         views::CreateSolidBackground(SK_ColorTRANSPARENT));
 
-    AddChildViewAt(settings_button_, child_count());
+    AddChildView(settings_button_);
     Layout();
   } else if (!show && settings_button_) {
     DCHECK(Contains(settings_button_));
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc
index 7638c5f6..36efce0 100644
--- a/ash/system/network/network_list.cc
+++ b/ash/system/network/network_list.cc
@@ -439,12 +439,12 @@
 void NetworkListView::PlaceViewAtIndex(views::View* view, int index) {
   if (view->parent() != scroll_content()) {
     scroll_content()->AddChildViewAt(view, index);
+  } else if (index < scroll_content()->child_count() &&
+             scroll_content()->child_at(index) == view) {
+    // ReorderChildView() would no-op in this case, but we still want to avoid
+    // setting |needs_relayout_|.
+    return;
   } else {
-    // No re-order and re-layout is necessary if |view| is already at |index|.
-    if (index < scroll_content()->child_count() &&
-        scroll_content()->child_at(index) == view) {
-      return;
-    }
     scroll_content()->ReorderChildView(view, index);
   }
   needs_relayout_ = true;
diff --git a/ash/system/power/power_event_observer_unittest.cc b/ash/system/power/power_event_observer_unittest.cc
index a0a7c32..f1a55e9 100644
--- a/ash/system/power/power_event_observer_unittest.cc
+++ b/ash/system/power/power_event_observer_unittest.cc
@@ -16,8 +16,7 @@
 #include "ash/wm/lock_state_controller_test_api.h"
 #include "ash/wm/test_session_state_animator.h"
 #include "base/time/time.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/power/power_manager_client.h"
+#include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
@@ -33,7 +32,6 @@
 
   // AshTestBase:
   void SetUp() override {
-    chromeos::DBusThreadManager::Initialize();
     AshTestBase::SetUp();
     observer_.reset(new PowerEventObserver());
   }
@@ -41,7 +39,6 @@
   void TearDown() override {
     observer_.reset();
     AshTestBase::TearDown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
  protected:
@@ -70,15 +67,16 @@
 };
 
 TEST_F(PowerEventObserverTest, LockBeforeSuspend) {
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
-  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
+  ASSERT_EQ(0, client->num_pending_suspend_readiness_callbacks());
 
   // Check that the observer requests a suspend-readiness callback when it hears
   // that the system is about to suspend.
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
 
   // It should run the callback when it hears that the screen is locked and the
   // lock screen animations have completed.
@@ -96,21 +94,21 @@
   // CompositingDidCommit are ignored.
   test_api.CompositingStarted(compositor);
   test_api.CompositingEnded(compositor);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   // Suspend should remain delayed after first compositing cycle ends.
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   test_api.CompositingDidCommit(compositor);
   test_api.CompositingStarted(compositor);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   test_api.CompositingEnded(compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 
   // If the system is already locked, no callback should be requested.
@@ -128,7 +126,7 @@
   test_api.CompositeFrame(compositor);
 
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 
   // It also shouldn't request a callback if it isn't instructed to lock the
@@ -138,7 +136,7 @@
   SetShouldLockScreenAutomatically(false);
   EXPECT_EQ(1, GetNumVisibleCompositors());
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
@@ -202,9 +200,10 @@
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
 
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
 
   BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
   observer_->SuspendDone(base::TimeDelta());
@@ -214,15 +213,15 @@
   // observer has not run the callback that it got from the first suspend
   // request.  The real PowerManagerClient would reset its internal counter in
   // this situation but the stub client is not that smart.
-  EXPECT_EQ(2, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(2, client->num_pending_suspend_readiness_callbacks());
 
   observer_->OnLockAnimationsComplete();
-  EXPECT_EQ(2, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(2, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   ASSERT_TRUE(PowerEventObserverTestApi(observer_.get())
                   .SimulateCompositorsReadyForSuspend());
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
@@ -234,9 +233,10 @@
 
   UpdateDisplay("100x100,200x200");
 
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
 
   aura::Window::Windows windows = Shell::GetAllRootWindows();
   ASSERT_EQ(2u, windows.size());
@@ -244,7 +244,7 @@
   ui::Compositor* primary_compositor = windows[0]->GetHost()->compositor();
   ui::Compositor* secondary_compositor = windows[1]->GetHost()->compositor();
   ASSERT_EQ(2, GetNumVisibleCompositors());
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
 
   PowerEventObserverTestApi test_api(observer_.get());
 
@@ -256,7 +256,7 @@
   test_api.CompositingStarted(secondary_compositor);
   test_api.CompositingEnded(secondary_compositor);
 
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(2, GetNumVisibleCompositors());
 
   test_api.CompositeFrame(primary_compositor);
@@ -267,11 +267,11 @@
   // Even though compositing for one display is done, changes to compositor
   // visibility, and suspend readines state should be delayed until compositing
   // for the other display finishes.
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(2, GetNumVisibleCompositors());
 
   test_api.CompositeFrame(secondary_compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
@@ -282,16 +282,17 @@
 
   UpdateDisplay("100x100,200x200");
 
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
 
   aura::Window::Windows windows = Shell::GetAllRootWindows();
   ASSERT_EQ(2u, windows.size());
 
   ui::Compositor* primary_compositor = windows[0]->GetHost()->compositor();
   ASSERT_EQ(2, GetNumVisibleCompositors());
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   observer_->OnLockAnimationsComplete();
 
   PowerEventObserverTestApi test_api(observer_.get());
@@ -302,7 +303,7 @@
   // Even though compositing for one display is done, changes to compositor
   // visibility, and suspend readines state should be delayed until compositing
   // for the other display finishes.
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(2, GetNumVisibleCompositors());
 
   // Remove the second display, and verify the remaining compositor is hidden
@@ -310,7 +311,7 @@
   UpdateDisplay("100x100");
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
@@ -318,17 +319,18 @@
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
 
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
 
   Shell::GetPrimaryRootWindow()->GetHost()->compositor()->SetVisible(false);
 
   observer_->OnLockAnimationsComplete();
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
@@ -384,8 +386,9 @@
 // another wallpaper after the screen is locked).
 TEST_F(PowerEventObserverTest,
        DisplaysNotReadyForSuspendUntilWallpaperAnimationEnds) {
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
-  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
+  ASSERT_EQ(0, client->num_pending_suspend_readiness_callbacks());
 
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
@@ -423,19 +426,20 @@
   // and displays get suspended.
   test_api.CompositeFrame(compositor);
   observer_->SuspendImminent(power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
 // Tests that animated wallpaper changes will be finished immediately when
 // suspend starts (if the screen was locked when suspend started).
 TEST_F(PowerEventObserverTest, EndWallpaperAnimationOnSuspendWhileLocked) {
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
-  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
+  ASSERT_EQ(0, client->num_pending_suspend_readiness_callbacks());
 
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
@@ -464,19 +468,20 @@
   // Expect that two compositing cycles are completed before suspend continues,
   // and displays get suspended.
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
 // Tests that animated wallpaper changes will be finished immediately when
 // suspend starts (if the screen lock started before suspend).
 TEST_F(PowerEventObserverTest, EndWallpaperAnimationOnSuspendWhileLocking) {
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
-  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
+  ASSERT_EQ(0, client->num_pending_suspend_readiness_callbacks());
 
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
@@ -506,19 +511,20 @@
   // Expect that two compositing cycles are completed before suspend continues,
   // and displays get suspended.
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
 // Tests that animated wallpaper changes will be finished immediately when
 // suspend starts and causes a screen lock.
 TEST_F(PowerEventObserverTest, EndWallpaperAnimationAfterLockDueToSuspend) {
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
-  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
+  ASSERT_EQ(0, client->num_pending_suspend_readiness_callbacks());
 
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
@@ -544,19 +550,20 @@
   // Expect that two compositing cycles are completed before suspend continues,
   // and displays get suspended.
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(1, GetNumVisibleCompositors());
 
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
 // Tests that removing a display while power event observer is waiting for the
 // wallpaper animation does not cause suspend to hang.
 TEST_F(PowerEventObserverTest, DisplayRemovedDuringWallpaperAnimation) {
-  chromeos::PowerManagerClient* client = chromeos::PowerManagerClient::Get();
-  ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  chromeos::FakePowerManagerClient* client =
+      chromeos::FakePowerManagerClient::Get();
+  ASSERT_EQ(0, client->num_pending_suspend_readiness_callbacks());
 
   SetCanLockScreen(true);
   SetShouldLockScreenAutomatically(true);
@@ -589,7 +596,7 @@
   // and displays get suspended.
   test_api.CompositeFrame(compositor);
   test_api.CompositeFrame(compositor);
-  EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, client->num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(0, GetNumVisibleCompositors());
 }
 
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index 6a6cda78a..67eee8c 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -568,21 +568,26 @@
       return;
   }
 
-  if (!window_state->IsMinimized()) {
-    if (IsMinimizedWindowStateType(previous_state_type) ||
-        window_state->IsFullscreen() || window_state->IsPinned()) {
-      window_state->SetBoundsDirect(bounds_in_parent);
-    } else if (window_state->IsMaximized() ||
-               IsMaximizedOrFullscreenOrPinnedWindowStateType(
-                   previous_state_type)) {
-      window_state->SetBoundsDirectCrossFade(bounds_in_parent);
-    } else if (window_state->is_dragged()) {
-      // SetBoundsDirectAnimated does not work when the window gets reparented.
-      // TODO(oshima): Consider fixing it and reenable the animation.
-      window_state->SetBoundsDirect(bounds_in_parent);
-    } else {
-      window_state->SetBoundsDirectAnimated(bounds_in_parent);
-    }
+  if (window_state->IsMinimized())
+    return;
+
+  if (IsMinimizedWindowStateType(previous_state_type) ||
+      window_state->IsFullscreen() || window_state->IsPinned() ||
+      enter_animation_type() == IMMEDIATE) {
+    window_state->SetBoundsDirect(bounds_in_parent);
+    // Reset the |enter_animation_type_| to DEFAULT if it is IMMEDIATE, which is
+    // set for non-top windows when entering clamshell mode.
+    set_enter_animation_type(DEFAULT);
+  } else if (window_state->IsMaximized() ||
+             IsMaximizedOrFullscreenOrPinnedWindowStateType(
+                 previous_state_type)) {
+    window_state->SetBoundsDirectCrossFade(bounds_in_parent);
+  } else if (window_state->is_dragged()) {
+    // SetBoundsDirectAnimated does not work when the window gets reparented.
+    // TODO(oshima): Consider fixing it and re-enable the animation.
+    window_state->SetBoundsDirect(bounds_in_parent);
+  } else {
+    window_state->SetBoundsDirectAnimated(bounds_in_parent);
   }
 }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 61b3ed3..9b16b5b 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -17,6 +17,7 @@
 #include "ash/wm/tablet_mode/internal_input_devices_event_blocker.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
+#include "ash/wm/window_state.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index 24429df0..d43315e 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -31,11 +31,15 @@
 
 namespace {
 
-// Exits overview mode if it is currently active.
-void CancelOverview() {
+// Exits overview mode if it is currently active. Returns true if overview is
+// active before cancelling it.
+bool CancelOverview() {
   OverviewController* controller = Shell::Get()->overview_controller();
-  if (controller->IsSelecting())
+  if (controller->IsSelecting()) {
     controller->OnSelectionEnded();
+    return true;
+  }
+  return false;
 }
 
 }  // namespace
@@ -44,7 +48,7 @@
   // Overview mode needs to be ended before exiting tablet mode to prevent
   // transforming windows which are currently in
   // overview: http://crbug.com/366605
-  CancelOverview();
+  const bool was_in_overview = CancelOverview();
   for (aura::Window* window : added_windows_)
     window->RemoveObserver(this);
   added_windows_.clear();
@@ -54,7 +58,7 @@
   Shell::Get()->split_view_controller()->RemoveObserver(this);
   EnableBackdropBehindTopWindowOnEachDisplay(false);
   RemoveWindowCreationObservers();
-  ArrangeWindowsForDesktopMode();
+  ArrangeWindowsForDesktopMode(was_in_overview);
 }
 
 int TabletModeWindowManager::GetNumberOfManagedWindows() {
@@ -377,9 +381,11 @@
   }
 }
 
-void TabletModeWindowManager::ArrangeWindowsForDesktopMode() {
+void TabletModeWindowManager::ArrangeWindowsForDesktopMode(
+    bool was_in_overview) {
   while (window_state_map_.size())
-    ForgetWindow(window_state_map_.begin()->first, false /* destroyed */);
+    ForgetWindow(window_state_map_.begin()->first, false /* destroyed */,
+                 was_in_overview);
 }
 
 void TabletModeWindowManager::SetDeferBoundsUpdates(aura::Window* window,
@@ -405,7 +411,8 @@
 }
 
 void TabletModeWindowManager::ForgetWindow(aura::Window* window,
-                                           bool destroyed) {
+                                           bool destroyed,
+                                           bool was_in_overview) {
   added_windows_.erase(window);
   window->RemoveObserver(this);
 
@@ -426,7 +433,7 @@
   } else {
     // By telling the state object to revert, it will switch back the old
     // State object and destroy itself, calling WindowStateDestroyed().
-    it->second->LeaveTabletMode(wm::GetWindowState(it->first));
+    it->second->LeaveTabletMode(wm::GetWindowState(it->first), was_in_overview);
     DCHECK(!base::ContainsKey(window_state_map_, window));
   }
 }
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h
index 57d249a..0ceb081 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -14,7 +14,6 @@
 #include "ash/shell_observer.h"
 #include "ash/wm/overview/overview_observer.h"
 #include "ash/wm/splitview/split_view_controller.h"
-#include "ash/wm/window_state.h"
 #include "base/macros.h"
 #include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
@@ -107,7 +106,9 @@
   void ArrangeWindowsForTabletMode();
 
   // Revert all windows to how they were arranged before tablet mode.
-  void ArrangeWindowsForDesktopMode();
+  // |was_in_overview| indicates whether it was in overview before entering
+  // desktop mode.
+  void ArrangeWindowsForDesktopMode(bool was_in_overview = false);
 
   // Set whether to defer bounds updates for |window|. When set to false bounds
   // will be updated as they may be stale.
@@ -121,10 +122,13 @@
                    bool snap = false,
                    bool animate_bounds_on_attach = true);
 
-  // Remove a window from our tracking list. If the window is going to be
-  // destroyed, do not restore its old previous window state object as it will
-  // send unneccessary window state change event.
-  void ForgetWindow(aura::Window* window, bool destroyed);
+  // Remove a window from our tracking list. |was_in_overview| used when
+  // |destroyed| is false to help handle leaving tablet mode. If the window is
+  // going to be destroyed, do not restore its old previous window state object
+  // as it will send unnecessary window state change event.
+  void ForgetWindow(aura::Window* window,
+                    bool destroyed,
+                    bool was_in_overview = false);
 
   // Returns true when the given window should be modified in any way by us.
   bool ShouldHandleWindow(aura::Window* window);
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.cc b/ash/wm/tablet_mode/tablet_mode_window_state.cc
index 1d34045a..27dceb17 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.cc
@@ -180,6 +180,7 @@
   DCHECK(!snap || CanSnapInSplitview(window));
   state_type_on_attach_ =
       snap ? current_state_type_ : GetMaximizedOrCenteredWindowType(state);
+  set_enter_animation_type(IsTopWindow(window) ? DEFAULT : STEP_END);
   old_state_.reset(
       state->SetStateObject(std::unique_ptr<State>(this)).release());
 }
@@ -188,7 +189,14 @@
   creator_->WindowStateDestroyed(window_);
 }
 
-void TabletModeWindowState::LeaveTabletMode(wm::WindowState* window_state) {
+void TabletModeWindowState::LeaveTabletMode(wm::WindowState* window_state,
+                                            bool was_in_overview) {
+  // TODO(minch): Keep the current animation if leaving tablet mode from
+  // overview. Need more investigation for windows' transform animation and
+  // updates bounds animation when overview is active.
+  old_state_->set_enter_animation_type(
+      (was_in_overview || IsTopWindow(window_state->window())) ? DEFAULT
+                                                               : IMMEDIATE);
   // Note: When we return we will destroy ourselves with the |our_reference|.
   std::unique_ptr<wm::WindowState::State> our_reference =
       window_state->SetStateObject(std::move(old_state_));
@@ -459,9 +467,12 @@
     if (!window_state->window()->IsVisible() || !animated) {
       window_state->SetBoundsDirect(bounds_in_parent);
     } else {
-      if (use_zero_animation_type_) {
+      if (use_zero_animation_type_ || enter_animation_type() == STEP_END) {
         window_state->SetBoundsDirectCrossFade(bounds_in_parent,
                                                gfx::Tween::ZERO);
+        // Reset the |enter_animation_type_| to DEFAULT it if is STEP_END, which
+        // is set for non-top windows when entering tablet mode.
+        set_enter_animation_type(DEFAULT);
         return;
       }
       // If we animate (to) tablet mode, we want to use the cross fade to
@@ -476,4 +487,11 @@
   }
 }
 
+bool TabletModeWindowState::IsTopWindow(aura::Window* window) {
+  MruWindowTracker::WindowList windows =
+      Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
+
+  return !windows.empty() && window == windows[0];
+}
+
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.h b/ash/wm/tablet_mode/tablet_mode_window_state.h
index decd5b6a..7e3eadd2 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.h
@@ -40,7 +40,7 @@
   void set_ignore_wm_events(bool ignore) { ignore_wm_events_ = ignore; }
 
   // Leaves the tablet mode by reverting to previous state object.
-  void LeaveTabletMode(wm::WindowState* window_state);
+  void LeaveTabletMode(wm::WindowState* window_state, bool was_in_overview);
 
   // Sets whether to ignore bounds updates. If set to false, immediately does a
   // bounds update as the current window bounds may no longer be correct.
@@ -87,6 +87,9 @@
   // window state. If |animated| is set we animate the change.
   void UpdateBounds(wm::WindowState* window_state, bool animated);
 
+  // True if |window| is the top window in BuildWindowForCycleList.
+  bool IsTopWindow(aura::Window* window);
+
   // The original state object of the window.
   std::unique_ptr<wm::WindowState::State> old_state_;
 
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 767b37c..cb121fc 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -73,6 +73,11 @@
   // Each subclass defines its own behavior and transition for each WMEvent.
   class State {
    public:
+    // Animation type of updating window bounds for entering current state.
+    // "IMMEDIATE" means update bounds directly without animation. "STEP_END"
+    // means update bounds at the end of the animation.
+    enum EnterAnimationType { DEFAULT, IMMEDIATE, STEP_END };
+
     State() {}
     virtual ~State() {}
 
@@ -97,7 +102,16 @@
     // Called when the window is being destroyed.
     virtual void OnWindowDestroying(WindowState* window_state) {}
 
+    EnterAnimationType enter_animation_type() const {
+      return enter_animation_type_;
+    }
+    void set_enter_animation_type(EnterAnimationType type) {
+      enter_animation_type_ = type;
+    }
+
    private:
+    EnterAnimationType enter_animation_type_ = DEFAULT;
+
     DISALLOW_COPY_AND_ASSIGN(State);
   };
 
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index b0eed08..faa2c4fa 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -890,26 +890,26 @@
   if (!window_state()->CanResize())
     return false;
 
-  aura::Window* root_window = GetTarget()->GetRootWindow();
-  DCHECK(root_window);
-  const std::vector<aura::Window*>& children =
-      root_window->GetChildById(kShellWindowId_DefaultContainer)->children();
-  for (auto i = children.rbegin();
-       i != children.rend() && !matcher.AreEdgesObscured(); ++i) {
-    wm::WindowState* other_state = wm::GetWindowState(*i);
-    if (other_state->window() == GetTarget() ||
-        !other_state->window()->IsVisible() ||
-        !other_state->IsNormalOrSnapped() || !other_state->CanResize()) {
-      continue;
-    }
-    if (matcher.ShouldAttach(other_state->window()->GetBoundsInScreen(),
-                             &magnetism_edge_)) {
-      magnetism_window_ = other_state->window();
-      window_tracker_.Add(magnetism_window_);
-      return true;
+  for (aura::Window* root_window : Shell::Get()->GetAllRootWindows()) {
+    // Test all children from the desktop in each root window.
+    const std::vector<aura::Window*>& children =
+        root_window->GetChildById(kShellWindowId_DefaultContainer)->children();
+    for (auto i = children.rbegin();
+         i != children.rend() && !matcher.AreEdgesObscured(); ++i) {
+      wm::WindowState* other_state = wm::GetWindowState(*i);
+      if (other_state->window() == GetTarget() ||
+          !other_state->window()->IsVisible() ||
+          !other_state->IsNormalOrSnapped() || !other_state->CanResize()) {
+        continue;
+      }
+      if (matcher.ShouldAttach(other_state->window()->GetBoundsInScreen(),
+                               &magnetism_edge_)) {
+        magnetism_window_ = other_state->window();
+        window_tracker_.Add(magnetism_window_);
+        return true;
+      }
     }
   }
-
   return false;
 }
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index c00e7ad..6e98ca4 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -33,6 +33,11 @@
 import("//testing/libfuzzer/fuzzer_test.gni")
 import("//testing/test.gni")
 
+if (is_mac) {
+  # Used to generate fuzzer corpus :base_mach_port_rendezvous_convert_corpus.
+  import("//third_party/protobuf/proto_library.gni")
+}
+
 declare_args() {
   # Indicates if the Location object contains the source code information
   # (file, function, line). False means only the program counter (and currently
@@ -817,6 +822,8 @@
     "task/task_scheduler/task_scheduler.h",
     "task/task_scheduler/task_scheduler_impl.cc",
     "task/task_scheduler/task_scheduler_impl.h",
+    "task/task_scheduler/task_source.cc",
+    "task/task_scheduler/task_source.h",
     "task/task_scheduler/task_tracker.cc",
     "task/task_scheduler/task_tracker.h",
     "task/task_scheduler/tracked_ref.h",
@@ -2541,6 +2548,7 @@
     "task/task_scheduler/sequence_unittest.cc",
     "task/task_scheduler/service_thread_unittest.cc",
     "task/task_scheduler/task_scheduler_impl_unittest.cc",
+    "task/task_scheduler/task_source_unittest.cc",
     "task/task_scheduler/task_tracker_unittest.cc",
     "task/task_scheduler/test_task_factory.cc",
     "task/task_scheduler/test_task_factory.h",
@@ -3398,6 +3406,37 @@
   ]
 }
 
+if (is_mac) {
+  protoc_convert("base_mach_port_rendezvous_convert_corpus") {
+    sources = [
+      "test/data/mach_port_rendezvous_fuzz/dead_name.textproto",
+      "test/data/mach_port_rendezvous_fuzz/send.textproto",
+    ]
+    inputs = [
+      "//testing/libfuzzer/fuzzers/mach/mach_message.proto",
+    ]
+    output_pattern = "$target_gen_dir/base_mach_port_rendezvous_corpus/{{source_name_part}}.binarypb"
+    args = [
+      "--encode=mach_fuzzer.MachMessage",
+      "-I",
+      rebase_path("//testing/libfuzzer/fuzzers/mach"),
+      rebase_path(inputs[0]),
+    ]
+  }
+  fuzzer_test("base_mach_port_rendezvous_fuzzer") {
+    sources = [
+      "mac/mach_port_rendezvous_fuzzer.cc",
+    ]
+    deps = [
+      "//base",
+      "//testing/libfuzzer/fuzzers/mach:converter",
+      "//third_party/libprotobuf-mutator",
+    ]
+    seed_corpus = "$target_gen_dir/base_mach_port_rendezvous_corpus"
+    seed_corpus_deps = [ ":base_mach_port_rendezvous_convert_corpus" ]
+  }
+}
+
 fuzzer_test("string_number_conversions_fuzzer") {
   sources = [
     "strings/string_number_conversions_fuzzer.cc",
diff --git a/base/files/file_util.h b/base/files/file_util.h
index d87fae1..75f0785 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -406,6 +406,16 @@
 BASE_EXPORT bool SetNonBlocking(int fd);
 
 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
+
+// Creates a pipe. Returns true on success, otherwise false.
+// On success, |read_fd| will be set to the fd of the read side, and
+// |write_fd| will be set to the one of write side. If |non_blocking|
+// is set the pipe will be created with O_NONBLOCK|O_CLOEXEC flags set
+// otherwise flag is set to zero (default).
+BASE_EXPORT bool CreatePipe(ScopedFD* read_fd,
+                            ScopedFD* write_fd,
+                            bool non_blocking = false);
+
 // Creates a non-blocking, close-on-exec pipe.
 // This creates a non-blocking pipe that is not intended to be shared with any
 // child process. This will be done atomically if the operating system supports
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index 226e757..17b984e 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -406,6 +406,17 @@
 }
 #endif  // !defined(OS_NACL_NONSFI)
 
+bool CreatePipe(ScopedFD* read_fd, ScopedFD* write_fd, bool non_blocking) {
+  int fds[2];
+  bool created =
+      non_blocking ? CreateLocalNonBlockingPipe(fds) : (0 == pipe(fds));
+  if (!created)
+    return false;
+  read_fd->reset(fds[0]);
+  write_fd->reset(fds[1]);
+  return true;
+}
+
 bool CreateLocalNonBlockingPipe(int fds[2]) {
 #if defined(OS_LINUX)
   return pipe2(fds, O_CLOEXEC | O_NONBLOCK) == 0;
diff --git a/base/mac/mach_port_rendezvous.h b/base/mac/mach_port_rendezvous.h
index 5c1c61c..422b2df30 100644
--- a/base/mac/mach_port_rendezvous.h
+++ b/base/mac/mach_port_rendezvous.h
@@ -102,6 +102,7 @@
 
  private:
   friend class MachPortRendezvousServerTest;
+  friend struct MachPortRendezvousFuzzer;
 
   struct ClientData {
     ClientData(ScopedDispatchObject<dispatch_source_t> exit_watcher,
diff --git a/base/mac/mach_port_rendezvous_fuzzer.cc b/base/mac/mach_port_rendezvous_fuzzer.cc
new file mode 100644
index 0000000..3ab32c15
--- /dev/null
+++ b/base/mac/mach_port_rendezvous_fuzzer.cc
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mach_port_rendezvous.h"
+
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/synchronization/lock.h"
+#include "testing/libfuzzer/fuzzers/mach/mach_message_converter.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+namespace base {
+
+struct MachPortRendezvousFuzzer {
+  MachPortRendezvousFuzzer() {
+    logging::SetMinLogLevel(logging::LOG_FATAL);
+
+    mach_port_t port =
+        base::MachPortRendezvousServer::GetInstance()->server_port_.get();
+    kern_return_t kr = mach_port_insert_right(mach_task_self(), port, port,
+                                              MACH_MSG_TYPE_MAKE_SEND);
+    MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_right";
+
+    server_send_right.reset(port);
+  }
+
+  void ClearClientData() {
+    base::MachPortRendezvousServer::GetInstance()->client_data_.clear();
+  }
+
+  base::mac::ScopedMachSendRight server_send_right;
+};
+
+}  // namespace base
+
+DEFINE_BINARY_PROTO_FUZZER(const mach_fuzzer::MachMessage& message) {
+  static base::MachPortRendezvousFuzzer environment;
+
+  {
+    auto* server = base::MachPortRendezvousServer::GetInstance();
+    base::AutoLock lock(server->GetLock());
+    environment.ClearClientData();
+    server->RegisterPortsForPid(
+        getpid(), {std::make_pair(0xbadbeef, base::MachRendezvousPort{
+                                                 mach_task_self(),
+                                                 MACH_MSG_TYPE_COPY_SEND})});
+  }
+
+  SendMessage(environment.server_send_right.get(), message);
+}
diff --git a/base/task/task_scheduler/platform_native_worker_pool_win.cc b/base/task/task_scheduler/platform_native_worker_pool_win.cc
index af18077..990653f 100644
--- a/base/task/task_scheduler/platform_native_worker_pool_win.cc
+++ b/base/task/task_scheduler/platform_native_worker_pool_win.cc
@@ -82,8 +82,8 @@
   scoped_refptr<Sequence> sequence = worker_pool->GetWork();
   DCHECK(sequence);
 
-  sequence = worker_pool->task_tracker_->RunAndPopNextTask(
-      std::move(sequence.get()), worker_pool);
+  sequence = worker_pool->task_tracker_->RunAndPopNextTask(std::move(sequence),
+                                                           worker_pool);
 
   // Reenqueue sequence and then submit another task to the Windows thread pool.
   //
diff --git a/base/task/task_scheduler/priority_queue.cc b/base/task/task_scheduler/priority_queue.cc
index 7fa78e6..a2176c7a 100644
--- a/base/task/task_scheduler/priority_queue.cc
+++ b/base/task/task_scheduler/priority_queue.cc
@@ -81,12 +81,7 @@
     return;
 
   while (!container_.empty()) {
-    scoped_refptr<Sequence> sequence = PopSequence();
-    Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
-    while (!sequence_transaction.IsEmpty()) {
-      sequence_transaction.TakeTask();
-      sequence_transaction.Pop();
-    }
+    PopSequence()->BeginTransaction().Clear();
   }
 }
 
diff --git a/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc b/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc
index c634f6a8..2113431fd 100644
--- a/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc
+++ b/base/task/task_scheduler/scheduler_single_thread_task_runner_manager.cc
@@ -345,9 +345,9 @@
   void PostTaskNow(Task task) {
     auto sequence_and_transaction =
         SequenceAndTransaction::FromSequence(sequence_);
-    const bool sequence_was_empty =
+    const bool task_source_should_be_queued =
         sequence_and_transaction.transaction.PushTask(std::move(task));
-    if (sequence_was_empty) {
+    if (task_source_should_be_queued) {
       if (outer_->task_tracker_->WillScheduleSequence(
               sequence_and_transaction.transaction, GetDelegate())) {
         GetDelegate()->ReEnqueueSequence(std::move(sequence_and_transaction));
diff --git a/base/task/task_scheduler/scheduler_worker_pool.cc b/base/task/task_scheduler/scheduler_worker_pool.cc
index f37acf93..0eed0df 100644
--- a/base/task/task_scheduler/scheduler_worker_pool.cc
+++ b/base/task/task_scheduler/scheduler_worker_pool.cc
@@ -60,15 +60,10 @@
   // in the past).
   DCHECK_LE(task.delayed_run_time, TimeTicks::Now());
 
-  const bool sequence_was_empty =
+  const bool task_source_should_be_queued =
       sequence_and_transaction.transaction.PushTask(std::move(task));
-  if (sequence_was_empty) {
-    // Try to schedule the Sequence locked by |sequence_transaction| if it was
-    // empty before |task| was inserted into it. Otherwise, one of these must be
-    // true:
-    // - The Sequence is already scheduled, or,
-    // - The pool is running a Task from the Sequence. The pool is expected to
-    //   reschedule the Sequence once it's done running the Task.
+  if (task_source_should_be_queued) {
+    // Try to schedule the Sequence locked by |sequence_transaction|.
     if (task_tracker_->WillScheduleSequence(
             sequence_and_transaction.transaction, this)) {
       OnCanScheduleSequence(std::move(sequence_and_transaction));
diff --git a/base/task/task_scheduler/scheduler_worker_unittest.cc b/base/task/task_scheduler/scheduler_worker_unittest.cc
index a830fdaf..87154602 100644
--- a/base/task/task_scheduler/scheduler_worker_unittest.cc
+++ b/base/task/task_scheduler/scheduler_worker_unittest.cc
@@ -225,7 +225,7 @@
         for (int i = 0; i < outer_->TasksPerSequence() - 1; ++i) {
           EXPECT_TRUE(sequence_transaction.TakeTask());
           EXPECT_EQ(i == outer_->TasksPerSequence() - 2,
-                    sequence_transaction.Pop());
+                    !sequence_transaction.DidRunTask());
         }
 
         // Add |sequence| to |did_run_task_sequences_|.
diff --git a/base/task/task_scheduler/sequence.cc b/base/task/task_scheduler/sequence.cc
index c9c8a8ca..d392a789 100644
--- a/base/task/task_scheduler/sequence.cc
+++ b/base/task/task_scheduler/sequence.cc
@@ -27,21 +27,12 @@
 
 SequenceAndTransaction::~SequenceAndTransaction() = default;
 
-Sequence::Transaction::Transaction(Sequence* sequence) : sequence_(sequence) {
-  sequence_->lock_.Acquire();
-}
+Sequence::Transaction::Transaction(Sequence* sequence)
+    : TaskSource::Transaction(sequence) {}
 
-Sequence::Transaction::Transaction(Sequence::Transaction&& other)
-    : sequence_(other.sequence()) {
-  other.sequence_ = nullptr;
-}
+Sequence::Transaction::Transaction(Sequence::Transaction&& other) = default;
 
-Sequence::Transaction::~Transaction() {
-  if (sequence_) {
-    sequence_->lock_.AssertAcquired();
-    sequence_->lock_.Release();
-  }
-}
+Sequence::Transaction::~Transaction() = default;
 
 bool Sequence::Transaction::PushTask(Task task) {
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
@@ -50,62 +41,49 @@
   DCHECK(task.queue_time.is_null());
   task.queue_time = base::TimeTicks::Now();
 
-  task.task = sequence_->traits_.shutdown_behavior() ==
+  task.task = sequence()->traits_.shutdown_behavior() ==
                       TaskShutdownBehavior::BLOCK_SHUTDOWN
                   ? MakeCriticalClosure(std::move(task.task))
                   : std::move(task.task);
 
-  sequence_->queue_.push(std::move(task));
+  sequence()->queue_.push(std::move(task));
 
-  // Return true if the sequence was empty before the push.
-  return sequence_->queue_.size() == 1;
+  // If the sequence was empty before |task| was inserted into it and the pool
+  // is not running any task from this sequence, it should be queued.
+  // Otherwise, one of these must be true:
+  // - The Sequence is already scheduled, or,
+  // - The pool is running a Task from the Sequence. The pool is expected to
+  //   reschedule the Sequence once it's done running the Task.
+  return sequence()->queue_.size() == 1 && NeedsWorker();
 }
 
-Optional<Task> Sequence::Transaction::TakeTask() {
+Optional<Task> Sequence::TakeTask() {
   DCHECK(!IsEmpty());
-  DCHECK(sequence_->queue_.front().task);
+  DCHECK(queue_.front().task);
 
-  return std::move(sequence_->queue_.front());
+  auto next_task = std::move(queue_.front());
+  queue_.pop();
+  return std::move(next_task);
 }
 
-bool Sequence::Transaction::Pop() {
+SequenceSortKey Sequence::GetSortKey() const {
   DCHECK(!IsEmpty());
-  DCHECK(!sequence_->queue_.front().task);
-  sequence_->queue_.pop();
-  return IsEmpty();
+  return SequenceSortKey(traits_.priority(), queue_.front().queue_time);
 }
 
-SequenceSortKey Sequence::Transaction::GetSortKey() const {
-  DCHECK(!IsEmpty());
-
-  // Save the sequenced time of the next task in the sequence.
-  base::TimeTicks next_task_queue_time = sequence_->queue_.front().queue_time;
-
-  return SequenceSortKey(sequence_->traits_.priority(), next_task_queue_time);
+bool Sequence::IsEmpty() const {
+  return queue_.empty();
 }
 
-bool Sequence::Transaction::IsEmpty() const {
-  return sequence_->queue_.empty();
-}
-
-void Sequence::Transaction::UpdatePriority(TaskPriority priority) {
-  if (FeatureList::IsEnabled(kAllTasksUserBlocking))
-    return;
-  sequence_->traits_.UpdatePriority(priority);
-}
-
-void Sequence::SetHeapHandle(const HeapHandle& handle) {
-  heap_handle_ = handle;
-}
-
-void Sequence::ClearHeapHandle() {
-  heap_handle_ = HeapHandle();
+void Sequence::Clear() {
+  while (!IsEmpty())
+    TakeTask();
 }
 
 Sequence::Sequence(
     const TaskTraits& traits,
     scoped_refptr<SchedulerParallelTaskRunner> scheduler_parallel_task_runner)
-    : traits_(traits),
+    : TaskSource(traits),
       scheduler_parallel_task_runner_(scheduler_parallel_task_runner) {}
 
 Sequence::~Sequence() {
diff --git a/base/task/task_scheduler/sequence.h b/base/task/task_scheduler/sequence.h
index ef4c632..19d5d58 100644
--- a/base/task/task_scheduler/sequence.h
+++ b/base/task/task_scheduler/sequence.h
@@ -10,14 +10,12 @@
 #include "base/base_export.h"
 #include "base/containers/queue.h"
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
 #include "base/optional.h"
 #include "base/sequence_token.h"
-#include "base/task/common/intrusive_heap.h"
-#include "base/task/task_scheduler/scheduler_lock.h"
 #include "base/task/task_scheduler/scheduler_parallel_task_runner.h"
 #include "base/task/task_scheduler/sequence_sort_key.h"
 #include "base/task/task_scheduler/task.h"
+#include "base/task/task_scheduler/task_source.h"
 #include "base/task/task_traits.h"
 #include "base/threading/sequence_local_storage_map.h"
 
@@ -42,58 +40,28 @@
 // the caller that the Sequence should be re-enqueued for execution).
 //
 // This class is thread-safe.
-class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> {
+class BASE_EXPORT Sequence : public TaskSource {
  public:
   // A Transaction can perform multiple operations atomically on a
   // Sequence. While a Transaction is alive, it is guaranteed that nothing
   // else will access the Sequence; the Sequence's lock is held for the
   // lifetime of the Transaction.
-  class BASE_EXPORT Transaction {
+  class BASE_EXPORT Transaction : public TaskSource::Transaction {
    public:
     Transaction(Transaction&& other);
     ~Transaction();
 
     // Adds |task| in a new slot at the end of the Sequence. Returns true if the
-    // Sequence was empty before this operation.
+    // Sequence needs to be enqueued again.
     bool PushTask(Task task);
 
-    // Transfers ownership of the Task in the front slot of the Sequence to the
-    // caller. The front slot of the Sequence will be nullptr and remain until
-    // Pop(). Cannot be called on an empty Sequence or a Sequence whose front
-    // slot is already nullptr.
-    //
-    // Because this method cannot be called on an empty Sequence, the returned
-    // Optional<Task> is never nullptr. An Optional is used in preparation for
-    // the merge between TaskScheduler and TaskQueueManager (in Blink).
-    // https://crbug.com/783309
-    Optional<Task> TakeTask();
-
-    // Removes the front slot of the Sequence. The front slot must have been
-    // emptied by TakeTask() before this is called. Cannot be called on an empty
-    // Sequence. Returns true if the Sequence is empty after this operation.
-    bool Pop();
-
-    // Returns a SequenceSortKey representing the priority of the Sequence.
-    // Cannot be called on an empty Sequence.
-    SequenceSortKey GetSortKey() const;
-
-    bool IsEmpty() const;
-
-    // Sets Sequence priority to |priority|.
-    void UpdatePriority(TaskPriority priority);
-
-    // Returns the traits of all Tasks in the Sequence.
-    TaskTraits traits() const { return sequence_->traits_; }
-
-    Sequence* sequence() const { return sequence_; }
+    Sequence* sequence() const { return static_cast<Sequence*>(task_source()); }
 
    private:
     friend class Sequence;
 
     explicit Transaction(Sequence* sequence);
 
-    Sequence* sequence_;
-
     DISALLOW_COPY_AND_ASSIGN(Transaction);
   };
 
@@ -108,11 +76,6 @@
   // active Sequence::Transaction.
   Transaction BeginTransaction();
 
-  // Support for IntrusiveHeap.
-  void SetHeapHandle(const HeapHandle& handle);
-  void ClearHeapHandle();
-  HeapHandle heap_handle() const { return heap_handle_; }
-
   // Returns a token that uniquely identifies this Sequence.
   const SequenceToken& token() const { return token_; }
 
@@ -120,40 +83,29 @@
     return &sequence_local_storage_;
   }
 
-  // Returns the shutdown behavior of all Tasks in the Sequence. Can be
-  // accessed without a Transaction because it is never mutated.
-  TaskShutdownBehavior shutdown_behavior() const {
-    return traits_.shutdown_behavior();
-  }
-
  private:
-  friend class RefCountedThreadSafe<Sequence>;
-  ~Sequence();
+  ~Sequence() override;
+
+  // TaskSource:
+  Optional<Task> TakeTask() override;
+  SequenceSortKey GetSortKey() const override;
+  bool IsEmpty() const override;
+  void Clear() override;
 
   const SequenceToken token_ = SequenceToken::Create();
 
-  // Synchronizes access to all members.
-  mutable SchedulerLock lock_{UniversalPredecessor()};
-
   // Queue of tasks to execute.
   base::queue<Task> queue_;
 
   // Holds data stored through the SequenceLocalStorageSlot API.
   SequenceLocalStorageMap sequence_local_storage_;
 
-  // The TaskTraits of all Tasks in the Sequence.
-  TaskTraits traits_;
-
   // A reference to the SchedulerParallelTaskRunner that created this Sequence,
   // if any. Used to remove Sequence from the TaskRunner's list of Sequence
   // references when Sequence is deleted.
   const scoped_refptr<SchedulerParallelTaskRunner>
       scheduler_parallel_task_runner_;
 
-  // The Sequence's position in its current PriorityQueue. Access is protected
-  // by the PriorityQueue's lock.
-  HeapHandle heap_handle_;
-
   DISALLOW_COPY_AND_ASSIGN(Sequence);
 };
 
diff --git a/base/task/task_scheduler/sequence_unittest.cc b/base/task/task_scheduler/sequence_unittest.cc
index 928bbb2..4730b7e 100644
--- a/base/task/task_scheduler/sequence_unittest.cc
+++ b/base/task/task_scheduler/sequence_unittest.cc
@@ -64,19 +64,19 @@
   EXPECT_FALSE(task->queue_time.is_null());
 
   // Remove the empty slot. Task B should now be in front.
-  EXPECT_FALSE(sequence_transaction.Pop());
+  EXPECT_TRUE(sequence_transaction.DidRunTask());
   task = sequence_transaction.TakeTask();
   ExpectMockTask(&mock_task_b, &task.value());
   EXPECT_FALSE(task->queue_time.is_null());
 
   // Remove the empty slot. Task C should now be in front.
-  EXPECT_FALSE(sequence_transaction.Pop());
+  EXPECT_TRUE(sequence_transaction.DidRunTask());
   task = sequence_transaction.TakeTask();
   ExpectMockTask(&mock_task_c, &task.value());
   EXPECT_FALSE(task->queue_time.is_null());
 
   // Remove the empty slot.
-  EXPECT_FALSE(sequence_transaction.Pop());
+  EXPECT_TRUE(sequence_transaction.DidRunTask());
 
   // Push task E in the sequence.
   EXPECT_FALSE(sequence_transaction.PushTask(CreateTask(&mock_task_e)));
@@ -87,13 +87,13 @@
   EXPECT_FALSE(task->queue_time.is_null());
 
   // Remove the empty slot. Task E should now be in front.
-  EXPECT_FALSE(sequence_transaction.Pop());
+  EXPECT_TRUE(sequence_transaction.DidRunTask());
   task = sequence_transaction.TakeTask();
   ExpectMockTask(&mock_task_e, &task.value());
   EXPECT_FALSE(task->queue_time.is_null());
 
   // Remove the empty slot. The sequence should now be empty.
-  EXPECT_TRUE(sequence_transaction.Pop());
+  EXPECT_FALSE(sequence_transaction.DidRunTask());
 }
 
 // Verifies the sort key of a BEST_EFFORT sequence that contains one task.
@@ -119,8 +119,8 @@
   EXPECT_EQ(take_best_effort_task->queue_time,
             best_effort_sort_key.next_task_sequenced_time());
 
-  // Pop for correctness.
-  best_effort_sequence_transaction.Pop();
+  // DidRunTask for correctness.
+  best_effort_sequence_transaction.DidRunTask();
 }
 
 // Same as TaskSchedulerSequenceTest.GetSortKeyBestEffort, but with a
@@ -147,18 +147,18 @@
   EXPECT_EQ(take_foreground_task->queue_time,
             foreground_sort_key.next_task_sequenced_time());
 
-  // Pop for correctness.
-  foreground_sequence_transaction.Pop();
+  // DidRunTask for correctness.
+  foreground_sequence_transaction.DidRunTask();
 }
 
-// Verify that a DCHECK fires if Pop() is called on a sequence whose front slot
-// isn't empty.
-TEST(TaskSchedulerSequenceTest, PopNonEmptyFrontSlot) {
+// Verify that a DCHECK fires if DidRunTask() is called on a sequence which
+// didn't return a Task.
+TEST(TaskSchedulerSequenceTest, DidRunTaskWithoutTakeTask) {
   scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(TaskTraits());
   Sequence::Transaction sequence_transaction(sequence->BeginTransaction());
   sequence_transaction.PushTask(Task(FROM_HERE, DoNothing(), TimeDelta()));
 
-  EXPECT_DCHECK_DEATH({ sequence_transaction.Pop(); });
+  EXPECT_DCHECK_DEATH({ sequence_transaction.DidRunTask(); });
 }
 
 // Verify that a DCHECK fires if TakeTask() is called on a sequence whose front
diff --git a/base/task/task_scheduler/task_source.cc b/base/task/task_scheduler/task_source.cc
new file mode 100644
index 0000000..bf01b237
--- /dev/null
+++ b/base/task/task_scheduler/task_source.cc
@@ -0,0 +1,101 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task/task_scheduler/task_source.h"
+
+#include <utility>
+
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/task/task_features.h"
+
+namespace base {
+namespace internal {
+
+TaskSourceAndTransaction::TaskSourceAndTransaction(
+    scoped_refptr<TaskSource> task_source_in,
+    TaskSource::Transaction transaction_in)
+    : task_source(std::move(task_source_in)),
+      transaction(std::move(transaction_in)) {}
+
+TaskSourceAndTransaction::TaskSourceAndTransaction(
+    TaskSourceAndTransaction&& other) = default;
+
+TaskSourceAndTransaction::~TaskSourceAndTransaction() = default;
+
+TaskSource::Transaction::Transaction(TaskSource* task_source)
+    : task_source_(task_source) {
+  task_source->lock_.Acquire();
+}
+
+TaskSource::Transaction::Transaction(TaskSource::Transaction&& other)
+    : task_source_(other.task_source()) {
+  other.task_source_ = nullptr;
+}
+
+TaskSource::Transaction::~Transaction() {
+  if (task_source_) {
+    task_source_->lock_.AssertAcquired();
+    task_source_->lock_.Release();
+  }
+}
+
+Optional<Task> TaskSource::Transaction::TakeTask() {
+  DCHECK(!task_source_->has_worker_);
+  task_source_->has_worker_ = true;
+  return task_source_->TakeTask();
+}
+
+bool TaskSource::Transaction::DidRunTask() {
+  DCHECK(task_source_->has_worker_);
+  task_source_->has_worker_ = false;
+  return !task_source_->IsEmpty();
+}
+
+SequenceSortKey TaskSource::Transaction::GetSortKey() const {
+  return task_source_->GetSortKey();
+}
+
+bool TaskSource::Transaction::NeedsWorker() const {
+  return !task_source_->IsEmpty() && !task_source_->has_worker_;
+}
+
+void TaskSource::Transaction::Clear() {
+  task_source_->Clear();
+}
+
+void TaskSource::Transaction::UpdatePriority(TaskPriority priority) {
+  if (FeatureList::IsEnabled(kAllTasksUserBlocking))
+    return;
+  task_source_->traits_.UpdatePriority(priority);
+}
+
+void TaskSource::SetHeapHandle(const HeapHandle& handle) {
+  heap_handle_ = handle;
+}
+
+void TaskSource::ClearHeapHandle() {
+  heap_handle_ = HeapHandle();
+}
+
+TaskSource::TaskSource(const TaskTraits& traits) : traits_(traits) {}
+
+TaskSource::~TaskSource() = default;
+
+TaskSource::Transaction TaskSource::BeginTransaction() {
+  return Transaction(this);
+}
+
+// static
+TaskSourceAndTransaction TaskSourceAndTransaction::FromTaskSource(
+    scoped_refptr<TaskSource> task_source) {
+  DCHECK(task_source);
+  TaskSource::Transaction transaction(task_source->BeginTransaction());
+  return TaskSourceAndTransaction(std::move(task_source),
+                                  std::move(transaction));
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/task/task_scheduler/task_source.h b/base/task/task_scheduler/task_source.h
new file mode 100644
index 0000000..b31ecabf
--- /dev/null
+++ b/base/task/task_scheduler/task_source.h
@@ -0,0 +1,168 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_TASK_SCHEDULER_TASK_SOURCE_H_
+#define BASE_TASK_TASK_SCHEDULER_TASK_SOURCE_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/task/common/intrusive_heap.h"
+#include "base/task/task_scheduler/scheduler_lock.h"
+#include "base/task/task_scheduler/sequence_sort_key.h"
+#include "base/task/task_scheduler/task.h"
+#include "base/task/task_traits.h"
+
+namespace base {
+namespace internal {
+
+// A TaskSource is a virtual class that provides a series of Tasks that must be
+// executed.
+//
+// In order to execute a task from this TaskSource, a worker should first make
+// sure that it can take up an additional worker with NeedsWorker(). TakeTask()
+// can then be called to access the next Task, and Pop() must be called after
+// the task executed and before accessing any subsequent Tasks. This ensure that
+// the number of workers concurrently running tasks never go over the intended
+// concurrency.
+//
+// In comments below, an "empty TaskSource" is a TaskSource with no Task.
+//
+// Note: there is a known refcounted-ownership cycle in the Scheduler
+// architecture: TaskSource -> Task -> TaskRunner -> TaskSource -> ...
+// This is okay so long as the other owners of TaskSource (PriorityQueue and
+// SchedulerWorker in alternation and
+// SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetWork()
+// temporarily) keep running it (and taking Tasks from it as a result). A
+// dangling reference cycle would only occur should they release their reference
+// to it while it's not empty. In other words, it is only correct for them to
+// release it after IsEmpty() returns true.
+// TODO(etiennep): Break ownership cycle by moving TaskRunner reference from
+// Task to TaskSource.
+//
+// This class is thread-safe.
+class BASE_EXPORT TaskSource : public RefCountedThreadSafe<TaskSource> {
+ public:
+  // A Transaction can perform multiple operations atomically on a
+  // TaskSource. While a Transaction is alive, it is guaranteed that nothing
+  // else will access the TaskSource; the TaskSource's lock is held for the
+  // lifetime of the Transaction.
+  class BASE_EXPORT Transaction {
+   public:
+    Transaction(Transaction&& other);
+    ~Transaction();
+
+    // Returns the next task to run from this TaskSource. This should be called
+    // only if NeedsWorker returns true. Cannot be called on an empty
+    // TaskSource.
+    //
+    // Because this method cannot be called on an empty TaskSource, the returned
+    // Optional<Task> is never nullptr. An Optional is used in preparation for
+    // the merge between TaskScheduler and TaskQueueManager (in Blink).
+    // https://crbug.com/783309
+    Optional<Task> TakeTask();
+
+    // Must be called once the task was executed. Cannot be called on an empty
+    // TaskSource. Returns true if the TaskSource should be queued after this
+    // operation.
+    bool DidRunTask();
+
+    // Returns a SequenceSortKey representing the priority of the TaskSource.
+    // Cannot be called on an empty TaskSource.
+    SequenceSortKey GetSortKey() const;
+
+    // Returns true if additional workers should run tasks from this TaskSource.
+    bool NeedsWorker() const;
+
+    // Sets TaskSource priority to |priority|.
+    void UpdatePriority(TaskPriority priority);
+
+    // Deletes all tasks contained in this TaskSource.
+    void Clear();
+
+    // Returns the traits of all Tasks in the TaskSource.
+    TaskTraits traits() const { return task_source_->traits_; }
+
+    TaskSource* task_source() const { return task_source_; }
+
+   protected:
+    explicit Transaction(TaskSource* task_source);
+
+   private:
+    friend class TaskSource;
+
+    TaskSource* task_source_;
+
+    DISALLOW_COPY_AND_ASSIGN(Transaction);
+  };
+
+  // |traits| is metadata that applies to all Tasks in the TaskSource.
+  explicit TaskSource(const TaskTraits& traits);
+
+  // Begins a Transaction. This method cannot be called on a thread which has an
+  // active TaskSource::Transaction.
+  Transaction BeginTransaction();
+
+  // Support for IntrusiveHeap.
+  void SetHeapHandle(const HeapHandle& handle);
+  void ClearHeapHandle();
+  HeapHandle heap_handle() const { return heap_handle_; }
+
+  // Returns the shutdown behavior of all Tasks in the TaskSource. Can be
+  // accessed without a Transaction because it is never mutated.
+  TaskShutdownBehavior shutdown_behavior() const {
+    return traits_.shutdown_behavior();
+  }
+
+ protected:
+  virtual ~TaskSource();
+
+  virtual Optional<Task> TakeTask() = 0;
+
+  virtual SequenceSortKey GetSortKey() const = 0;
+
+  virtual bool IsEmpty() const = 0;
+
+  virtual void Clear() = 0;
+
+  // Sets TaskSource priority to |priority|.
+  void UpdatePriority(TaskPriority priority);
+
+  // The TaskTraits of all Tasks in the TaskSource.
+  TaskTraits traits_;
+
+ private:
+  friend class RefCountedThreadSafe<TaskSource>;
+
+  // Synchronizes access to all members.
+  mutable SchedulerLock lock_{UniversalPredecessor()};
+
+  // The TaskSource's position in its current PriorityQueue. Access is protected
+  // by the PriorityQueue's lock.
+  HeapHandle heap_handle_;
+
+  // TODO(etiennep): Add support for TaskSources with more than one worker.
+  bool has_worker_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskSource);
+};
+
+struct BASE_EXPORT TaskSourceAndTransaction {
+  scoped_refptr<TaskSource> task_source;
+  TaskSource::Transaction transaction;
+  TaskSourceAndTransaction(scoped_refptr<TaskSource> task_source_in,
+                           TaskSource::Transaction transaction_in);
+  TaskSourceAndTransaction(TaskSourceAndTransaction&& other);
+  static TaskSourceAndTransaction FromTaskSource(
+      scoped_refptr<TaskSource> task_source);
+  ~TaskSourceAndTransaction();
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_TASK_SCHEDULER_TASK_SOURCE_H_
diff --git a/base/task/task_scheduler/task_source_unittest.cc b/base/task/task_scheduler/task_source_unittest.cc
new file mode 100644
index 0000000..17b6ade
--- /dev/null
+++ b/base/task/task_scheduler/task_source_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task/task_scheduler/task_source.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/gtest_util.h"
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+class MockTaskSource : public TaskSource {
+ public:
+  MockTaskSource(TaskTraits traits) : TaskSource(traits) {}
+
+ protected:
+  MOCK_METHOD0(TakeTask, base::Optional<Task>());
+  MOCK_CONST_METHOD0(GetSortKey, SequenceSortKey());
+  MOCK_CONST_METHOD0(IsEmpty, bool());
+  MOCK_METHOD0(Clear, void());
+
+ private:
+  ~MockTaskSource() override = default;
+};
+
+}  // namespace
+
+TEST(TaskSchedulerTaskSourceTest, TakeTaskDidRunTask) {
+  scoped_refptr<MockTaskSource> task_source =
+      MakeRefCounted<MockTaskSource>(TaskTraits(TaskPriority::BEST_EFFORT));
+  TaskSource::Transaction task_source_transaction(
+      task_source->BeginTransaction());
+
+  EXPECT_TRUE(task_source_transaction.NeedsWorker());
+  task_source_transaction.TakeTask();
+  EXPECT_FALSE(task_source_transaction.NeedsWorker());
+
+  EXPECT_TRUE(task_source_transaction.DidRunTask());
+  EXPECT_TRUE(task_source_transaction.NeedsWorker());
+
+  task_source_transaction.TakeTask();
+  EXPECT_TRUE(task_source_transaction.DidRunTask());
+}
+
+TEST(TaskSchedulerTaskSourceTest, InvalidTakeTask) {
+  scoped_refptr<MockTaskSource> task_source =
+      MakeRefCounted<MockTaskSource>(TaskTraits(TaskPriority::BEST_EFFORT));
+  TaskSource::Transaction task_source_transaction(
+      task_source->BeginTransaction());
+
+  task_source_transaction.TakeTask();
+  // Can not be called before DidRunTask().
+  EXPECT_DCHECK_DEATH(task_source_transaction.TakeTask());
+}
+
+TEST(TaskSchedulerTaskSourceTest, InvalidDidRunTask) {
+  scoped_refptr<MockTaskSource> task_source =
+      MakeRefCounted<MockTaskSource>(TaskTraits(TaskPriority::BEST_EFFORT));
+  TaskSource::Transaction task_source_transaction(
+      task_source->BeginTransaction());
+
+  // Can not be called before TakeTask().
+  EXPECT_DCHECK_DEATH(task_source_transaction.DidRunTask());
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/task/task_scheduler/task_tracker.cc b/base/task/task_scheduler/task_tracker.cc
index b0b0f92..588328c 100644
--- a/base/task/task_scheduler/task_tracker.cc
+++ b/base/task/task_scheduler/task_tracker.cc
@@ -497,11 +497,12 @@
   if (task->delayed_run_time.is_null())
     DecrementNumIncompleteUndelayedTasks();
 
-  const bool sequence_is_empty_after_pop = sequence->BeginTransaction().Pop();
+  const bool sequence_must_be_queued =
+      sequence->BeginTransaction().DidRunTask();
 
-  // Never reschedule a Sequence emptied by Pop(). The contract is such that
-  // next poster to make it non-empty is responsible to schedule it.
-  if (sequence_is_empty_after_pop)
+  // Never reschedule a Sequence empty after DidRunTask(). The contract is such
+  // that next poster to make it non-empty is responsible to schedule it.
+  if (!sequence_must_be_queued)
     sequence = nullptr;
 
   // Allow |sequence| to be rescheduled only if its next task is set to run
diff --git a/base/test/data/mach_port_rendezvous_fuzz/dead_name.textproto b/base/test/data/mach_port_rendezvous_fuzz/dead_name.textproto
new file mode 100644
index 0000000..940775a4
--- /dev/null
+++ b/base/test/data/mach_port_rendezvous_fuzz/dead_name.textproto
@@ -0,0 +1,3 @@
+local_port: DEAD_NAME
+id: 0x6d727a76
+include_body_if_not_complex: false
diff --git a/base/test/data/mach_port_rendezvous_fuzz/send.textproto b/base/test/data/mach_port_rendezvous_fuzz/send.textproto
new file mode 100644
index 0000000..32d35fb
--- /dev/null
+++ b/base/test/data/mach_port_rendezvous_fuzz/send.textproto
@@ -0,0 +1,3 @@
+local_port: SEND
+id: 0x6d727a76
+include_body_if_not_complex: false
diff --git a/build/android/devil_chromium.json b/build/android/devil_chromium.json
index c75ae94..6cb7608c 100644
--- a/build/android/devil_chromium.json
+++ b/build/android/devil_chromium.json
@@ -5,7 +5,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/27.0.3/aapt"
+            "../../third_party/android_sdk/public/build-tools/27.0.3/aapt"
           ]
         }
       }
@@ -14,7 +14,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/platform-tools/adb"
+            "../../third_party/android_sdk/public/platform-tools/adb"
           ]
         }
       }
@@ -23,7 +23,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/27.0.3/lib64/libc++.so"
+            "../../third_party/android_sdk/public/build-tools/27.0.3/lib64/libc++.so"
           ]
         }
       }
@@ -32,7 +32,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk"
+            "../../third_party/android_sdk/public"
           ]
         }
       }
@@ -41,7 +41,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/27.0.3/dexdump"
+            "../../third_party/android_sdk/public/build-tools/27.0.3/dexdump"
           ]
         }
       }
@@ -50,7 +50,7 @@
       "file_info": {
         "linux2_x86_64": {
           "local_paths": [
-            "../../third_party/android_tools/sdk/build-tools/27.0.3/split-select"
+            "../../third_party/android_sdk/public/build-tools/27.0.3/split-select"
           ]
         }
       }
diff --git a/build/android/docs/build_config.md b/build/android/docs/build_config.md
index 797587f..74af651 100644
--- a/build/android/docs/build_config.md
+++ b/build/android/docs/build_config.md
@@ -126,8 +126,8 @@
 ```sh
 python ../../build/android/gyp/process_resources.py \
     --depfile gen/ui/android/ui_java_resources_1.d \
-    --android-sdk-jar ../../third_party/android_tools/sdk/platforms/android-27/android.jar \
-    --aapt-path ../../third_party/android_tools/sdk/build-tools/27.0.3/aapt \
+    --android-sdk-jar ../../third_party/android_sdk/public/platforms/android-28/android.jar \
+    --aapt-path ../../third_party/android_sdk/public/build-tools/27.0.3/aapt \
     --dependencies-res-zips=@FileArg\(gen/ui/android/ui_java_resources.build_config:resources:dependency_zips\) \
     --extra-res-packages=@FileArg\(gen/ui/android/ui_java_resources.build_config:resources:extra_package_names\) \
     --extra-r-text-files=@FileArg\(gen/ui/android/ui_java_resources.build_config:resources:extra_r_text_files\) \
diff --git a/build/android/download_doclava.py b/build/android/download_doclava.py
index f9f9ea2..f9b3af63 100755
--- a/build/android/download_doclava.py
+++ b/build/android/download_doclava.py
@@ -11,20 +11,12 @@
 import sys
 
 
-# Its existence signifies an Android checkout.
-ANDROID_ONLY_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
-                                os.pardir, os.pardir,
-                                'third_party', 'android_tools')
-
-
 def main():
-  # Some Windows bots inadvertently have third_party/android_tools installed,
+  # Some Windows bots inadvertently have third_party/android_sdk installed,
   # but are unable to run download_from_google_storage because depot_tools
   # is not in their path, so avoid failure and bail.
   if sys.platform == 'win32':
     return 0
-  if not os.path.exists(ANDROID_ONLY_DIR):
-    return 0
   subprocess.check_call([
       'download_from_google_storage',
       '--no_resume',
diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh
index 022a78686..ea066d29 100755
--- a/build/android/envsetup.sh
+++ b/build/android/envsetup.sh
@@ -18,7 +18,7 @@
   local SCRIPT_PATH="$1"
   local SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
   local CHROME_SRC="$(readlink -f "${SCRIPT_DIR}/../../")"
-  local ANDROID_SDK_ROOT="${CHROME_SRC}/third_party/android_tools/sdk/"
+  local ANDROID_SDK_ROOT="${CHROME_SRC}/third_party/android_sdk/public/"
 
   export PATH=$PATH:${ANDROID_SDK_ROOT}/platform-tools
   export PATH=$PATH:${ANDROID_SDK_ROOT}/tools/
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index a8ec796..314b1e97 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -233,6 +233,8 @@
     <ignore regexp="Static interface  method requires API level 24"/>
     <!-- 1 This is for testonly target android_support_chromium_java. -->
     <ignore regexp="third_party/android_tools/sdk/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"/>
+    <!-- 1 This is for testonly target android_support_chromium_java in android_sdk. -->
+    <ignore regexp="third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java"/>
     <!-- Endnote: Please specify number of suppressions when adding more -->
   </issue>
   <!-- This warning just adds a lot of false positives. -->
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index b98f2a3..901a942 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -102,8 +102,8 @@
 
 ANDROID_SDK_VERSION = version_codes.OREO_MR1
 ANDROID_SDK_BUILD_TOOLS_VERSION = '27.0.3'
-ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
-                                'third_party', 'android_tools', 'sdk')
+ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'android_sdk',
+                                'public')
 ANDROID_SDK_TOOLS = os.path.join(ANDROID_SDK_ROOT,
                                  'build-tools', ANDROID_SDK_BUILD_TOOLS_VERSION)
 ANDROID_NDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
diff --git a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
index 85a92bb3..baa93132 100644
--- a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
+++ b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
@@ -53,25 +53,28 @@
             + "(?:.*L%C;.*)|"
             // E.g.: END SomeTestClass#someMethod
             + "(?:.*?%c#%m.*?)|"
-            // E.g.: The member "Foo.bar"
-            // E.g.: The class "Foobar"
-            + "(?:.*?\"%c\\.%m\".*)|"
-            + "(?:.*?\"%c\".*)|"
             // Special-case for a common junit logcat message:
             // E.g.: java.lang.NoClassDefFoundError: SomeFrameworkClass in isTestClass for Foo
             + "(?:.* isTestClass for %c)|"
             // E.g.: Caused by: java.lang.RuntimeException: Intentional Java Crash
             + "(?:Caused by: %c:.*)|"
-            // E.g.: java.lang.RuntimeException: Intentional Java Crash
-            + "(?:%c:.*)|"
-            // All lines that end with a class / class+method:
+            // Quoted values and lines that end with a class / class+method:
             // E.g.: The class: Foo
             // E.g.: INSTRUMENTATION_STATUS: class=Foo
             // E.g.: NoClassDefFoundError: SomeFrameworkClass in isTestClass for Foo
             // E.g.: Could not find class 'SomeFrameworkClass', referenced from method Foo.bar
             // E.g.: Could not find method SomeFrameworkMethod, referenced from method Foo.bar
-            + "(?:.*(?:=|:\\s*|\\b)%c\\.%m)|"
-            + "(?:.*(?:=|:\\s*|\\b)%c)"
+            // E.g.: The member "Foo.bar"
+            // E.g.: The class "Foobar"
+            // Be careful about matching %c without %m since language tags look like class names.
+            + "(?:.*?%c\\.%m)|"
+            + "(?:.*?\"%c\\.%m\".*)|"
+            + "(?:.*\\b(?:[Cc]lass|[Tt]ype)\\b.*?\"%c\".*)|"
+            + "(?:.*\\b(?:[Cc]lass|[Tt]ype)\\b.*?%c)|"
+            // E.g.: java.lang.RuntimeException: Intentional Java Crash
+            + "(?:%c:.*)|"
+            // See if entire line matches a class name (e.g. for manual deobfuscation)
+            + "(?:%c)"
             + ")";
 
     private static void usage() {
diff --git a/build/android/stacktrace/java_deobfuscate_test.py b/build/android/stacktrace/java_deobfuscate_test.py
index 59edcd2..98b66dd 100755
--- a/build/android/stacktrace/java_deobfuscate_test.py
+++ b/build/android/stacktrace/java_deobfuscate_test.py
@@ -34,66 +34,68 @@
 """
 
 TEST_DATA = [
-    "FOO",
-    "FOO.bar",
-    "Here is a FOO",
-    "Here is a FOO baz",
-    "Here is a \"FOO\" baz",
-    "Here is a \"FOO.bar\" baz",
-    "Here it is: FOO",
-    "Here it is: FOO.bar",
-    "SomeError: SomeFrameworkClass in isTestClass for FOO",
-    "Here is a FOO.bar",
-    "Here is a FOO.bar baz",
-    "END FOO#bar",
-    "new-instance 3810 (LSome/Framework/Class;) in LFOO;",
-    "FOO: Error message",
-    "Caused by: FOO: Error message",
-    "\tat FOO.bar(PG:1)",
-    "\t at\t FOO.bar\t (\t PG:\t 1\t )",
-    ("Unable to start activity ComponentInfo{garbage.in/here.test}:"
-     " java.lang.NullPointerException: Attempt to invoke interface method 'void"
-     " FOO.bar(int,android.os.Bundle)' on a null object reference"),
-    ("Caused by: java.lang.NullPointerException: Attempt to read from field"
-     " 'int[] FOO.a' on a null object reference"),
-    "java.lang.VerifyError: FOO",
+    '',
+    'FOO',
+    'FOO.bar',
+    'Here is a FOO',
+    'Here is a class FOO',
+    'Here is a class FOO baz',
+    'Here is a "FOO" baz',
+    'Here is a type "FOO" baz',
+    'Here is a "FOO.bar" baz',
+    'SomeError: SomeFrameworkClass in isTestClass for FOO',
+    'Here is a FOO.bar',
+    'Here is a FOO.bar baz',
+    'END FOO#bar',
+    'new-instance 3810 (LSome/Framework/Class;) in LFOO;',
+    'FOO: Error message',
+    'Caused by: FOO: Error message',
+    '\tat FOO.bar(PG:1)',
+    '\t at\t FOO.bar\t (\t PG:\t 1\t )',
+    ('Unable to start activity ComponentInfo{garbage.in/here.test}:'
+     ' java.lang.NullPointerException: Attempt to invoke interface method'
+     ' \'void FOO.bar(int,android.os.Bundle)\' on a null object reference'),
+    ('Caused by: java.lang.NullPointerException: Attempt to read from field'
+     ' \'int[] FOO.a\' on a null object reference'),
+    'java.lang.VerifyError: FOO',
     ('java.lang.NoSuchFieldError: No instance field a of type '
      'Ljava/lang/Class; in class LFOO;'),
-    "NOTFOO: Object of type FOO was not destroyed...",
+    'NOTFOO: Object of type FOO was not destroyed...',
 ]
 
 EXPECTED_OUTPUT = [
-    "this.was.Deobfuscated",
-    "this.was.Deobfuscated.someMethod",
-    "Here is a this.was.Deobfuscated",
-    "Here is a FOO baz",
-    "Here is a \"this.was.Deobfuscated\" baz",
-    "Here is a \"this.was.Deobfuscated.someMethod\" baz",
-    "Here it is: this.was.Deobfuscated",
-    "Here it is: this.was.Deobfuscated.someMethod",
-    "SomeError: SomeFrameworkClass in isTestClass for this.was.Deobfuscated",
-    "Here is a this.was.Deobfuscated.someMethod",
-    "Here is a FOO.bar baz",
-    "END this.was.Deobfuscated#someMethod",
-    "new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated;",
-    "this.was.Deobfuscated: Error message",
-    "Caused by: this.was.Deobfuscated: Error message",
-    "\tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65)",
-    ("\t at\t this.was.Deobfuscated.someMethod\t "
-     "(\t Deobfuscated.java:\t 65\t )"),
-    ("Unable to start activity ComponentInfo{garbage.in/here.test}:"
-     " java.lang.NullPointerException: Attempt to invoke interface method"
-     " 'void this.was.Deobfuscated.someMethod(int,android.os.Bundle)' on a null"
-     " object reference"),
-    ("Caused by: java.lang.NullPointerException: Attempt to read from field"
-     " 'int[] this.was.Deobfuscated.mFontFamily' on a null object reference"),
+    '',
+    'this.was.Deobfuscated',
+    'this.was.Deobfuscated.someMethod',
+    'Here is a FOO',
+    'Here is a class this.was.Deobfuscated',
+    'Here is a class FOO baz',
+    'Here is a "FOO" baz',
+    'Here is a type "this.was.Deobfuscated" baz',
+    'Here is a "this.was.Deobfuscated.someMethod" baz',
+    'SomeError: SomeFrameworkClass in isTestClass for this.was.Deobfuscated',
+    'Here is a this.was.Deobfuscated.someMethod',
+    'Here is a FOO.bar baz',
+    'END this.was.Deobfuscated#someMethod',
+    'new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated;',
+    'this.was.Deobfuscated: Error message',
+    'Caused by: this.was.Deobfuscated: Error message',
+    '\tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65)',
+    ('\t at\t this.was.Deobfuscated.someMethod\t '
+     '(\t Deobfuscated.java:\t 65\t )'),
+    ('Unable to start activity ComponentInfo{garbage.in/here.test}:'
+     ' java.lang.NullPointerException: Attempt to invoke interface method'
+     ' \'void this.was.Deobfuscated.someMethod(int,android.os.Bundle)\' on a'
+     ' null object reference'),
+    ('Caused by: java.lang.NullPointerException: Attempt to read from field'
+     ' \'int[] this.was.Deobfuscated.mFontFamily\' on a null object reference'),
     'java.lang.VerifyError: this.was.Deobfuscated',
     ('java.lang.NoSuchFieldError: No instance field mFontFamily of type '
      'Ljava/lang/Class; in class Lthis/was/Deobfuscated;'),
-    "NOTFOO: Object of type this.was.Deobfuscated was not destroyed...",
+    'NOTFOO: Object of type this.was.Deobfuscated was not destroyed...',
 ]
-TEST_DATA = [s + "\n" for s in TEST_DATA]
-EXPECTED_OUTPUT = [s + "\n" for s in EXPECTED_OUTPUT]
+TEST_DATA = [s + '\n' for s in TEST_DATA]
+EXPECTED_OUTPUT = [s + '\n' for s in EXPECTED_OUTPUT]
 
 
 class JavaDeobfuscateTest(unittest.TestCase):
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 26b6287..24169e5 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -79,7 +79,7 @@
   }
 
   if (android_sdk_release == "o_mr1") {
-    default_android_sdk_root = "//third_party/android_tools/sdk"
+    default_android_sdk_root = "//third_party/android_sdk/public"
     default_android_sdk_version = 27
     default_android_sdk_build_tools_version = "27.0.3"
     default_android_sdk_tools_version_suffix = "-26.0.0-dev"
@@ -87,7 +87,7 @@
   }
 
   if (android_sdk_release == "p") {
-    default_android_sdk_root = "//third_party/android_tools/sdk"
+    default_android_sdk_root = "//third_party/android_sdk/public"
     default_android_sdk_version = 28
     default_android_sdk_build_tools_version = "27.0.3"
     default_android_sdk_tools_version_suffix = "-26.0.0-dev"
@@ -97,7 +97,7 @@
   if (!defined(default_lint_android_sdk_root)) {
     # Purposefully repeated so that downstream can change
     # default_android_sdk_root without changing lint version.
-    default_lint_android_sdk_root = "//third_party/android_tools/sdk"
+    default_lint_android_sdk_root = "//third_party/android_sdk/public"
     default_lint_android_sdk_version = 26
   }
 
@@ -105,7 +105,7 @@
     # Purposefully repeated so that downstream can change
     # default_android_sdk_root without changing where we load the SDK extras
     # from. (Google Play services, etc.)
-    default_extras_android_sdk_root = "//third_party/android_tools/sdk"
+    default_extras_android_sdk_root = "//third_party/android_sdk/public"
   }
 
   if (!defined(default_android_keystore_path)) {
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index f1ec6e5..cd1e130 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1090,7 +1090,7 @@
       if (emma_coverage) {
         args += [
           "--classpath",
-          rebase_path("//third_party/android_tools/sdk/tools/lib/emma.jar",
+          rebase_path("//third_party/android_sdk/public/tools/lib/emma.jar",
                       root_build_dir),
           "--noverify",
         ]
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 126d5e2c..b9fd23d 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3e59cb1001cf58cc723a415cdf9ec1b3f1160c28
\ No newline at end of file
+032385d9bec7a2dcb3ab84ec3509a6b140b8095f
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index c0f51f6..0cb4b16 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-436c2e2b3588138fe1b5c96950827450aacd0c86
\ No newline at end of file
+857487bc12b87a5958e5fb243cdf83ad9657fdcd
\ No newline at end of file
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
index bfc217f..79dce34 100644
--- a/build/secondary/third_party/android_tools/BUILD.gn
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -81,13 +81,13 @@
 
   android_library("android_support_chromium_java") {
     testonly = true
-    java_files = [ "//third_party/android_tools/sdk/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
+    java_files = [ "//third_party/android_sdk/public/extras/chromium/support/src/org/chromium/android/support/PackageManagerWrapper.java" ]
   }
   android_java_prebuilt("android_gcm_java") {
-    jar_path = "//third_party/android_tools/sdk/extras/google/gcm/gcm-client/dist/gcm.jar"
+    jar_path = "//third_party/android_sdk/public/extras/google/gcm/gcm-client/dist/gcm.jar"
   }
   android_java_prebuilt("emma_device_java") {
-    jar_path = "//third_party/android_tools/sdk/tools/lib/emma_device.jar"
+    jar_path = "//third_party/android_sdk/public/tools/lib/emma_device.jar"
     include_java_resources = true
   }
 
@@ -98,6 +98,6 @@
     requires_android = true
     no_build_hooks = true
     testonly = true
-    jar_path = "//third_party/android_tools/sdk/build-tools/25.0.2/lib/dx.jar"
+    jar_path = "//third_party/android_sdk/public/build-tools/25.0.2/lib/dx.jar"
   }
 }
diff --git a/buildtools/.gitignore b/buildtools/.gitignore
index dea1ab0..98d4676 100644
--- a/buildtools/.gitignore
+++ b/buildtools/.gitignore
@@ -5,9 +5,12 @@
 third_party/libunwind/trunk
 linux64/clang-format
 linux64/gn
+linux64/.versions
 mac/clang-format
 mac/gn
+mac/.versions
 win/clang-format.exe
 win/gn.exe
+win/.versions
 android/doclava/
 android/doclava.tar.gz
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index ced533d..74cf51aa 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -31,7 +31,6 @@
   void SetNeedsRedraw(const gfx::Rect& damage_rect) override {}
   void SetNextCommitWaitsForActivation() override {}
   bool RequestedAnimatePending() override;
-  void NotifyInputThrottledUntilCommit() override {}
   void SetDeferMainFrameUpdate(bool defer_main_frame_update) override {}
   void StartDeferringCommits(base::TimeDelta timeout) override {}
   void StopDeferringCommits() override {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index a220cf1..a8b7ee2 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -650,10 +650,6 @@
   return visible_;
 }
 
-void LayerTreeHost::NotifyInputThrottledUntilCommit() {
-  proxy_->NotifyInputThrottledUntilCommit();
-}
-
 void LayerTreeHost::LayoutAndUpdateLayers() {
   DCHECK(IsSingleThreaded());
   // This function is only valid when not using the scheduler.
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 3ec2655..64fd6b7 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -275,11 +275,6 @@
 
   // Input Handling ---------------------------------------------
 
-  // Notifies the compositor that input from the browser is being throttled till
-  // the next commit. The compositor will prioritize activation of the pending
-  // tree so a commit can be performed.
-  void NotifyInputThrottledUntilCommit();
-
   // Sets the state of the browser controls. (Used for URL bar animations on
   // android).
   void UpdateBrowserControlsState(BrowserControlsState constraints,
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index 305d3c6..b275bc8 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -60,8 +60,6 @@
   // completed yet.
   virtual bool RequestedAnimatePending() = 0;
 
-  virtual void NotifyInputThrottledUntilCommit() = 0;
-
   // Defers LayerTreeHost::BeginMainFrameUpdate and commits until it is
   // reset. It is only supported when using a scheduler.
   virtual void SetDeferMainFrameUpdate(bool defer_main_frame_update) = 0;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 0a49df13..af52ec8 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -62,7 +62,6 @@
       commit_completion_waits_for_activation_(false),
       next_frame_is_newly_committed_frame_(false),
       inside_draw_(false),
-      input_throttled_until_commit_(false),
       task_runner_provider_(task_runner_provider),
       smoothness_priority_expiration_notifier_(
           task_runner_provider->ImplThreadTaskRunner(),
@@ -167,14 +166,6 @@
     scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
 }
 
-void ProxyImpl::SetInputThrottledUntilCommitOnImpl(bool is_throttled) {
-  DCHECK(IsImplThread());
-  if (is_throttled == input_throttled_until_commit_)
-    return;
-  input_throttled_until_commit_ = is_throttled;
-  RenewTreePriority();
-}
-
 void ProxyImpl::SetDeferBeginMainFrameOnImpl(
     bool defer_begin_main_frame) const {
   DCHECK(IsImplThread());
@@ -201,9 +192,6 @@
   DCHECK(IsImplThread());
   DCHECK(scheduler_->CommitPending());
 
-  if (CommitEarlyOutHandledCommit(reason)) {
-    SetInputThrottledUntilCommitOnImpl(false);
-  }
   host_impl_->BeginMainFrameAborted(reason, std::move(swap_promises));
   scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
   scheduler_->BeginMainFrameAborted(reason);
@@ -426,7 +414,7 @@
 
   // New content always takes priority when ui resources have been evicted.
   if (host_impl_->active_tree()->GetDeviceViewport().size().IsEmpty() ||
-      host_impl_->EvictedUIResourcesExist() || input_throttled_until_commit_) {
+      host_impl_->EvictedUIResourcesExist()) {
     // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active
     // tree might be freed. We need to set RequiresHighResToDraw to ensure that
     // high res tiles will be required to activate pending tree.
@@ -632,8 +620,6 @@
   // often a good bit of work to update the tree and prepare the new frame.
   host_impl_->CommitComplete();
 
-  SetInputThrottledUntilCommitOnImpl(false);
-
   next_frame_is_newly_committed_frame_ = true;
 }
 
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 1f6f4be..77e5428 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -44,7 +44,6 @@
   void InitializeMutatorOnImpl(std::unique_ptr<LayerTreeMutator> mutator);
   void InitializePaintWorkletLayerPainterOnImpl(
       std::unique_ptr<PaintWorkletLayerPainter> painter);
-  void SetInputThrottledUntilCommitOnImpl(bool is_throttled);
   void SetDeferBeginMainFrameOnImpl(bool defer_begin_main_frame) const;
   void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect);
   void SetNeedsCommitOnImpl();
@@ -164,7 +163,6 @@
   bool next_frame_is_newly_committed_frame_;
 
   bool inside_draw_;
-  bool input_throttled_until_commit_;
 
   bool send_compositor_frame_ack_;
 
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index c859f043..6cc9a4b 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -443,13 +443,6 @@
   return max_requested_pipeline_stage_ >= ANIMATE_PIPELINE_STAGE;
 }
 
-void ProxyMain::NotifyInputThrottledUntilCommit() {
-  DCHECK(IsMainThread());
-  ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::BindOnce(&ProxyImpl::SetInputThrottledUntilCommitOnImpl,
-                                base::Unretained(proxy_impl_.get()), true));
-}
-
 void ProxyMain::SetDeferMainFrameUpdate(bool defer_main_frame_update) {
   DCHECK(IsMainThread());
   if (defer_main_frame_update_ == defer_main_frame_update)
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h
index 76ee5de..a9e5fb4 100644
--- a/cc/trees/proxy_main.h
+++ b/cc/trees/proxy_main.h
@@ -88,7 +88,6 @@
   void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
   void SetNextCommitWaitsForActivation() override;
   bool RequestedAnimatePending() override;
-  void NotifyInputThrottledUntilCommit() override;
   void SetDeferMainFrameUpdate(bool defer_main_frame_update) override;
   void StartDeferringCommits(base::TimeDelta timeout) override;
   void StopDeferringCommits() override;
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index e0f07ef9..24f95bfb 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -52,7 +52,6 @@
   void SetNeedsRedraw(const gfx::Rect& damage_rect) override;
   void SetNextCommitWaitsForActivation() override;
   bool RequestedAnimatePending() override;
-  void NotifyInputThrottledUntilCommit() override {}
   void SetDeferMainFrameUpdate(bool defer_main_frame_update) override;
   void StartDeferringCommits(base::TimeDelta timeout) override;
   void StopDeferringCommits() override;
diff --git a/chrome/VERSION b/chrome/VERSION
index c173a64..0c26395 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=75
 MINOR=0
-BUILD=3738
+BUILD=3739
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index a983c2cb..06d07be 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1017,6 +1017,38 @@
   }
 }
 
+# TODO(estevenson): Remove this target once these assets move to
+# trichrome_library_apk.
+if (android_64bit_target_cpu) {
+  android_assets("v8_snapshot_secondary_abi_assets") {
+    _secondary_abi_out_dir =
+        get_label_info("//v8($android_secondary_abi_toolchain)", "root_out_dir")
+    sources = [
+      "$_secondary_abi_out_dir/natives_blob.bin",
+    ]
+    if (use_v8_context_snapshot) {
+      renaming_sources = [ "$_secondary_abi_out_dir/v8_context_snapshot.bin" ]
+      renaming_destinations = [ "v8_context_snapshot_32.bin" ]
+    } else {
+      renaming_sources = [ "$_secondary_abi_out_dir/snapshot_blob.bin" ]
+      renaming_destinations = [ "snapshot_blob_32.bin" ]
+    }
+    disable_compression = true
+    deps = [
+      "//tools/v8_context_snapshot($android_secondary_abi_toolchain)",
+      "//v8($android_secondary_abi_toolchain)",
+    ]
+  }
+
+  java_group("chrome_public_secondary_abi_non_pak_assets") {
+    deps = [
+      ":v8_snapshot_secondary_abi_assets",
+      "//chrome/android/webapk/libs/runtime_library:runtime_library_assets",
+      "//third_party/icu:icu_assets",
+    ]
+  }
+}
+
 jinja_template_resources("chrome_public_apk_template_resources") {
   resources = [
     "java/res_template/xml/file_paths.xml",
@@ -1148,12 +1180,17 @@
   #
   # Variables:
   #    is_monochrome: If true, generate Monochrome targets rather than Chrome.
+  #    is_trichrome: Optionally generate Trichrome targets that use monochrome
+  #      library targets but don't include webview resources.
   #    is_bundle: If true, generate resources for bundles rather than APK.
   template("resource_packaging") {
     _is_monochrome = invoker.is_monochrome
     _is_bundle = invoker.is_bundle
+    _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
 
-    if (_is_monochrome) {
+    if (_is_trichrome) {
+      _type = "trichrome_chrome"
+    } else if (_is_monochrome) {
       _type = "monochrome"
     } else {
       _type = "chrome"
@@ -1166,11 +1203,16 @@
     _variant = "${_type}_${_output_type}"
 
     if (enable_resource_whitelist_generation) {
+      if (_is_trichrome || _is_monochrome) {
+        _lib = "monochrome"
+      } else {
+        _lib = "chrome"
+      }
       _resource_whitelist_target = "${_variant}_resource_whitelist"
       _resource_whitelist_file =
           "$target_gen_dir/${_variant}_resource_whitelist.txt"
 
-      if (_is_monochrome) {
+      if (_is_trichrome || _is_monochrome) {
         _target_prefix = ""
       } else {
         _target_prefix = "lib"
@@ -1180,12 +1222,12 @@
       } else {
         _suffix = ""
       }
-      _lib_path = "/lib.unstripped/lib" + _type + _suffix + shlib_extension
-      _lib_target = _target_prefix + _type + _suffix
+      _lib_path = "/lib.unstripped/lib" + _lib + _suffix + shlib_extension
+      _lib_target = _target_prefix + _lib + _suffix
 
       generate_resource_whitelist(_resource_whitelist_target) {
         _fat_lib_toolchain = ""
-        if (_is_monochrome) {
+        if (_is_monochrome || _is_trichrome) {
           # Always use the 32-bit library's whitelist since the 64-bit one is
           # webview-only.
           if (!android_64bit_target_cpu) {
@@ -1340,6 +1382,11 @@
     is_monochrome = true
     is_bundle = false
   }
+  resource_packaging("trichrome_chrome_apk_pak_assets") {
+    is_monochrome = false
+    is_trichrome = true
+    is_bundle = false
+  }
   resource_packaging("chrome_bundle_pak_assets") {
     is_monochrome = false
     is_bundle = true
@@ -1348,6 +1395,11 @@
     is_monochrome = true
     is_bundle = true
   }
+  resource_packaging("trichrome_chrome_bundle_pak_assets") {
+    is_monochrome = false
+    is_bundle = true
+    is_trichrome = true
+  }
 
   # TODO(cjgrant): Remove this temporary alias after downstream renaming lands.
   java_group("chrome_public_pak_assets") {
@@ -1642,12 +1694,12 @@
 template("monochrome_public_apk_or_module_tmpl") {
   _android_manifest =
       "$target_gen_dir/manifest/${target_name}/AndroidManifest.xml"
+  _is_trichrome =
+      defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
 
   # Generate the manifest here in the template, to avoid a growing collection
   # of manually-instantiated manifests.
   jinja_template("${target_name}__android_manifest") {
-    _is_trichrome =
-        defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
     includes = [ "java/AndroidManifest.xml" ]
     variables = chrome_public_jinja_variables
     if (_is_trichrome) {
@@ -1698,7 +1750,7 @@
     android_manifest = _android_manifest
     android_manifest_dep = ":${target_name}__android_manifest"
 
-    if (public_android_sdk) {
+    if (public_android_sdk && !_is_trichrome) {
       # Resource whitelist used when generating R.java files and causes
       # only the webview subset of resources to be marked as non-final.
       shared_resources_whitelist_target = "//android_webview:system_webview_apk"
@@ -1709,11 +1761,14 @@
     }
 
     deps = [
-      ":monochrome_java",
-      "//android_webview:platform_service_bridge_upstream_implementation_java",
-      "//base:base_java",
       "//chrome/android:app_hooks_java",
     ]
+    if (!_is_trichrome) {
+      deps += [
+        ":monochrome_java",
+        "//android_webview:platform_service_bridge_upstream_implementation_java",
+      ]
+    }
 
     _needs_arm32_lib = target_cpu == "arm" ||
                        (target_cpu == "arm64" && build_apk_secondary_abi)
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 2b5624d..32147a1 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -51,6 +51,10 @@
 #     final APK or bundle.
 #   is_modern: If true, indicates this corresponds to a chrome_modern_XXX
 #     target that can only run on Android L-M.
+#   is_monochrome: Indicates that this target contains chrome and webview
+#     packaged together and can only run on Android N+.
+#   is_trichrome: Indicates this target relies on a trichrome static library
+#     target and can only run on Android P+.
 #   png_to_webp: Optional. If true, convert image resources to webp format.
 #     requires Android K+, since these were not supported by Android properly
 #     before 4.3.0.
@@ -58,7 +62,6 @@
 #     directly from the APK (and stored zipaligned and uncompressed). This
 #     requires either the Chromium linker, or Android M+.
 #   version_name: Application version name (e.g. "Developer Build").
-#   is_modern: Optional. true iff this is a chrome_modern derived build.
 #
 #   Plus all other variables accepted by android_apk() or
 #   android_app_bundle_module(), depending on the target type.
@@ -70,6 +73,9 @@
           invoker.target_type == "android_app_bundle_module" ||
           invoker.target_type == "instrumentation_test_apk",
       "Invalid target_type definition, should be 'android_apk' or 'android_app_bundle_module'")
+  assert(!(defined(invoker.is_trichrome) && invoker.is_trichrome) ||
+             !(defined(invoker.is_monochrome) && invoker.is_monochrome),
+         "Cannot be both trichrome and monochrome!")
 
   # Adds unwind table asset to the chrome apk for the given library target. This
   # is not part of generic apk assets target since it depends on the main shared
@@ -100,10 +106,8 @@
   assert(_is_modern || !_is_modern)  # Mark as used.
 
   _is_monochrome = defined(invoker.is_monochrome) && invoker.is_monochrome
-
-  _use_trichrome_library =
-      defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
-  assert(_use_trichrome_library || !_use_trichrome_library)  # Mark as used.
+  _is_trichrome = defined(invoker.is_trichrome) && invoker.is_trichrome
+  assert(_is_trichrome || !_is_trichrome)  # Mark as used.
 
   if (defined(invoker.enable_multidex)) {
     _enable_multidex = invoker.enable_multidex
@@ -149,7 +153,7 @@
       }
     }
 
-    if (!_is_monochrome) {
+    if (!_is_monochrome && !_is_trichrome) {
       deps += [
         "//third_party/crashpad/crashpad/handler:crashpad_handler_named_as_so",
       ]
@@ -247,7 +251,7 @@
     }
 
     if (!defined(version_code)) {
-      if (_use_trichrome_library) {
+      if (_is_trichrome) {
         version_code = trichrome_version_code
       } else if (_is_monochrome) {
         version_code = monochrome_version_code
@@ -262,7 +266,12 @@
 }
 
 # The equivalent of chrome_common_apk_or_module_tmpl for all builds of
-# monochrome.
+# monochrome and trichrome chrome.
+
+# Variables:
+#   use_trichrome_library: Specifies that this target depends on a trichrome
+#     static library target to provide certain shared library deps, and that
+#     this target should not package webview deps.
 template("monochrome_public_common_apk_or_module_tmpl") {
   if (defined(invoker.enable_multidex)) {
     _enable_multidex = invoker.enable_multidex
@@ -270,11 +279,16 @@
     _enable_multidex = is_java_debug || multidex_in_release
   }
   chrome_public_common_apk_or_module_tmpl(target_name) {
-    is_monochrome = true
-    use_trichrome_library =
+    is_trichrome =
         defined(invoker.use_trichrome_library) && invoker.use_trichrome_library
+    is_monochrome = !is_trichrome
 
-    if (!use_trichrome_library) {
+    loadable_modules = []
+    secondary_abi_loadable_modules = []
+
+    _deps = [ "//components/crash/android:handler_java" ]
+
+    if (is_monochrome) {
       if (invoker.target_type == "android_app_bundle_module") {
         _suffix = bundle_library_suffix
       } else {
@@ -301,7 +315,33 @@
       if (invoker.add_unwind_tables_in_apk) {
         shared_library_for_unwind_asset = "monochrome${_suffix}"
       }
-    } else {
+
+      _deps += [
+        "//android_webview:monochrome_webview_assets",
+        "//android_webview/apk:webview_license_activity_java",
+        "//android_webview/glue",
+        "//chrome/android:chrome_public_non_pak_assets",
+        "//chrome/android:monochrome_java",
+        "//chrome/android/monochrome:monochrome_license_provider_java",
+        "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
+      ]
+      loadable_modules += [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
+
+      if (android_64bit_target_cpu && build_apk_secondary_abi &&
+          (!defined(invoker.is_64_bit_browser) || !invoker.is_64_bit_browser ||
+           invoker.include_32_bit_webview)) {
+        _trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)"
+        _deps += [ _trampoline ]
+        _secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
+        secondary_abi_loadable_modules +=
+            [ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
+      }
+      alternative_android_sdk_dep = webview_framework_dep
+      app_as_shared_lib = true
+      min_sdk_version = 24
+      _pak_prefix = "monochrome"
+    }
+    if (is_trichrome) {
       # Include placeholder libraries to make Chrome multiarch in the same way
       # as Monochrome, even though Chrome only runs with one of the two
       # bitnesses. This allows the "32-bit" and "64-bit" versions of Chrome to
@@ -311,12 +351,17 @@
       if (android_64bit_target_cpu && build_apk_secondary_abi) {
         secondary_native_lib_placeholders = [ "libdummy.so" ]
       }
+      if (android_64bit_target_cpu) {
+        _deps +=
+            [ "//chrome/android:chrome_public_secondary_abi_non_pak_assets" ]
+      } else {
+        _deps += [ "//chrome/android:chrome_public_non_pak_assets" ]
+      }
+      min_sdk_version = 28
+      _pak_prefix = "trichrome_chrome"
     }
 
-    alternative_android_sdk_dep = webview_framework_dep
-    app_as_shared_lib = true
     use_chromium_linker = false
-    min_sdk_version = 24
 
     # Resources config for blocklisting resource names from obfuscation
     resources_config_path = "//android_webview/aapt2.config"
@@ -341,46 +386,12 @@
     # Android N+ better supports multiple locales (https://crbug.com/780847).
     support_zh_hk = false
 
-    if (!defined(deps)) {
-      deps = []
-    }
-    if (!defined(loadable_modules)) {
-      loadable_modules = []
-    }
-    if (!defined(secondary_abi_loadable_modules)) {
-      secondary_abi_loadable_modules = []
-    }
-
-    if (!use_trichrome_library) {
-      deps += [
-        "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
-      ]
-      loadable_modules += [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
-
-      if (android_64bit_target_cpu && build_apk_secondary_abi &&
-          (!defined(invoker.is_64_bit_browser) || !invoker.is_64_bit_browser ||
-           invoker.include_32_bit_webview)) {
-        _trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)"
-        deps += [ _trampoline ]
-        _secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
-        secondary_abi_loadable_modules +=
-            [ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
-      }
-    }
-
-    deps += [
-      "//android_webview:monochrome_webview_assets",
-      "//android_webview/apk:webview_license_activity_java",
-      "//android_webview/glue",
-      "//chrome/android:chrome_public_non_pak_assets",
-      "//chrome/android/monochrome:monochrome_license_provider_java",
-      "//components/crash/android:handler_java",
-    ]
     if (invoker.target_type == "android_app_bundle_module") {
-      deps +=
-          [ "//chrome/android:monochrome_${bundle_pak_asset_type}_pak_assets" ]
+      _deps += [
+        "//chrome/android:${_pak_prefix}_${bundle_pak_asset_type}_pak_assets",
+      ]
     } else {
-      deps += [ "//chrome/android:monochrome_apk_pak_assets" ]
+      _deps += [ "//chrome/android:${_pak_prefix}_apk_pak_assets" ]
     }
 
     if (_enable_multidex && invoker.target_type == "android_apk" &&
@@ -398,13 +409,15 @@
       if (!defined(proguard_configs)) {
         proguard_configs = []
       }
-      proguard_configs += [ "//android_webview/apk/java/proguard.flags" ]
+      if (is_monochrome) {
+        proguard_configs += [ "//android_webview/apk/java/proguard.flags" ]
+      }
       png_to_webp = true
     }
 
     if ((invoker.target_type == "android_apk" || !modularize_ar) &&
         package_arcore) {
-      deps += [
+      _deps += [
         "//chrome/browser/android/vr:ar_java",
         "//third_party/android_deps:com_google_ar_core_java",
       ]
@@ -418,5 +431,9 @@
         loadable_modules += [ "$root_gen_dir/third_party/android_deps/com_google_ar_core_java/jni/armeabi-v7a/libarcore_sdk_c.so" ]
       }
     }
+    if (!defined(deps)) {
+      deps = []
+    }
+    deps += _deps
   }
 }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
index 65747ab..7128bbd 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantCarouselCoordinator.java
@@ -33,6 +33,10 @@
     public AssistantCarouselCoordinator(Context context, AssistantCarouselModel model) {
         mLayoutManager = new LinearLayoutManager(
                 context, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false);
+
+        // Workaround for b/128679161.
+        mLayoutManager.setMeasurementCacheEnabled(false);
+
         mView = new RecyclerView(context);
         mView.setLayoutManager(mLayoutManager);
         mView.addItemDecoration(new SpaceItemDecoration(context));
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java
index ebd550a..6e7cd30 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java
@@ -7,13 +7,14 @@
 import android.content.Context;
 
 import org.chromium.base.ContextUtils;
-import org.chromium.base.ThreadUtils;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
 import org.chromium.components.background_task_scheduler.TaskIds;
 import org.chromium.components.background_task_scheduler.TaskInfo;
 import org.chromium.components.background_task_scheduler.TaskParameters;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.util.concurrent.TimeUnit;
 
@@ -95,6 +96,7 @@
         // as light weight as possible. Instead of going to native to reschedule with a more
         // informed threshold, just schedule for 1 day from now. The next time a successful fetch
         // occurs, this value will be set to a value tailored to current usage patterns.
-        ThreadUtils.runOnUiThread(() -> scheduleWakeUp(TimeUnit.DAYS.toMillis(1)));
+        PostTask.runOrPostTask(
+                UiThreadTaskTraits.DEFAULT, () -> scheduleWakeUp(TimeUnit.DAYS.toMillis(1)));
     }
 }
diff --git a/chrome/android/java/res/layout/control_container.xml b/chrome/android/java/res/layout/control_container.xml
index 3ff8c90..c4d71d4 100644
--- a/chrome/android/java/res/layout/control_container.xml
+++ b/chrome/android/java/res/layout/control_container.xml
@@ -24,7 +24,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content" >
 
-        <org.chromium.ui.AsyncViewStub
+        <ViewStub
             android:id="@+id/toolbar_stub"
             android:layout_width="match_parent"
             android:layout_marginTop="@dimen/tab_strip_height"
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index 1068729..9a138cd6 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -22,7 +22,7 @@
         android:layout_height="@dimen/ntp_logo_height"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="16dp"
-        android:layout_marginTop="26dp"
+        android:layout_marginTop="@dimen/ntp_logo_margin_top"
         android:layout_marginBottom="23dp" />
 
     <!-- Search box -->
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml
index e0f3c30..59266c58 100644
--- a/chrome/android/java/res/values/attrs.xml
+++ b/chrome/android/java/res/values/attrs.xml
@@ -83,12 +83,4 @@
         <!-- drawableTint wasn't added in Android until API level 23. -->
         <attr name="chromeDrawableTint" format="color"/>
     </declare-styleable>
-
-    <declare-styleable name="AsyncViewStub">
-        <!-- Supply an identifier for the layout resource to inflate when the AsyncViewStub
-             becomes visible or when forced to do so. The layout resource must be a
-             valid reference to a layout. -->
-        <attr name="layout" format="reference" />
-        <attr name="autoInflate" format="boolean" />
-    </declare-styleable>
 </resources>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index dcc2558..e421560 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -344,6 +344,7 @@
     <dimen name="tile_view_padding">4dp</dimen>
     <dimen name="tile_view_title_margin_top_modern">61dp</dimen>
     <dimen name="ntp_logo_height">100dp</dimen>
+    <dimen name="ntp_logo_margin_top">26dp</dimen>
     <dimen name="duet_ntp_logo_top_margin">-16dp</dimen>
     <dimen name="ntp_search_box_height">48dp</dimen>
     <dimen name="ntp_search_box_transition_length">16dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
index a3e1f61..06acb00c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -53,6 +53,7 @@
 import org.chromium.chrome.browser.survey.SurveyController;
 import org.chromium.chrome.browser.tab.AuthenticatorNavigationInterceptor;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.touchless.TouchlessUiController;
 import org.chromium.chrome.browser.webapps.GooglePlayWebApkInstallDelegate;
 import org.chromium.chrome.browser.webauth.Fido2ApiHandler;
 import org.chromium.chrome.browser.widget.FeatureHighlightProvider;
@@ -367,6 +368,14 @@
     }
 
     /**
+     * @param activity An activity for access to different features.
+     * @return A new {@link TouchlessUiController} instance.
+     */
+    public TouchlessUiController createTouchlessUiController(ChromeActivity activity) {
+        return null;
+    }
+
+    /**
      * Checks the Google Play services availability on the this device.
      *
      * This is a workaround for the
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
index d34b694..84b4b56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
@@ -11,15 +11,16 @@
 import com.google.android.gms.gcm.TaskParams;
 
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.ServiceManagerStartupUtils;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsLauncher;
 import org.chromium.chrome.browser.offlinepages.BackgroundScheduler;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * {@link ChromeBackgroundService} is scheduled through the {@link GcmNetworkManager} when the
@@ -34,35 +35,32 @@
     public int onRunTask(final TaskParams params) {
         final String taskTag = params.getTag();
         final Context context = this;
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                switch (taskTag) {
-                    case BackgroundSyncLauncher.TASK_TAG:
-                        handleBackgroundSyncEvent(context, taskTag);
-                        break;
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            switch (taskTag) {
+                case BackgroundSyncLauncher.TASK_TAG:
+                    handleBackgroundSyncEvent(context, taskTag);
+                    break;
 
-                    case OfflinePageUtils.TASK_TAG:
-                        // Offline pages are migrating to BackgroundTaskScheduler, therefore getting
-                        // a task through ChromeBackgroundSerivce should cause a rescheduling using
-                        // the new component.
-                        rescheduleOfflinePages();
-                        break;
+                case OfflinePageUtils.TASK_TAG:
+                    // Offline pages are migrating to BackgroundTaskScheduler, therefore getting
+                    // a task through ChromeBackgroundSerivce should cause a rescheduling using
+                    // the new component.
+                    rescheduleOfflinePages();
+                    break;
 
-                    case SnippetsLauncher.TASK_TAG_WIFI:
-                    case SnippetsLauncher.TASK_TAG_FALLBACK:
-                        handleSnippetsOnPersistentSchedulerWakeUp(context, taskTag);
-                        break;
+                case SnippetsLauncher.TASK_TAG_WIFI:
+                case SnippetsLauncher.TASK_TAG_FALLBACK:
+                    handleSnippetsOnPersistentSchedulerWakeUp(context, taskTag);
+                    break;
 
-                    // This is only for tests.
-                    case ServiceManagerStartupUtils.TASK_TAG:
-                        handleServicificationStartupTask(context, taskTag);
-                        break;
+                // This is only for tests.
+                case ServiceManagerStartupUtils.TASK_TAG:
+                    handleServicificationStartupTask(context, taskTag);
+                    break;
 
-                    default:
-                        Log.i(TAG, "Unknown task tag " + taskTag);
-                        break;
-                }
+                default:
+                    Log.i(TAG, "Unknown task tag " + taskTag);
+                    break;
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index e96a5bc4..d0450ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -240,7 +240,6 @@
     public static final String HOMEPAGE_TILE = "HomepageTile";
     public static final String HORIZONTAL_TAB_SWITCHER_ANDROID = "HorizontalTabSwitcherAndroid";
     public static final String INCOGNITO_STRINGS = "IncognitoStrings";
-    public static final String INFLATE_TOOLBAR_ON_BACKGROUND_THREAD = "BackgroundToolbarInflation";
     public static final String INLINE_UPDATE_FLOW = "InlineUpdateFlow";
     public static final String INTENT_BLOCK_EXTERNAL_FORM_REDIRECT_NO_GESTURE =
             "IntentBlockExternalFormRedirectsNoGesture";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java
index ae0615c..4d17e6c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java
@@ -20,7 +20,9 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.task.AsyncTask;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.security.Principal;
@@ -150,10 +152,10 @@
         public void alias(final String alias) {
             // This is called by KeyChainActivity in a background thread. Post task to
             // handle the certificate selection on the UI thread.
-            ThreadUtils.runOnUiThread(() -> {
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
                 if (alias == null) {
                     // No certificate was selected.
-                    ThreadUtils.runOnUiThread(
+                    PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT,
                             () -> nativeOnSystemRequestCompletion(mNativePtr, null, null));
                 } else {
                     new CertAsyncTaskKeyChain(mContext, mNativePtr, alias)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ThemeColorProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/ThemeColorProvider.java
index 1664590..8b0b914 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ThemeColorProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ThemeColorProvider.java
@@ -68,22 +68,53 @@
         mDarkModeTint = ColorUtils.getThemedToolbarIconTint(context, false);
     }
 
+    /**
+     * @param observer Adds a {@link ThemeColorObserver} that will be notified when the theme color
+     *                 changes. This method does not trigger the observer.
+     */
     public void addThemeColorObserver(ThemeColorObserver observer) {
         mThemeColorObservers.addObserver(observer);
     }
 
+    /**
+     * @param observer Removes the observer so it no longer receives theme color changes.
+     */
     public void removeThemeColorObserver(ThemeColorObserver observer) {
         mThemeColorObservers.removeObserver(observer);
     }
 
+    /**
+     * @param observer Adds a {@link TintObserver} that will be notified when the tint changes. This
+     *                 method does not trigger the observer.
+     */
     public void addTintObserver(TintObserver observer) {
         mTintObservers.addObserver(observer);
     }
 
+    /**
+     * @param observer Removes the observer so it no longer receives tint changes.
+     */
     public void removeTintObserver(TintObserver observer) {
         mTintObservers.removeObserver(observer);
     }
 
+    /**
+     * @return The current tint of this provider.
+     */
+    public ColorStateList getTint() {
+        return useLight() ? mLightModeTint : mDarkModeTint;
+    }
+
+    /**
+     * @return Whether or not this provider is using light tints.
+     */
+    public boolean useLight() {
+        return mUseLightTint != null ? mUseLightTint : false;
+    }
+
+    /**
+     * Clears out the observer lists.
+     */
     public void destroy() {
         mThemeColorObservers.clear();
         mTintObservers.clear();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
index 4f80741..0aa19c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
@@ -24,9 +24,9 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver;
@@ -40,6 +40,7 @@
 import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.components.bookmarks.BookmarkId;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -350,11 +351,8 @@
         @BinderThread
         @Override
         public void onDestroy() {
-            ThreadUtils.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (mBookmarkModel != null) mBookmarkModel.destroy();
-                }
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+                if (mBookmarkModel != null) mBookmarkModel.destroy();
             });
             deleteWidgetState(mContext, mWidgetId);
         }
@@ -380,16 +378,13 @@
             //A reference of BookmarkLoader is needed in binder thread to
             //prevent it from being garbage collected.
             final BookmarkLoader bookmarkLoader = new BookmarkLoader();
-            ThreadUtils.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    bookmarkLoader.initialize(mContext, folderId, new BookmarkLoaderCallback() {
-                        @Override
-                        public void onBookmarksLoaded(BookmarkFolder folder) {
-                            resultQueue.add(folder);
-                        }
-                    });
-                }
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+                bookmarkLoader.initialize(mContext, folderId, new BookmarkLoaderCallback() {
+                    @Override
+                    public void onBookmarksLoaded(BookmarkFolder folder) {
+                        resultQueue.add(folder);
+                    }
+                });
             });
             try {
                 return resultQueue.take();
@@ -436,12 +431,7 @@
             //returns. If it happens, refresh widget until the bookmarks are all loaded.
             if (mCurrentFolder == null || !mPreferences.getString(PREF_CURRENT_FOLDER, "")
                     .equals(mCurrentFolder.folder.id.toString())) {
-                ThreadUtils.runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        refreshWidget();
-                    }
-                });
+                PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { refreshWidget(); });
             }
             if (mCurrentFolder == null) {
                 return 0;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
index 5139429..94df9acf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
@@ -16,8 +16,8 @@
 import android.view.View;
 
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.contextmenu.ContextMenuParams;
@@ -27,6 +27,7 @@
 import org.chromium.chrome.browser.init.AsyncInitializationActivity;
 import org.chromium.chrome.browser.rappor.RapporServiceBridge;
 import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.common.Referrer;
 import org.chromium.ui.base.MenuSourceType;
 
@@ -177,16 +178,12 @@
 
     private void recordClientPackageName() {
         if (TextUtils.isEmpty(mUntrustedCreatorPackageName)) return;
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                RapporServiceBridge.sampleString(
-                        "BrowserActions.ServiceClient.PackageName", mUntrustedCreatorPackageName);
-                if (GSAState.isGsaPackageName(mUntrustedCreatorPackageName)) return;
-                RapporServiceBridge.sampleString(
-                        "BrowserActions.ServiceClient.PackageNameThirdParty",
-                        mUntrustedCreatorPackageName);
-            }
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            RapporServiceBridge.sampleString(
+                    "BrowserActions.ServiceClient.PackageName", mUntrustedCreatorPackageName);
+            if (GSAState.isGsaPackageName(mUntrustedCreatorPackageName)) return;
+            RapporServiceBridge.sampleString("BrowserActions.ServiceClient.PackageNameThirdParty",
+                    mUntrustedCreatorPackageName);
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabModelSelector.java b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabModelSelector.java
index bfd13fcd..a695600 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabModelSelector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionsTabModelSelector.java
@@ -27,6 +27,7 @@
 import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -119,7 +120,7 @@
         };
         getModel(false).addObserver(tabModelObserver);
         if (mTabCreationRunnable != null) {
-            ThreadUtils.runOnUiThread(mTabCreationRunnable);
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, mTabCreationRunnable);
         }
         mTabCreationRunnable = null;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java
index 4b2ac81b..7749cd5c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java
@@ -23,11 +23,13 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.content_public.browser.BrowserStartupController;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -225,7 +227,7 @@
         if (!TextUtils.isEmpty(disableDalUrl)
                 && mOrigin.equals(new Origin(disableDalUrl))) {
             Log.i(TAG, "Verification skipped for %s due to command line flag.", origin);
-            ThreadUtils.runOnUiThread(new VerifiedCallback(true, null));
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, new VerifiedCallback(true, null));
             return;
         }
 
@@ -235,13 +237,13 @@
             Log.i(TAG, "Verification failed for %s as not https.", origin);
             BrowserServicesMetrics.recordVerificationResult(
                     BrowserServicesMetrics.VerificationResult.HTTPS_FAILURE);
-            ThreadUtils.runOnUiThread(new VerifiedCallback(false, null));
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, new VerifiedCallback(false, null));
             return;
         }
 
         if (shouldOverrideVerification(mPackageName, mOrigin, mRelation)) {
             Log.i(TAG, "Verification succeeded for %s, it was overridden.", origin);
-            ThreadUtils.runOnUiThread(new VerifiedCallback(true, null));
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, new VerifiedCallback(true, null));
             return;
         }
 
@@ -271,7 +273,7 @@
         if (!requestSent) {
             BrowserServicesMetrics.recordVerificationResult(
                     BrowserServicesMetrics.VerificationResult.REQUEST_FAILURE);
-            ThreadUtils.runOnUiThread(new VerifiedCallback(false, false));
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, new VerifiedCallback(false, false));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index f882588a..ad9e5822 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -678,52 +678,49 @@
             int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl,
             final String caption, final String quickActionUri, final int quickActionCategory,
             final long loggedEventId, final String searchUrlFull, final String searchUrlPreload) {
-        mNetworkCommunicator.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode,
-                searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust,
-                selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri,
-                quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload);
+        mNetworkCommunicator.handleSearchTermResolutionResponse(
+                new ResolvedSearchTerm(isNetworkUnavailable, responseCode, searchTerm, displayText,
+                        alternateTerm, mid, doPreventPreload, selectionStartAdjust,
+                        selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri,
+                        quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload));
     }
 
     @Override
-    public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode,
-            String searchTerm, String displayText, String alternateTerm, String mid,
-            boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust,
-            String contextLanguage, String thumbnailUrl, String caption, String quickActionUri,
-            int quickActionCategory, long loggedEventId, String searchUrlFull,
-            String searchUrlPreload) {
+    public void handleSearchTermResolutionResponse(ResolvedSearchTerm resolvedSearchTerm) {
         if (!mInternalStateController.isStillWorkingOn(InternalState.RESOLVING)) return;
 
         // Show an appropriate message for what to search for.
         String message;
         boolean doLiteralSearch = false;
-        if (isNetworkUnavailable) {
+        if (resolvedSearchTerm.isNetworkUnavailable()) {
             // TODO(donnd): double-check that the network is really unavailable, maybe using
             // NetworkChangeNotifier#isOnline.
             message = mActivity.getResources().getString(
                     R.string.contextual_search_network_unavailable);
-        } else if (!isHttpFailureCode(responseCode) && !TextUtils.isEmpty(displayText)) {
-            message = displayText;
+        } else if (!isHttpFailureCode(resolvedSearchTerm.responseCode())
+                && !TextUtils.isEmpty(resolvedSearchTerm.displayText())) {
+            message = resolvedSearchTerm.displayText();
         } else if (!mPolicy.shouldShowErrorCodeInBar()) {
             message = mSelectionController.getSelectedText();
             doLiteralSearch = true;
         } else {
             message = mActivity.getResources().getString(
-                    R.string.contextual_search_error, responseCode);
+                    R.string.contextual_search_error, resolvedSearchTerm.responseCode());
             doLiteralSearch = true;
         }
 
-        boolean receivedCaptionOrThumbnail = !TextUtils.isEmpty(caption)
-                || !TextUtils.isEmpty(thumbnailUrl);
+        boolean receivedCaptionOrThumbnail = !TextUtils.isEmpty(resolvedSearchTerm.caption())
+                || !TextUtils.isEmpty(resolvedSearchTerm.thumbnailUrl());
 
         assert mSearchPanel != null;
-        mSearchPanel.onSearchTermResolved(message, thumbnailUrl, quickActionUri,
-                quickActionCategory);
-        if (!TextUtils.isEmpty(caption)) {
+        mSearchPanel.onSearchTermResolved(message, resolvedSearchTerm.thumbnailUrl(),
+                resolvedSearchTerm.quickActionUri(), resolvedSearchTerm.quickActionCategory());
+        if (!TextUtils.isEmpty(resolvedSearchTerm.caption())) {
             // Call #onSetCaption() to set the caption. For entities, the caption should not be
             // regarded as an answer. In the future, when quick actions are added, doesAnswer will
             // need to be determined rather than always set to false.
             boolean doesAnswer = false;
-            onSetCaption(caption, doesAnswer);
+            onSetCaption(resolvedSearchTerm.caption(), doesAnswer);
         }
 
         boolean quickActionShown =
@@ -741,12 +738,16 @@
         ContextualSearchUma.logContextualCardsDataShown(mReceivedContextualCardsEntityData);
         mSearchPanel.getPanelMetrics().setWasContextualCardsDataShown(
                 mReceivedContextualCardsEntityData);
-        ContextualSearchUma.logQuickActionShown(quickActionShown, quickActionCategory);
+        ContextualSearchUma.logQuickActionShown(
+                quickActionShown, resolvedSearchTerm.quickActionCategory());
         mSearchPanel.getPanelMetrics().setWasQuickActionShown(
-                quickActionShown, quickActionCategory);
+                quickActionShown, resolvedSearchTerm.quickActionCategory());
 
         // If there was an error, fall back onto a literal search for the selection.
         // Since we're showing the panel, there must be a selection.
+        String searchTerm = resolvedSearchTerm.searchTerm();
+        String alternateTerm = resolvedSearchTerm.alternateTerm();
+        boolean doPreventPreload = resolvedSearchTerm.doPreventPreload();
         if (doLiteralSearch) {
             searchTerm = mSelectionController.getSelectedText();
             alternateTerm = null;
@@ -756,10 +757,12 @@
             // TODO(donnd): Instead of preloading, we should prefetch (ie the URL should not
             // appear in the user's history until the user views it).  See crbug.com/406446.
             boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchSearchResult();
-            mSearchRequest = new ContextualSearchRequest(
-                    searchTerm, alternateTerm, mid, shouldPreload, searchUrlFull, searchUrlPreload);
+            mSearchRequest = new ContextualSearchRequest(searchTerm, alternateTerm,
+                    resolvedSearchTerm.mid(), shouldPreload, resolvedSearchTerm.searchUrlFull(),
+                    resolvedSearchTerm.searchUrlPreload());
             // Trigger translation, if enabled.
-            mTranslateController.forceTranslateIfNeeded(mSearchRequest, contextLanguage);
+            mTranslateController.forceTranslateIfNeeded(
+                    mSearchRequest, resolvedSearchTerm.contextLanguage());
             mDidStartLoadingResolvedSearchRequest = false;
             if (mSearchPanel.isContentShowing()) {
                 mSearchRequest.setNormalPriority();
@@ -771,6 +774,8 @@
         }
 
         // Adjust the selection unless the user changed it since we initiated the search.
+        int selectionStartAdjust = resolvedSearchTerm.selectionStartAdjust();
+        int selectionEndAdjust = resolvedSearchTerm.selectionEndAdjust();
         if ((selectionStartAdjust != 0 || selectionEndAdjust != 0)
                 && mSelectionController.getSelectionType() == SelectionType.TAP) {
             String originalSelection = mContext == null ? null : mContext.getInitialSelectedWord();
@@ -783,7 +788,7 @@
         }
 
         // Tell the Interaction Recorder about the current Event ID for persisted interaction.
-        mInteractionRecorder.persistInteraction(loggedEventId);
+        mInteractionRecorder.persistInteraction(resolvedSearchTerm.loggedEventId());
 
         mInternalStateController.notifyFinishedWorkOn(InternalState.RESOLVING);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java
index 7201360..8187173 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java
@@ -22,34 +22,10 @@
 
     /**
      * Handles a Search Term Resolution response.
-     * @param isNetworkUnavailable whether the network is available.
-     * @param responseCode the server's HTTP response code.
-     * @param searchTerm the term to search for.
-     * @param displayText the text to display that describes the search term.
-     * @param alternateTerm the alternate search term.
-     * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string.
-     *            A MID is a unique identifier for an entity in the Search Knowledge Graph.
-     * @param doPreventPreload whether to prevent preloading the search result.
-     * @param selectionStartAdjust The start offset adjustment of the selection to use to highlight
-     *                             the search term.
-     * @param selectionEndAdjust The end offset adjustment of the selection to use to highlight
-     *                           the search term.
-     * @param contextLanguage The language of the context, or the empty string if unknown.
-     * @param thumbnailUrl The URL of the thumbnail to display in our UX.
-     * @param caption The caption to display.
-     * @param quickActionUri The URI for the intent associated with the quick action.
-     * @param quickActionCategory The {@link QuickActionCategory} for the quick action.
-     * @param loggedEventId The EventID logged by the server, which should be recorded and sent back
-     *        to the server along with user action results in a subsequent request.
-     * @param searchUrlFull The URL for the full search to present in the overlay, or empty.
-     * @param searchUrlPreload The URL for the search to preload into the overlay, or empty.
+     * @param resolvedSearchTerm A {@link ResolvedSearchTerm} that encapsulates the response from
+     *        the server.
      */
-    void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode,
-            String searchTerm, String displayText, String alternateTerm, String mid,
-            boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust,
-            String contextLanguage, String thumbnailUrl, String caption, String quickActionUri,
-            int quickActionCategory, long loggedEventId, String searchUrlFull,
-            String searchUrlPreload);
+    void handleSearchTermResolutionResponse(ResolvedSearchTerm resolvedSearchTerm);
 
     /**
      * @return Whether the device is currently online.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java
new file mode 100644
index 0000000..a8800902
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java
@@ -0,0 +1,167 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.contextualsearch;
+
+/**
+ * Encapsulates the results of a server Resolve request into a single immutable object.
+ */
+public class ResolvedSearchTerm {
+    private final boolean mIsNetworkUnavailable;
+    private final int mResponseCode;
+    private final String mSearchTerm;
+    private final String mDisplayText;
+    private final String mAlternateTerm;
+    private final String mMid;
+    private final boolean mDoPreventPreload;
+    private final int mSelectionStartAdjust;
+    private final int mSelectionEndAdjust;
+    private final String mContextLanguage;
+    private final String mThumbnailUrl;
+    private final String mCaption;
+    @QuickActionCategory
+    private final String mQuickActionUri;
+    private final int mQuickActionCategory;
+    private final long mLoggedEventId;
+    private final String mSearchUrlFull;
+    private final String mSearchUrlPreload;
+
+    /**
+     * Called in response to the
+     * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method.
+     * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all other
+     *        parameters should be ignored.
+     * @param responseCode The HTTP response code. If the code is not OK, the query should be
+     *        ignored.
+     * @param searchTerm The term to use in our subsequent search.
+     * @param displayText The text to display in our UX.
+     * @param alternateTerm The alternate term to display on the results page.
+     * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string.
+     *        A MID is a unique identifier for an entity in the Search Knowledge Graph.
+     * @param doPreventPreload Whether we should prevent preloading on this search.
+     * @param selectionStartAdjust A positive number of characters that the start of the existing
+     *        selection should be expanded by.
+     * @param selectionEndAdjust A positive number of characters that the end of the existing
+     *        selection should be expanded by.
+     * @param contextLanguage The language of the original search term, or an empty string.
+     * @param thumbnailUrl The URL of the thumbnail to display in our UX.
+     * @param caption The caption to display.
+     * @param quickActionUri The URI for the intent associated with the quick action.
+     * @param quickActionCategory The {@link QuickActionCategory} for the quick action.
+     * @param loggedEventId The EventID logged by the server, which should be recorded and sent back
+     *        to the server along with user action results in a subsequent request.
+     * @param searchUrlFull The URL for the full search to present in the overlay, or empty.
+     * @param searchUrlPreload The URL for the search to preload into the overlay, or empty.
+     */
+    ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm,
+            final String displayText, final String alternateTerm, final String mid,
+            boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust,
+            final String contextLanguage, final String thumbnailUrl, final String caption,
+            final String quickActionUri, final int quickActionCategory, final long loggedEventId,
+            final String searchUrlFull, final String searchUrlPreload) {
+        mIsNetworkUnavailable = isNetworkUnavailable;
+        mResponseCode = responseCode;
+        mSearchTerm = searchTerm;
+        mDisplayText = displayText;
+        mAlternateTerm = alternateTerm;
+        mMid = mid;
+        mDoPreventPreload = doPreventPreload;
+        mSelectionStartAdjust = selectionStartAdjust;
+        mSelectionEndAdjust = selectionEndAdjust;
+        mContextLanguage = contextLanguage;
+        mThumbnailUrl = thumbnailUrl;
+        mCaption = caption;
+        mQuickActionUri = quickActionUri;
+        mQuickActionCategory = quickActionCategory;
+        mLoggedEventId = loggedEventId;
+        mSearchUrlFull = searchUrlFull;
+        mSearchUrlPreload = searchUrlPreload;
+    }
+
+    /**
+     * Called in response to the
+     * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method.
+     * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all other
+     *        parameters should be ignored.
+     * @param responseCode The HTTP response code. If the code is not OK, the query should be
+     *        ignored.
+     * @param searchTerm The term to use in our subsequent search.
+     * @param displayText The text to display in our UX.
+     * @param alternateTerm The alternate term to display on the results page.
+     * @param doPreventPreload Whether we should prevent preloading on this search.
+     */
+    ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm,
+            final String displayText, final String alternateTerm, boolean doPreventPreload) {
+        this(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, "",
+                doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0L, "", "");
+    }
+
+    public boolean isNetworkUnavailable() {
+        return mIsNetworkUnavailable;
+    }
+
+    public int responseCode() {
+        return mResponseCode;
+    }
+
+    public String searchTerm() {
+        return mSearchTerm;
+    }
+
+    public String displayText() {
+        return mDisplayText;
+    }
+
+    public String alternateTerm() {
+        return mAlternateTerm;
+    }
+
+    public String mid() {
+        return mMid;
+    }
+
+    public boolean doPreventPreload() {
+        return mDoPreventPreload;
+    }
+
+    public int selectionStartAdjust() {
+        return mSelectionStartAdjust;
+    }
+
+    public int selectionEndAdjust() {
+        return mSelectionEndAdjust;
+    }
+
+    public String contextLanguage() {
+        return mContextLanguage;
+    }
+
+    public String thumbnailUrl() {
+        return mThumbnailUrl;
+    }
+
+    public String caption() {
+        return mCaption;
+    }
+
+    public String quickActionUri() {
+        return mQuickActionUri;
+    }
+
+    public @QuickActionCategory int quickActionCategory() {
+        return mQuickActionCategory;
+    }
+
+    public long loggedEventId() {
+        return mLoggedEventId;
+    }
+
+    public String searchUrlFull() {
+        return mSearchUrlFull;
+    }
+
+    public String searchUrlPreload() {
+        return mSearchUrlPreload;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
index c94b61f..116f6e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
@@ -25,9 +25,9 @@
 import android.util.SparseBooleanArray;
 
 import org.chromium.base.ContextUtils;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.browserservices.Origin;
 import org.chromium.chrome.browser.browserservices.OriginVerifier;
@@ -35,6 +35,7 @@
 import org.chromium.chrome.browser.browserservices.PostMessageHandler;
 import org.chromium.chrome.browser.installedapp.InstalledAppProviderImpl;
 import org.chromium.chrome.browser.util.UrlUtilities;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.Referrer;
 
@@ -478,7 +479,8 @@
         };
 
         params.originVerifier = new OriginVerifier(params.getPackageName(), relation);
-        ThreadUtils.runOnUiThread(() -> { params.originVerifier.start(listener, origin); });
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT,
+                () -> { params.originVerifier.start(listener, origin); });
         if (relation == CustomTabsService.RELATION_HANDLE_ALL_URLS
                 && InstalledAppProviderImpl.isAppInstalledAndAssociatedWithOrigin(
                            params.getPackageName(), URI.create(origin.toString()),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index e1da8af..f3287f06 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -37,7 +37,6 @@
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.metrics.RecordHistogram;
@@ -557,15 +556,11 @@
         if (TextUtils.isEmpty(clientName)) clientName = mIntentDataProvider.getClientPackageName();
         final String packageName = clientName;
         if (TextUtils.isEmpty(packageName) || packageName.contains(getPackageName())) return;
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                RapporServiceBridge.sampleString(
-                        "CustomTabs.ServiceClient.PackageName", packageName);
-                if (GSAState.isGsaPackageName(packageName)) return;
-                RapporServiceBridge.sampleString(
-                        "CustomTabs.ServiceClient.PackageNameThirdParty", packageName);
-            }
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            RapporServiceBridge.sampleString("CustomTabs.ServiceClient.PackageName", packageName);
+            if (GSAState.isGsaPackageName(packageName)) return;
+            RapporServiceBridge.sampleString(
+                    "CustomTabs.ServiceClient.PackageNameThirdParty", packageName);
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index c0a541d5..fce64ffc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -1301,7 +1301,8 @@
      */
     @VisibleForTesting
     void cleanUpSession(final CustomTabsSessionToken session) {
-        ThreadUtils.runOnUiThread(() -> mClientManager.cleanupSession(session));
+        PostTask.runOrPostTask(
+                UiThreadTaskTraits.DEFAULT, () -> mClientManager.cleanupSession(session));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
index 35910f376..62d92290 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
@@ -21,12 +21,13 @@
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.CachedMetrics.SparseHistogramSample;
 import org.chromium.base.metrics.CachedMetrics.TimesHistogramSample;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * Utility class for external authentication tools.
@@ -199,7 +200,7 @@
                     errorHandler.handleError(context, resultCode);
                 }
             };
-            ThreadUtils.runOnUiThread(errorHandlerTask);
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, errorHandlerTask);
         }
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 012606f2..0356eda 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -83,6 +83,7 @@
 import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.content_public.browser.BrowserTaskExecutor;
 import org.chromium.content_public.browser.ChildProcessLauncherHelper;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.printing.PrintDocumentAdapterWrapper;
 import org.chromium.printing.PrintingControllerImpl;
@@ -374,12 +375,8 @@
                         new AccountsChangeObserver() {
                             @Override
                             public void onAccountsChanged() {
-                                ThreadUtils.runOnUiThread(new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        ForcedSigninProcessor.start(application, null);
-                                    }
-                                });
+                                PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT,
+                                        () -> { ForcedSigninProcessor.start(application, null); });
                             }
                         });
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
index 61e2840..b6bf2ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
@@ -18,11 +18,12 @@
 import android.os.SystemClock;
 import android.util.Log;
 
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.webapps.WebappRegistry;
 import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * The Notification service receives intents fired as responses to user actions issued on Android
@@ -90,12 +91,8 @@
             return;
         }
 
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                dispatchIntentOnUIThread(NotificationService.this, intent);
-            }
-        });
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT,
+                () -> { dispatchIntentOnUIThread(NotificationService.this, intent); });
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index fd2bf2a..4509f138 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -439,7 +439,7 @@
         // Apply negative margin to the top of the N logo (which would otherwise be the height of
         // the top toolbar) when Duet is enabled to remove some of the empty space.
         mNewTabPageLayout.setSearchProviderTopMargin((layoutParams.bottomMargin == 0)
-                        ? 0
+                        ? view.getResources().getDimensionPixelSize(R.dimen.ntp_logo_margin_top)
                         : -view.getResources().getDimensionPixelSize(
                                 R.dimen.duet_ntp_logo_top_margin));
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
index e842949..be3ee37 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
@@ -8,10 +8,10 @@
 import android.graphics.Bitmap;
 import android.support.annotation.IntDef;
 
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
@@ -35,6 +35,7 @@
 import org.chromium.components.signin.ChromeSigninController;
 import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.components.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -432,7 +433,7 @@
     }
 
     private void update() {
-        ThreadUtils.runOnUiThread(() -> {
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
             if (mIsDestroyed) return;
             updateForeignSessions();
             postUpdate();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaService.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaService.java
index 61f8903..74c8862 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaService.java
@@ -13,13 +13,14 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.task.AsyncTask;
+import org.chromium.base.task.PostTask;
 import org.chromium.components.background_task_scheduler.BackgroundTask;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
 import org.chromium.components.background_task_scheduler.TaskIds;
 import org.chromium.components.background_task_scheduler.TaskInfo;
 import org.chromium.components.background_task_scheduler.TaskParameters;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * Manages scheduling and running of the Omaha client code.
@@ -38,14 +39,11 @@
                 Log.i(OmahaBase.TAG, "Scheduled using AlarmManager and IntentService");
             } else {
                 final long delay = nextTimestampMs - currentTimestampMs;
-                ThreadUtils.runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (scheduleJobService(getContext(), delay)) {
-                            Log.i(OmahaBase.TAG, "Scheduled using JobService");
-                        } else {
-                            Log.e(OmahaBase.TAG, "Failed to schedule job");
-                        }
+                PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+                    if (scheduleJobService(getContext(), delay)) {
+                        Log.i(OmahaBase.TAG, "Scheduled using JobService");
+                    } else {
+                        Log.e(OmahaBase.TAG, "Failed to schedule job");
                     }
                 });
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
index de16597d..e95ee6f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
@@ -5,13 +5,10 @@
 package org.chromium.chrome.browser.photo_picker;
 
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -21,12 +18,15 @@
 import android.support.annotation.Nullable;
 
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.util.ConversionUtils;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
-import java.io.FileNotFoundException;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -39,9 +39,6 @@
     // A tag for logging error messages.
     private static final String TAG = "ImageDecoderHost";
 
-    // A content resolver for providing file descriptors for the images.
-    private ContentResolver mContentResolver;
-
     // The number of successful decodes, per batch.
     private int mSuccessfulDecodes;
 
@@ -99,8 +96,8 @@
      * Class for keeping track of the data involved with each request.
      */
     private static class DecoderServiceParams {
-        // The URI for the file containing the bitmap to decode.
-        public Uri mUri;
+        // The path to the file containing the bitmap to decode.
+        public String mFilePath;
 
         // The requested size (width and height) of the bitmap, once decoded.
         public int mSize;
@@ -111,8 +108,8 @@
         // The timestamp for when the request was sent for decoding.
         long mTimestamp;
 
-        public DecoderServiceParams(Uri uri, int size, ImageDecodedCallback callback) {
-            mUri = uri;
+        public DecoderServiceParams(String filePath, int size, ImageDecodedCallback callback) {
+            mFilePath = filePath;
             mSize = size;
             mCallback = callback;
         }
@@ -142,7 +139,6 @@
             mCallbacks.add(sReadyCallbackForTesting);
         }
         mContext = context;
-        mContentResolver = mContext.getContentResolver();
     }
 
     /**
@@ -169,13 +165,13 @@
     /**
      * Accepts a request to decode a single image. Queues up the request and reports back
      * asynchronously on |callback|.
-     * @param uri The URI of the file to decode.
+     * @param filePath The path to the file to decode.
      * @param size The requested size (width and height) of the resulting bitmap.
      * @param callback The callback to use to communicate the decoding results.
      */
-    public void decodeImage(Uri uri, int size, ImageDecodedCallback callback) {
-        DecoderServiceParams params = new DecoderServiceParams(uri, size, callback);
-        mRequests.put(uri.getPath(), params);
+    public void decodeImage(String filePath, int size, ImageDecodedCallback callback) {
+        DecoderServiceParams params = new DecoderServiceParams(filePath, size, callback);
+        mRequests.put(filePath, params);
         if (mRequests.size() == 1) dispatchNextDecodeImageRequest();
     }
 
@@ -186,7 +182,7 @@
         if (mRequests.entrySet().iterator().hasNext()) {
             DecoderServiceParams params = mRequests.entrySet().iterator().next().getValue();
             params.mTimestamp = SystemClock.elapsedRealtime();
-            dispatchDecodeImageRequest(params.mUri, params.mSize);
+            dispatchDecodeImageRequest(params.mFilePath, params.mSize);
         } else {
             int totalRequests = mSuccessfulDecodes + mFailedDecodesRuntime + mFailedDecodesMemory;
             if (totalRequests > 0) {
@@ -210,24 +206,21 @@
         // As per the Android documentation, AIDL callbacks can (and will) happen on any thread, so
         // make sure the code runs on the UI thread, since further down the callchain the code will
         // end up creating UI objects.
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // Read the reply back from the service.
-                    String filePath = payload.getString(DecoderService.KEY_FILE_PATH);
-                    Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS);
-                    Bitmap bitmap = success
-                            ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAGE_BITMAP)
-                            : null;
-                    long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME);
-                    mSuccessfulDecodes++;
-                    closeRequest(filePath, bitmap, decodeTime);
-                } catch (RuntimeException e) {
-                    mFailedDecodesRuntime++;
-                } catch (OutOfMemoryError e) {
-                    mFailedDecodesMemory++;
-                }
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            try {
+                // Read the reply back from the service.
+                String filePath = payload.getString(DecoderService.KEY_FILE_PATH);
+                Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS);
+                Bitmap bitmap = success
+                        ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAGE_BITMAP)
+                        : null;
+                long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME);
+                mSuccessfulDecodes++;
+                closeRequest(filePath, bitmap, decodeTime);
+            } catch (RuntimeException e) {
+                mFailedDecodesRuntime++;
+            } catch (OutOfMemoryError e) {
+                mFailedDecodesMemory++;
             }
         });
     }
@@ -264,11 +257,13 @@
 
     /**
      * Communicates with the server to decode a single bitmap.
-     * @param uri The URI of the image on disk.
+     * @param filePath The path to the image on disk.
      * @param size The requested width and height of the resulting bitmap.
      */
-    private void dispatchDecodeImageRequest(Uri uri, int size) {
+    private void dispatchDecodeImageRequest(String filePath, int size) {
         // Obtain a file descriptor to send over to the sandboxed process.
+        File file = new File(filePath);
+        FileInputStream inputFile = null;
         ParcelFileDescriptor pfd = null;
         Bundle bundle = new Bundle();
 
@@ -276,36 +271,38 @@
         // contents, so we need to obtain a file descriptor to pass over.
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
         try {
-            AssetFileDescriptor afd = null;
             try {
-                afd = mContentResolver.openAssetFileDescriptor(uri, "r");
-            } catch (FileNotFoundException e) {
+                inputFile = new FileInputStream(file);
+                FileDescriptor fd = inputFile.getFD();
+                pfd = ParcelFileDescriptor.dup(fd);
+                bundle.putParcelable(DecoderService.KEY_FILE_DESCRIPTOR, pfd);
+            } catch (IOException e) {
                 Log.e(TAG, "Unable to obtain FileDescriptor: " + e);
-                closeRequest(uri.getPath(), null, -1);
-                return;
-            }
-            pfd = afd.getParcelFileDescriptor();
-            if (pfd == null) {
-                closeRequest(uri.getPath(), null, -1);
-                return;
+                closeRequest(filePath, null, -1);
             }
         } finally {
+            try {
+                if (inputFile != null) inputFile.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to close inputFile: " + e);
+            }
             StrictMode.setThreadPolicy(oldPolicy);
         }
 
+        if (pfd == null) return;
+
         // Prepare and send the data over.
-        bundle.putString(DecoderService.KEY_FILE_PATH, uri.getPath());
-        bundle.putParcelable(DecoderService.KEY_FILE_DESCRIPTOR, pfd);
+        bundle.putString(DecoderService.KEY_FILE_PATH, filePath);
         bundle.putInt(DecoderService.KEY_SIZE, size);
         try {
             mIRemoteService.decodeImage(bundle, this);
             pfd.close();
         } catch (RemoteException e) {
             Log.e(TAG, "Communications failed (Remote): " + e);
-            closeRequest(uri.getPath(), null, -1);
+            closeRequest(filePath, null, -1);
         } catch (IOException e) {
             Log.e(TAG, "Communications failed (IO): " + e);
-            closeRequest(uri.getPath(), null, -1);
+            closeRequest(filePath, null, -1);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java
index 789bbdd38..5d91aec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java
@@ -5,11 +5,7 @@
 package org.chromium.chrome.browser.photo_picker;
 
 import android.Manifest;
-import android.content.ContentResolver;
-import android.content.ContentUris;
 import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
 import android.os.Environment;
 import android.provider.MediaStore;
 
@@ -20,6 +16,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -45,9 +42,6 @@
     // The filter to apply to the list.
     private MimeTypeFilter mFilter;
 
-    // The ContentResolver to use to retrieve image metadata from disk.
-    private ContentResolver mContentResolver;
-
     // The camera directory undir DCIM.
     private static final String SAMPLE_DCIM_SOURCE_SUB_DIRECTORY = "Camera";
 
@@ -56,14 +50,12 @@
      * @param windowAndroid The window wrapper associated with the current activity.
      * @param callback The callback to use to communicate back the results.
      * @param filter The file filter to apply to the list.
-     * @param contentResolver The ContentResolver to use to retrieve image metadata from disk.
      */
-    public FileEnumWorkerTask(WindowAndroid windowAndroid, FilesEnumeratedCallback callback,
-            MimeTypeFilter filter, ContentResolver contentResolver) {
+    public FileEnumWorkerTask(
+            WindowAndroid windowAndroid, FilesEnumeratedCallback callback, MimeTypeFilter filter) {
         mWindowAndroid = windowAndroid;
         mCallback = callback;
         mFilter = filter;
-        mContentResolver = contentResolver;
     }
 
     /**
@@ -75,6 +67,30 @@
     }
 
     /**
+     * Recursively enumerate files in a directory (and subdirectories) and add them to a list.
+     * @param directory The parent directory to recursively traverse.
+     * @param pickerBitmaps The list to add the results to.
+     * @return True if traversing can continue, false if traversing was aborted and should stop.
+     */
+    private boolean traverseDir(File directory, List<PickerBitmap> pickerBitmaps) {
+        File[] files = directory.listFiles(mFilter);
+        if (files == null) return true;
+
+        for (File file : files) {
+            if (isCancelled()) return false;
+
+            if (file.isDirectory()) {
+                if (!traverseDir(file, pickerBitmaps)) return false;
+            } else {
+                pickerBitmaps.add(new PickerBitmap(
+                        file.getPath(), file.lastModified(), PickerBitmap.TileTypes.PICTURE));
+            }
+        }
+
+        return true;
+    }
+
+    /**
      * Enumerates (in the background) the image files on disk. Called on a non-UI thread
      * @param params Ignored, do not use.
      * @return A sorted list of images (by last-modified first).
@@ -87,48 +103,27 @@
 
         List<PickerBitmap> pickerBitmaps = new ArrayList<>();
 
-        final String[] selectColumns = {MediaStore.Images.Media._ID,
-                MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.DATA};
+        // TODO(finnur): Figure out which directories to scan and stop hard coding "Camera" above.
+        File[] sourceDirs = new File[] {
+                getCameraDirectory(),
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
+        };
 
-        final String whereClause = "(" + MediaStore.Images.Media.DATA + " LIKE ? OR "
-                + MediaStore.Images.Media.DATA + " LIKE ? OR " + MediaStore.Images.Media.DATA
-                + " LIKE ?) AND " + MediaStore.Images.Media.DATA + " NOT LIKE ?";
-
-        final String[] whereArgs = {// Include:
-                getCameraDirectory().toString() + "%",
-                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "%",
-                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
-                        + "%",
-                // Exclude low-quality sources, such as the screenshots directory:
-                // TODO(finnur): As of the Q SDK this can be converted to DIRECTORY_SCREENSHOTS.
-                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
-                        + "/Screenshots/"
-                        + "%"};
-
-        final String orderBy = MediaStore.Images.Media.DATE_TAKEN + " DESC";
-
-        Cursor imageCursor = mContentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                selectColumns, whereClause, whereArgs, orderBy);
-
-        while (imageCursor.moveToNext()) {
-            int dataIndex = imageCursor.getColumnIndex(MediaStore.Images.Media.DATA);
-            int dateTakenIndex = imageCursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
-            int idIndex = imageCursor.getColumnIndex(MediaStore.Images.ImageColumns._ID);
-            Uri uri = ContentUris.withAppendedId(
-                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageCursor.getInt(idIndex));
-            long dateTaken = imageCursor.getLong(dateTakenIndex);
-            pickerBitmaps.add(new PickerBitmap(uri, dateTaken, PickerBitmap.TileTypes.PICTURE));
+        for (File directory : sourceDirs) {
+            if (!traverseDir(directory, pickerBitmaps)) return null;
         }
-        imageCursor.close();
 
-        pickerBitmaps.add(0, new PickerBitmap(null, 0, PickerBitmap.TileTypes.GALLERY));
+        Collections.sort(pickerBitmaps);
+
+        pickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.TileTypes.GALLERY));
         boolean hasCameraAppAvailable =
                 mWindowAndroid.canResolveActivity(new Intent(MediaStore.ACTION_IMAGE_CAPTURE));
         boolean hasOrCanRequestCameraPermission =
                 mWindowAndroid.hasPermission(Manifest.permission.CAMERA)
                 || mWindowAndroid.canRequestPermission(Manifest.permission.CAMERA);
         if (hasCameraAppAvailable && hasOrCanRequestCameraPermission) {
-            pickerBitmaps.add(0, new PickerBitmap(null, 0, PickerBitmap.TileTypes.CAMERA));
+            pickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.TileTypes.CAMERA));
         }
 
         return pickerBitmaps;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java
index ac466f21..ae7a10ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java
@@ -6,7 +6,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.net.Uri;
 import android.support.v7.app.AlertDialog;
 
 import org.chromium.base.ActivityState;
@@ -56,7 +55,7 @@
 
         // PhotoPickerListener:
         @Override
-        public void onPhotoPickerUserAction(@PhotoPickerAction int action, Uri[] photos) {
+        public void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos) {
             mExternalIntentSelected = false;
             if (action == PhotoPickerAction.LAUNCH_GALLERY
                     || action == PhotoPickerAction.LAUNCH_CAMERA) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmap.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmap.java
index 27f46a29..ffc24c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmap.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmap.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.photo_picker;
 
-import android.net.Uri;
 import android.support.annotation.IntDef;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -27,8 +26,8 @@
         int GALLERY = 2;
     }
 
-    // The URI of the bitmap to show.
-    private Uri mUri;
+    // The file path to the bitmap to show.
+    private String mFilePath;
 
     // When the bitmap was last modified on disk.
     private long mLastModified;
@@ -39,22 +38,22 @@
 
     /**
      * The PickerBitmap constructor.
-     * @param uri The URI for the bitmap to show.
+     * @param filePath The file path to the bitmap to show.
      * @param lastModified When the bitmap was last modified on disk.
      * @param type The type of tile involved.
      */
-    public PickerBitmap(Uri uri, long lastModified, @TileTypes int type) {
-        mUri = uri;
+    public PickerBitmap(String filePath, long lastModified, @TileTypes int type) {
+        mFilePath = filePath;
         mLastModified = lastModified;
         mType = type;
     }
 
     /**
-     * Accessor for the URI.
-     * @return The URI for this PickerBitmap object.
+     * Accessor for the filepath.
+     * @return The file path for this PickerBitmap object.
      */
-    public Uri getUri() {
-        return mUri;
+    public String getFilePath() {
+        return mFilePath;
     }
 
     /**
@@ -62,10 +61,9 @@
      * @return The filename (without the extension and path).
      */
     public String getFilenameWithoutExtension() {
-        String filePath = mUri.getPath();
-        int index = filePath.lastIndexOf("/");
-        if (index == -1) return filePath;
-        return filePath.substring(index + 1, filePath.length());
+        int index = mFilePath.lastIndexOf("/");
+        if (index == -1) return mFilePath;
+        return mFilePath.substring(index + 1, mFilePath.length());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java
index ecdae499..3ae3759 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java
@@ -59,7 +59,7 @@
                     .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         }
 
-        if (!TextUtils.equals(mBitmapDetails.getUri().getPath(), filePath)) {
+        if (!TextUtils.equals(mBitmapDetails.getFilePath(), filePath)) {
             return;
         }
 
@@ -87,7 +87,7 @@
             return PickerAdapter.DecodeActions.NO_ACTION;
         }
 
-        String filePath = mBitmapDetails.getUri().getPath();
+        String filePath = mBitmapDetails.getFilePath();
         Bitmap original = mCategoryView.getHighResBitmaps().get(filePath);
         if (original != null) {
             mItemView.initialize(mBitmapDetails, original, false);
@@ -109,17 +109,14 @@
             mItemView.initialize(mBitmapDetails, null, true);
         }
 
-        mCategoryView.getDecoderServiceHost().decodeImage(mBitmapDetails.getUri(), size, this);
+        mCategoryView.getDecoderServiceHost().decodeImage(filePath, size, this);
         return PickerAdapter.DecodeActions.DECODE;
     }
 
     /**
-     * Returns the file path of the current request, or null if no request is in progress for this
-     * holder.
+     * Returns the file path of the current request.
      */
     public String getFilePath() {
-        if (mBitmapDetails == null || mBitmapDetails.type() != PickerBitmap.TileTypes.PICTURE)
-            return null;
-        return mBitmapDetails.getUri().getPath();
+        return mBitmapDetails == null ? null : mBitmapDetails.getFilePath();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
index d18e6cb..58716e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
@@ -9,7 +9,6 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.SystemClock;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -367,8 +366,8 @@
         }
 
         mEnumStartTime = SystemClock.elapsedRealtime();
-        mWorkerTask = new FileEnumWorkerTask(mActivity.getWindowAndroid(), this,
-                new MimeTypeFilter(mMimeTypes, true), mActivity.getContentResolver());
+        mWorkerTask = new FileEnumWorkerTask(
+                mActivity.getWindowAndroid(), this, new MimeTypeFilter(mMimeTypes, true));
         mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
@@ -378,10 +377,10 @@
     private void notifyPhotosSelected() {
         List<PickerBitmap> selectedFiles = mSelectionDelegate.getSelectedItemsAsList();
         Collections.sort(selectedFiles);
-        Uri[] photos = new Uri[selectedFiles.size()];
+        String[] photos = new String[selectedFiles.size()];
         int i = 0;
         for (PickerBitmap bitmap : selectedFiles) {
-            photos[i++] = bitmap.getUri();
+            photos[i++] = bitmap.getFilePath();
         }
 
         executeAction(
@@ -432,7 +431,7 @@
      * @param umaId The UMA value to record with the action.
      */
     private void executeAction(
-            @PhotoPickerListener.PhotoPickerAction int action, Uri[] photos, int umaId) {
+            @PhotoPickerListener.PhotoPickerAction int action, String[] photos, int umaId) {
         mListener.onPhotoPickerUserAction(action, photos);
         mDialog.dismiss();
         UiUtils.onPhotoPickerDismissed();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index de9042a..494fd03 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -173,10 +173,10 @@
     private static final String NTP_BUTTON_VARIANT_KEY = "ntp_button_variant";
 
     /**
-     * Whether or not to inflate the ChromeTabbedActivity toolbar on a background thread async.
-     * Default value is false.
+     * Deprecated in M75. This value may still exist in shared preferences file. Do not reuse.
      */
-    public static final String INFLATE_TOOLBAR_ON_BACKGROUND_THREAD_KEY =
+    @Deprecated
+    private static final String INFLATE_TOOLBAR_ON_BACKGROUND_THREAD_KEY =
             "inflate_toolbar_on_background_thread";
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/AccountsChangedReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/services/AccountsChangedReceiver.java
index cdb66d0..52b98de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/AccountsChangedReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/AccountsChangedReceiver.java
@@ -11,15 +11,16 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.task.AsyncTask;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.init.BrowserParts;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.EmptyBrowserParts;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.SigninHelper;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * This receiver is notified when accounts are added, accounts are removed, or
@@ -63,14 +64,11 @@
         BrowserParts parts = new EmptyBrowserParts() {
             @Override
             public void finishNativeInitialization() {
-                ThreadUtils.runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        // TODO(bsazonov): Check whether invalidateAccountSeedStatus is needed here.
-                        IdentityServicesProvider.getAccountTrackerService()
-                                .invalidateAccountSeedStatus(false /* don't refresh right now */);
-                        SigninHelper.get().validateAccountSettings(true);
-                    }
+                PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+                    // TODO(bsazonov): Check whether invalidateAccountSeedStatus is needed here.
+                    IdentityServicesProvider.getAccountTrackerService().invalidateAccountSeedStatus(
+                            false /* don't refresh right now */);
+                    SigninHelper.get().validateAccountSettings(true);
                 });
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
index 1094a09a..624d59b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
@@ -19,6 +19,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.metrics.CachedMetrics;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
@@ -27,6 +28,7 @@
 import org.chromium.components.gcm_driver.GCMDriver;
 import org.chromium.components.gcm_driver.GCMMessage;
 import org.chromium.components.gcm_driver.LazySubscriptionsManager;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * Receives Downstream messages and status of upstream messages from GCM.
@@ -52,19 +54,16 @@
         }
 
         // Dispatch the message to the GCM Driver for native features.
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                GCMMessage message = null;
-                try {
-                    message = new GCMMessage(from, data);
-                } catch (IllegalArgumentException e) {
-                    Log.e(TAG, "Received an invalid GCM Message", e);
-                    return;
-                }
-
-                scheduleOrDispatchMessageToDriver(message);
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            GCMMessage message = null;
+            try {
+                message = new GCMMessage(from, data);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Received an invalid GCM Message", e);
+                return;
             }
+
+            scheduleOrDispatchMessageToDriver(message);
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncPromoView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncPromoView.java
index 52dcb84..fe532cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncPromoView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncPromoView.java
@@ -15,7 +15,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import org.chromium.base.ThreadUtils;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.signin.AccountSigninActivity.AccessPoint;
@@ -23,6 +23,7 @@
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.components.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * A View that shows the user the next step they must complete to start syncing their data (eg.
@@ -207,6 +208,6 @@
     @Override
     public void androidSyncSettingsChanged() {
         // AndroidSyncSettings calls this method from non-UI threads.
-        ThreadUtils.runOnUiThread(this::update);
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, this::update);
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
index 099d6bac..0b5d7e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -16,6 +16,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
 import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.invalidation.InvalidationController;
@@ -26,6 +27,7 @@
 import org.chromium.components.sync.ModelType;
 import org.chromium.components.sync.Passphrase;
 import org.chromium.components.sync.StopSource;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * SyncController handles the coordination of sync state between the invalidation controller,
@@ -207,12 +209,7 @@
      */
     @Override
     public void androidSyncSettingsChanged() {
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                updateSyncStateFromAndroid();
-            }
-        });
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { updateSyncStateFromAndroid(); });
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index e92175a..d1a92229 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -1217,7 +1217,7 @@
         for (TabPersistentStoreObserver observer : mObservers) {
             // mergeState() starts an AsyncTask to call this and this calls
             // onTabStateInitialized which should be called from the UI thread.
-            ThreadUtils.runOnUiThread(() -> observer.onStateLoaded());
+            PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> observer.onStateLoaded());
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java
index 70a91ec..1cc98c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider.IncognitoStateObserver;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 
 /** A ThemeColorProvider for the app theme (incognito or standard theming). */
 public class AppThemeColorProvider extends ThemeColorProvider implements IncognitoStateObserver {
@@ -39,8 +40,13 @@
     /** Whether app is in overview mode. */
     private boolean mIsOverviewVisible;
 
+    /** The activity {@link Context}. */
+    private final Context mActivityContext;
+
     AppThemeColorProvider(Context context) {
         super(context);
+
+        mActivityContext = context;
         mLightPrimaryColor = ApiCompatibilityUtils.getColor(
                 context.getResources(), R.color.modern_primary_color);
         mDarkPrimaryColor = ApiCompatibilityUtils.getColor(
@@ -81,8 +87,10 @@
         final boolean isAccessibilityEnabled = DeviceClassManager.enableAccessibilityLayout();
         final boolean isHorizontalTabSwitcherEnabled =
                 ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID);
+        final boolean isTabGridEnabled =
+                FeatureUtilities.isGridTabSwitcherEnabled(mActivityContext);
         final boolean shouldUseDarkBackground = mIsIncognito
-                && (isAccessibilityEnabled || isHorizontalTabSwitcherEnabled
+                && (isAccessibilityEnabled || isHorizontalTabSwitcherEnabled || isTabGridEnabled
                         || !mIsOverviewVisible);
 
         updatePrimaryColor(shouldUseDarkBackground ? mDarkPrimaryColor : mLightPrimaryColor, false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index b10330c..dd3e9a575 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -112,7 +112,6 @@
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
-import org.chromium.ui.AsyncViewProvider;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.widget.Toast;
@@ -170,7 +169,6 @@
      */
     private static final int MINIMUM_LOAD_PROGRESS = 5;
 
-    private final AsyncViewProvider<ToolbarLayout> mToolbarProvider;
     private final IncognitoStateProvider mIncognitoStateProvider;
     private final TabCountProvider mTabCountProvider;
     private final ThemeColorProvider mTabThemeColorProvider;
@@ -187,7 +185,6 @@
     private Profile mCurrentProfile;
     private BookmarkBridge mBookmarkBridge;
     private TemplateUrlServiceObserver mTemplateUrlObserver;
-    @Nullable
     private LocationBar mLocationBar;
     private FindToolbarManager mFindToolbarManager;
     private AppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
@@ -223,7 +220,6 @@
 
     private TextBubble mTextBubble;
 
-    private boolean mToolbarInflationComplete;
     private boolean mInitializedWithNative;
     private Runnable mOnInitializedRunnable;
 
@@ -311,31 +307,8 @@
 
         mAppThemeColorProvider = new AppThemeColorProvider(mActivity);
 
-        mToolbarProvider = AsyncViewProvider.of(controlContainer, R.id.toolbar_stub, R.id.toolbar);
-        mToolbar = new TopToolbarCoordinator(controlContainer, mToolbarProvider);
-        mToolbarProvider.whenLoaded((toolbar)
-                                            -> onToolbarInflationComplete(menuHandler,
-                                                    appMenuPropertiesDelegate, invalidator));
-    }
-
-    @Override
-    public void onScrimClick() {
-        setUrlBarFocus(false);
-    }
-
-    @Override
-    public void onScrimVisibilityChanged(boolean visible) {
-        if (visible) {
-            mActivity.addViewObscuringAllTabs(mActivity.getScrim());
-        } else {
-            mActivity.removeViewObscuringAllTabs(mActivity.getScrim());
-        }
-    }
-
-    private void onToolbarInflationComplete(final AppMenuHandler menuHandler,
-            AppMenuPropertiesDelegate appMenuPropertiesDelegate, Invalidator invalidator) {
-        mToolbarInflationComplete = true;
-
+        mToolbar =
+                new TopToolbarCoordinator(controlContainer, mActivity.findViewById(R.id.toolbar));
         mActionModeController = new ActionModeController(mActivity, mActionBarDelegate);
         mActionModeController.setCustomSelectionActionModeCallback(mToolbarActionModeCallback);
 
@@ -366,7 +339,7 @@
 
         mAppMenuPropertiesDelegate = appMenuPropertiesDelegate;
 
-        mOmniboxStartupMetrics = new OmniboxStartupMetrics(mActivity);
+        mOmniboxStartupMetrics = new OmniboxStartupMetrics(activity);
 
         mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
             @Override
@@ -740,11 +713,25 @@
                 mActivity.isTablet() ? mAppThemeColorProvider : mTabThemeColorProvider);
     }
 
+    @Override
+    public void onScrimVisibilityChanged(boolean visible) {
+        if (visible) {
+            mActivity.addViewObscuringAllTabs(mActivity.getScrim());
+        } else {
+            mActivity.removeViewObscuringAllTabs(mActivity.getScrim());
+        }
+    }
+
+    @Override
+    public void onScrimClick() {
+        setUrlBarFocus(false);
+    }
+
     /**
      * @return  Whether the UrlBar currently has focus.
      */
     public boolean isUrlBarFocused() {
-        return mLocationBar == null ? false : mLocationBar.isUrlBarFocused();
+        return mLocationBar.isUrlBarFocused();
     }
 
     /**
@@ -861,7 +848,7 @@
      * @param featureName The associated feature name.
      */
     public void showDownloadPageTextBubble(final Tab tab, String featureName) {
-        if (tab == null || !mToolbarInflationComplete) return;
+        if (tab == null) return;
 
         // TODO(shaktisahu): Find out if the download menu button is enabled (crbug/712438).
         ChromeActivity activity = tab.getActivity();
@@ -894,7 +881,7 @@
      * @param featureName The associated feature name.
      */
     public void showTranslateMenuButtonTextBubble(final Tab tab, String featureName) {
-        if (tab == null || !mToolbarInflationComplete) return;
+        if (tab == null) return;
         ChromeActivity activity = tab.getActivity();
 
         if (!mAppMenuPropertiesDelegate.isTranslateMenuItemVisible(tab)) return;
@@ -929,82 +916,79 @@
             OnClickListener customTabsBackClickHandler) {
         assert !mInitializedWithNative;
 
-        mToolbarProvider.whenLoaded((toolbar) -> {
-            mTabModelSelector = tabModelSelector;
+        mTabModelSelector = tabModelSelector;
 
-            mToolbar.initializeWithNative(tabModelSelector, controlsVisibilityDelegate,
-                    layoutManager, tabSwitcherClickHandler, newTabClickHandler,
-                    bookmarkClickHandler, customTabsBackClickHandler);
+        mToolbar.initializeWithNative(tabModelSelector, controlsVisibilityDelegate, layoutManager,
+                tabSwitcherClickHandler, newTabClickHandler, bookmarkClickHandler,
+                customTabsBackClickHandler);
 
-            toolbar.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
-                @Override
-                public void onViewDetachedFromWindow(View v) {}
+        mToolbar.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewDetachedFromWindow(View v) {}
 
-                @Override
-                public void onViewAttachedToWindow(View v) {
-                    // As we have only just registered for notifications, any that were sent prior
-                    // to this may have been missed. Calling refreshSelectedTab in case we missed
-                    // the initial selection notification.
-                    refreshSelectedTab();
-                }
-            });
-
-            mLocationBarModel.initializeWithNative();
-
-            mFindToolbarManager = findToolbarManager;
-
-            assert controlsVisibilityDelegate != null;
-            mControlsVisibilityDelegate = controlsVisibilityDelegate;
-
-            mNativeLibraryReady = false;
-
-            mFindToolbarManager.addObserver(mFindToolbarObserver);
-
-            if (overviewModeBehavior != null) {
-                mOverviewModeBehavior = overviewModeBehavior;
-                mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
-                mAppThemeColorProvider.setOverviewModeBehavior(mOverviewModeBehavior);
-            }
-            if (layoutManager != null) {
-                mLayoutManager = layoutManager;
-                mLayoutManager.addSceneChangeObserver(mSceneChangeObserver);
-            }
-
-            if (mBottomControlsCoordinator != null) {
-                final OnClickListener closeTabsClickListener = v -> {
-                    recordBottomToolbarUseForIPH();
-                    final boolean isIncognito = mTabModelSelector.isIncognitoSelected();
-                    if (isIncognito) {
-                        RecordUserAction.record("MobileToolbarCloseAllIncognitoTabsButtonTap");
-                    } else {
-                        RecordUserAction.record("MobileToolbarCloseAllRegularTabsButtonTap");
-                    }
-
-                    mTabModelSelector.getModel(isIncognito).closeAllTabs();
-                };
-                mAppMenuButtonHelper.setOnClickRunnable(() -> recordBottomToolbarUseForIPH());
-                mBottomControlsCoordinator.initializeWithNative(mActivity,
-                        mActivity.getCompositorViewHolder().getResourceManager(),
-                        mActivity.getCompositorViewHolder().getLayoutManager(),
-                        wrapBottomToolbarClickListenerForIPH(tabSwitcherClickHandler),
-                        wrapBottomToolbarClickListenerForIPH(newTabClickHandler),
-                        closeTabsClickListener, mAppMenuButtonHelper, mOverviewModeBehavior,
-                        mActivity.getWindowAndroid(), mTabCountProvider, mIncognitoStateProvider,
-                        mActivity.findViewById(R.id.control_container));
-
-                // Allow the bottom toolbar to be focused in accessibility after the top toolbar.
-                ApiCompatibilityUtils.setAccessibilityTraversalBefore(
-                        mLocationBar.getContainerView(), R.id.bottom_toolbar);
-            }
-
-            onNativeLibraryReady();
-            mInitializedWithNative = true;
-
-            if (mOnInitializedRunnable != null) {
-                mOnInitializedRunnable.run();
-                mOnInitializedRunnable = null;
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                // As we have only just registered for notifications, any that were sent prior
+                // to this may have been missed. Calling refreshSelectedTab in case we missed
+                // the initial selection notification.
+                refreshSelectedTab();
             }
         });
+
+        mLocationBarModel.initializeWithNative();
+
+        mFindToolbarManager = findToolbarManager;
+
+        assert controlsVisibilityDelegate != null;
+        mControlsVisibilityDelegate = controlsVisibilityDelegate;
+
+        mNativeLibraryReady = false;
+
+        mFindToolbarManager.addObserver(mFindToolbarObserver);
+
+        if (overviewModeBehavior != null) {
+            mOverviewModeBehavior = overviewModeBehavior;
+            mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
+            mAppThemeColorProvider.setOverviewModeBehavior(mOverviewModeBehavior);
+        }
+        if (layoutManager != null) {
+            mLayoutManager = layoutManager;
+            mLayoutManager.addSceneChangeObserver(mSceneChangeObserver);
+        }
+
+        if (mBottomControlsCoordinator != null) {
+            final OnClickListener closeTabsClickListener = v -> {
+                recordBottomToolbarUseForIPH();
+                final boolean isIncognito = mTabModelSelector.isIncognitoSelected();
+                if (isIncognito) {
+                    RecordUserAction.record("MobileToolbarCloseAllIncognitoTabsButtonTap");
+                } else {
+                    RecordUserAction.record("MobileToolbarCloseAllRegularTabsButtonTap");
+                }
+
+                mTabModelSelector.getModel(isIncognito).closeAllTabs();
+            };
+            mAppMenuButtonHelper.setOnClickRunnable(() -> recordBottomToolbarUseForIPH());
+            mBottomControlsCoordinator.initializeWithNative(mActivity,
+                    mActivity.getCompositorViewHolder().getResourceManager(),
+                    mActivity.getCompositorViewHolder().getLayoutManager(),
+                    wrapBottomToolbarClickListenerForIPH(tabSwitcherClickHandler),
+                    wrapBottomToolbarClickListenerForIPH(newTabClickHandler),
+                    closeTabsClickListener, mAppMenuButtonHelper, mOverviewModeBehavior,
+                    mActivity.getWindowAndroid(), mTabCountProvider, mIncognitoStateProvider,
+                    mActivity.findViewById(R.id.control_container));
+
+            // Allow the bottom toolbar to be focused in accessibility after the top toolbar.
+            ApiCompatibilityUtils.setAccessibilityTraversalBefore(
+                    mLocationBar.getContainerView(), R.id.bottom_toolbar);
+        }
+
+        onNativeLibraryReady();
+        mInitializedWithNative = true;
+        if (mOnInitializedRunnable != null) {
+            mOnInitializedRunnable.run();
+            mOnInitializedRunnable = null;
+        }
     }
 
     /**
@@ -1076,7 +1060,6 @@
     /**
      * @return The toolbar interface that this manager handles.
      */
-    @Nullable
     public Toolbar getToolbar() {
         return mToolbar;
     }
@@ -1112,7 +1095,6 @@
      * @return The view containing the security icon.
      */
     public View getSecurityIconView() {
-        if (mLocationBar == null) return null;
         return mLocationBar.getSecurityIconView();
     }
 
@@ -1431,8 +1413,6 @@
      */
     @Override
     public void onUrlFocusChange(boolean hasFocus) {
-        assert mToolbarInflationComplete;
-
         mToolbar.onUrlFocusChange(hasFocus);
 
         if (hasFocus) mOmniboxStartupMetrics.onUrlBarFocused();
@@ -1550,14 +1530,14 @@
     }
 
     /**
-     * @see ToolbarLayout#setUrlBarHidden(boolean)
+     * @see TopToolbarCoordinator#setUrlBarHidden(boolean)
      */
     public void setUrlBarHidden(boolean hidden) {
         mToolbar.setUrlBarHidden(hidden);
     }
 
     /**
-     * @see ToolbarLayout#getContentPublisher()
+     * @see TopToolbarCoordinator#getContentPublisher()
      */
     public String getContentPublisher() {
         return mToolbar.getContentPublisher();
@@ -1606,7 +1586,6 @@
      * change the focus state of the location bar.
      */
     public void revertLocationBarChanges() {
-        if (mLocationBar == null) return;
         mLocationBar.revertChanges();
     }
 
@@ -1651,7 +1630,6 @@
      * inheriting classes the chance to update the button visuals as well.
      */
     private void updateButtonStatus() {
-        assert mToolbarInflationComplete;
         Tab currentTab = mLocationBarModel.getTab();
         boolean tabCrashed = currentTab != null && SadTab.isShowing(currentTab);
 
@@ -1666,7 +1644,6 @@
     }
 
     private void updateBookmarkButtonStatus() {
-        assert mToolbarInflationComplete;
         Tab currentTab = mLocationBarModel.getTab();
         boolean isBookmarked =
                 currentTab != null && currentTab.getBookmarkId() != Tab.INVALID_BOOKMARK_ID;
@@ -1676,7 +1653,6 @@
     }
 
     private void updateReloadState(boolean tabCrashed) {
-        assert mToolbarInflationComplete;
         Tab currentTab = mLocationBarModel.getTab();
         boolean isLoading = false;
         if (!tabCrashed) {
@@ -1690,7 +1666,6 @@
      * Triggered when the selected tab has changed.
      */
     private void refreshSelectedTab() {
-        assert mToolbarInflationComplete;
         Tab tab = null;
         if (mPreselectedTabId != Tab.INVALID_TAB_ID) {
             tab = mTabModelSelector.getTabById(mPreselectedTabId);
@@ -1764,8 +1739,6 @@
     }
 
     private void updateCurrentTabDisplayStatus() {
-        assert mLocationBar != null;
-
         Tab tab = mLocationBarModel.getTab();
         mLocationBar.setUrlToPageUrl();
 
@@ -1791,13 +1764,11 @@
     }
 
     private void updateTabLoadingState(boolean updateUrl) {
-        assert mLocationBar != null;
         mLocationBar.updateLoadingState(updateUrl);
         if (updateUrl) updateButtonStatus();
     }
 
     private void updateLoadProgress(int progress) {
-        assert mToolbarInflationComplete;
         // If it's a native page, progress bar is already hidden or being hidden, so don't update
         // the value.
         // TODO(kkimlabs): Investigate back/forward navigation with native page & web content and
@@ -1813,7 +1784,6 @@
     }
 
     private void finishLoadProgress(boolean delayed) {
-        assert mToolbarInflationComplete;
         mLoadProgressSimulator.cancel();
         mToolbar.finishLoadProgress(delayed);
     }
@@ -1822,7 +1792,6 @@
      * Only start showing the progress bar if it is not already started.
      */
     private void startLoadProgress() {
-        assert mToolbarInflationComplete;
         if (mToolbar.isProgressStarted()) return;
         mToolbar.startLoadProgress();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
index 5a53ec3..efab768f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
@@ -142,6 +142,9 @@
     // Whether dark tint should be applied to icons and text.
     private boolean mUseDarkColors;
 
+    private final ColorStateList mDarkModeTint;
+    private final ColorStateList mLightModeTint;
+
     private ValueAnimator mBrandColorTransitionAnimation;
     private boolean mBrandColorTransitionActive;
 
@@ -163,6 +166,9 @@
      */
     public CustomTabToolbar(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        mDarkModeTint = ColorUtils.getThemedToolbarIconTint(context, false);
+        mLightModeTint = ColorUtils.getThemedToolbarIconTint(context, true);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
index 9c198ab7f..aa60869 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -25,9 +25,7 @@
 import org.chromium.chrome.browser.widget.ControlContainer;
 import org.chromium.chrome.browser.widget.ToolbarProgressBar;
 import org.chromium.chrome.browser.widget.ViewResourceFrameLayout;
-import org.chromium.ui.AsyncViewStub;
 import org.chromium.ui.KeyboardVisibilityDelegate;
-import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.resources.dynamics.ViewResourceAdapter;
 import org.chromium.ui.widget.OptimizedFrameLayout;
 
@@ -92,19 +90,9 @@
         try (TraceEvent te = TraceEvent.scoped("ToolbarControlContainer.initWithToolbar")) {
             mToolbarContainer =
                     (ToolbarViewResourceFrameLayout) findViewById(R.id.toolbar_container);
-            View viewStub = findViewById(R.id.toolbar_stub);
-            if (viewStub instanceof AsyncViewStub) {
-                AsyncViewStub toolbarStub = (AsyncViewStub) viewStub;
-                toolbarStub.setLayoutResource(toolbarLayoutId);
-                toolbarStub.setShouldInflateOnBackgroundThread(
-                        !DeviceFormFactor.isNonMultiDisplayContextOnTablet(getContext())
-                        && FeatureUtilities.shouldInflateToolbarOnBackgroundThread());
-                toolbarStub.inflate();
-            } else {
-                ViewStub toolbarStub = (ViewStub) viewStub;
-                toolbarStub.setLayoutResource(toolbarLayoutId);
-                toolbarStub.inflate();
-            }
+            ViewStub toolbarStub = findViewById(R.id.toolbar_stub);
+            toolbarStub.setLayoutResource(toolbarLayoutId);
+            toolbarStub.inflate();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index d7865c8..db0db8ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -25,6 +25,8 @@
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ThemeColorProvider;
+import org.chromium.chrome.browser.ThemeColorProvider.TintObserver;
 import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.compositor.Invalidator;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
@@ -50,7 +52,7 @@
  * interaction that are not from Views inside Toolbar hierarchy all interactions should be done
  * through {@link Toolbar} rather than using this class directly.
  */
-public abstract class ToolbarLayout extends FrameLayout {
+public abstract class ToolbarLayout extends FrameLayout implements TintObserver {
     private Invalidator mInvalidator;
 
     private final int[] mTempPosition = new int[2];
@@ -60,8 +62,7 @@
      */
     private MenuButton mMenuButtonWrapper;
 
-    protected final ColorStateList mDarkModeTint;
-    protected final ColorStateList mLightModeTint;
+    private final ColorStateList mDefaultTint;
 
     private ToolbarDataProvider mToolbarDataProvider;
     private ToolbarTabController mToolbarTabController;
@@ -75,13 +76,14 @@
 
     private boolean mFindInPageToolbarShowing;
 
+    private ThemeColorProvider mThemeColorProvider;
+
     /**
      * Basic constructor for {@link ToolbarLayout}.
      */
     public ToolbarLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mDarkModeTint = ColorUtils.getThemedToolbarIconTint(getContext(), false);
-        mLightModeTint = ColorUtils.getThemedToolbarIconTint(getContext(), true);
+        mDefaultTint = ColorUtils.getThemedToolbarIconTint(getContext(), false);
         mProgressBar = createProgressBar();
 
         addOnLayoutChangeListener(new OnLayoutChangeListener() {
@@ -122,7 +124,38 @@
     /**
      * Cleans up any code as necessary.
      */
-    void destroy() {}
+    void destroy() {
+        if (mThemeColorProvider != null) {
+            mThemeColorProvider.removeTintObserver(this);
+            mThemeColorProvider = null;
+        }
+    }
+
+    /**
+     * @param themeColorProvider The {@link ThemeColorProvider} used for tinting the toolbar
+     *                           buttons.
+     */
+    void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
+        mThemeColorProvider = themeColorProvider;
+        mThemeColorProvider.addTintObserver(this);
+    }
+
+    /**
+     * @return The tint the toolbar buttons should use.
+     */
+    protected ColorStateList getTint() {
+        return mThemeColorProvider == null ? mDefaultTint : mThemeColorProvider.getTint();
+    }
+
+    /**
+     * @return Whether to use light assets.
+     */
+    protected boolean useLight() {
+        return mThemeColorProvider != null && mThemeColorProvider.useLight();
+    }
+
+    @Override
+    public void onTintChanged(ColorStateList tint, boolean useLight) {}
 
     /**
      * Set the height that the progress bar should be.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 72e3768..140278f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -151,7 +151,6 @@
     @ViewDebug.ExportedProperty(category = "chrome")
     protected boolean mTextureCaptureMode;
     private boolean mForceTextureCapture;
-    private boolean mUseLightDrawablesForTextureCapture;
     private boolean mLightDrawablesUsedForLastTextureCapture;
     private int mTabCountForLastTextureCapture;
 
@@ -275,7 +274,6 @@
     }
 
     protected @VisualState int mVisualState = VisualState.NORMAL;
-    protected boolean mUseLightToolbarDrawables;
 
     private NewTabPage mVisibleNewTabPage;
     private float mPreTextureCaptureAlpha = 1f;
@@ -1285,16 +1283,14 @@
                     menuButton.getHeight() - menuButton.getPaddingBottom());
             translateCanvasToView(mToolbarButtonsContainer, menuButton, canvas);
             mTabSwitcherAnimationMenuDrawable.setAlpha(rgbAlpha);
-            int color = mUseLightDrawablesForTextureCapture ? mLightModeDefaultColor
-                                                            : mDarkModeDefaultColor;
+            int color = useLight() ? mLightModeDefaultColor : mDarkModeDefaultColor;
             mTabSwitcherAnimationMenuDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
             mTabSwitcherAnimationMenuDrawable.draw(canvas);
         }
 
         // Draw the menu badge if necessary.
-        Drawable badgeDrawable = mUseLightDrawablesForTextureCapture
-                ? mTabSwitcherAnimationMenuBadgeLightDrawable
-                : mTabSwitcherAnimationMenuBadgeDarkDrawable;
+        Drawable badgeDrawable = useLight() ? mTabSwitcherAnimationMenuBadgeLightDrawable
+                                            : mTabSwitcherAnimationMenuBadgeDarkDrawable;
 
         final View menuBadge = getMenuBadge();
         if (menuBadge != null && !mIsBottomToolbarVisible && isShowingAppMenuUpdateBadge()
@@ -1307,7 +1303,7 @@
             badgeDrawable.draw(canvas);
         }
 
-        mLightDrawablesUsedForLastTextureCapture = mUseLightDrawablesForTextureCapture;
+        mLightDrawablesUsedForLastTextureCapture = useLight();
         mWasBottomToolbarVisibleForLastTextureCapture = mIsBottomToolbarVisible;
 
         if (mTabSwitcherAnimationTabStackDrawable != null && mToggleTabStackButton != null
@@ -1541,11 +1537,9 @@
     @Override
     public boolean setForceTextureCapture(boolean forceTextureCapture) {
         if (forceTextureCapture) {
-            setUseLightDrawablesForTextureCapture();
             // Only force a texture capture if the tint for the toolbar drawables is changing or
             // if the tab count has changed since the last texture capture.
-            mForceTextureCapture =
-                    mLightDrawablesUsedForLastTextureCapture != mUseLightDrawablesForTextureCapture
+            mForceTextureCapture = mLightDrawablesUsedForLastTextureCapture != useLight()
                     || mWasBottomToolbarVisibleForLastTextureCapture != mIsBottomToolbarVisible;
 
             if (mTabSwitcherAnimationTabStackDrawable != null && mToggleTabStackButton != null) {
@@ -1617,6 +1611,26 @@
         }
     }
 
+    @Override
+    public void onTintChanged(ColorStateList tint, boolean useLight) {
+        if (mHomeButton != null) {
+            ApiCompatibilityUtils.setImageTintList(mHomeButton, tint);
+        }
+
+        if (mToggleTabStackButton != null) {
+            mToggleTabStackButton.setUseLightDrawables(useLight);
+            if (mTabSwitcherAnimationTabStackDrawable != null) {
+                mTabSwitcherAnimationTabStackDrawable.setTint(tint);
+            }
+        }
+
+        if (mExperimentalButton != null) {
+            ApiCompatibilityUtils.setImageTintList(mExperimentalButton, tint);
+        }
+
+        if (mLayoutUpdateHost != null) mLayoutUpdateHost.requestUpdate();
+    }
+
     private void removeHomeButton() {
         mHomeButton.setVisibility(GONE);
     }
@@ -1624,8 +1638,6 @@
     private void addHomeButton() {
         mHomeButton.setVisibility(
                 urlHasFocus() || isTabSwitcherAnimationRunning() ? INVISIBLE : VISIBLE);
-        ColorStateList tintList = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
-        ApiCompatibilityUtils.setImageTintList(mHomeButton, tintList);
     }
 
     private ObjectAnimator createEnterTabSwitcherModeAnimation() {
@@ -2342,9 +2354,7 @@
                     ColorUtils.shouldUseLightForegroundOnBackground(currentPrimaryColor);
             boolean unfocusedLocationBarUsesTransparentBg =
                     !ColorUtils.shouldUseOpaqueTextboxBackground(currentPrimaryColor);
-            if (useLightToolbarDrawables != mUseLightToolbarDrawables
-                    || unfocusedLocationBarUsesTransparentBg
-                            != mUnfocusedLocationBarUsesTransparentBg) {
+            if (unfocusedLocationBarUsesTransparentBg != mUnfocusedLocationBarUsesTransparentBg) {
                 visualStateChanged = true;
             } else {
                 updateToolbarBackgroundFromState(VisualState.BRAND_COLOR);
@@ -2357,7 +2367,6 @@
         // Refresh the toolbar texture.
         if ((mVisualState == VisualState.BRAND_COLOR || visualStateChanged)
                 && mLayoutUpdateHost != null) {
-            setUseLightDrawablesForTextureCapture();
             mLayoutUpdateHost.requestUpdate();
         }
         updateShadowVisibility();
@@ -2378,10 +2387,6 @@
             return;
         }
 
-        // Only use primary color to decide icon tint, regardless of night mode, incognito mode,
-        // and whether the toolbar is on the NTP.
-        mUseLightToolbarDrawables =
-                ColorUtils.shouldUseLightForegroundOnBackground(currentPrimaryColor);
         mUnfocusedLocationBarUsesTransparentBg = false;
         mLocationBarBackgroundAlpha = 255;
         getProgressBar().setThemeColor(themeColorForProgressBar, isIncognito());
@@ -2396,24 +2401,7 @@
                     : 255;
         }
 
-        if (mToggleTabStackButton != null) {
-            mToggleTabStackButton.setUseLightDrawables(mUseLightToolbarDrawables);
-            if (mTabSwitcherAnimationTabStackDrawable != null) {
-                mTabSwitcherAnimationTabStackDrawable.setTint(
-                        mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
-            }
-        }
-
         updateModernLocationBarColor(getLocationBarColorForToolbarColor(currentPrimaryColor));
-        if (mExperimentalButton != null) {
-            ColorStateList tintList = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
-            ApiCompatibilityUtils.setImageTintList(mExperimentalButton, tintList);
-        }
-
-        ColorStateList tint = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
-        if (mIsHomeButtonEnabled && mHomeButton != null) {
-            ApiCompatibilityUtils.setImageTintList(mHomeButton, tint);
-        }
 
         mLocationBar.updateVisualsForState();
 
@@ -2471,8 +2459,7 @@
         mExperimentalButton.setImageResource(drawableResId);
         mExperimentalButton.setContentDescription(
                 getContext().getResources().getString(contentDescriptionResId));
-        ApiCompatibilityUtils.setImageTintList(
-                mExperimentalButton, mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+        ApiCompatibilityUtils.setImageTintList(mExperimentalButton, getTint());
 
         mExperimentalButtonLayoutListener = () -> requestLayoutHostUpdateForExperimentalButton();
         if (mTabSwitcherState == STATIC_TAB) {
@@ -2673,13 +2660,6 @@
         ((BitmapDrawable) mTabSwitcherAnimationMenuBadgeLightDrawable).setGravity(Gravity.CENTER);
     }
 
-    private void setUseLightDrawablesForTextureCapture() {
-        int currentPrimaryColor = getToolbarDataProvider().getPrimaryColor();
-        mUseLightDrawablesForTextureCapture = isIncognito()
-                || (currentPrimaryColor != 0
-                           && ColorUtils.shouldUseLightForegroundOnBackground(currentPrimaryColor));
-    }
-
     /**
      * Custom drawable that allows sharing the NTP search box drawable between the toolbar and the
      * NTP.  This allows animations to continue as the drawable is switched between the two owning
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
index 76df30c..c6e3d715 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -349,14 +349,6 @@
                     ColorUtils.getTextBoxColorForToolbarBackground(getResources(), false, color);
             mLocationBar.getBackground().setColorFilter(textBoxColor, PorterDuff.Mode.SRC_IN);
 
-            final ColorStateList tint = ColorUtils.shouldUseLightForegroundOnBackground(color)
-                    ? mLightModeTint
-                    : mDarkModeTint;
-            ApiCompatibilityUtils.setImageTintList(mHomeButton, tint);
-            ApiCompatibilityUtils.setImageTintList(mBackButton, tint);
-            ApiCompatibilityUtils.setImageTintList(mForwardButton, tint);
-            ApiCompatibilityUtils.setImageTintList(mSaveOfflineButton, tint);
-
             mAccessibilitySwitcherButton.setUseLightDrawables(incognito);
             mLocationBar.updateVisualsForState();
             mIsIncognito = incognito;
@@ -365,6 +357,15 @@
         updateNtp();
     }
 
+    @Override
+    public void onTintChanged(ColorStateList tint, boolean useLight) {
+        ApiCompatibilityUtils.setImageTintList(mHomeButton, tint);
+        ApiCompatibilityUtils.setImageTintList(mBackButton, tint);
+        ApiCompatibilityUtils.setImageTintList(mForwardButton, tint);
+        ApiCompatibilityUtils.setImageTintList(mSaveOfflineButton, tint);
+        ApiCompatibilityUtils.setImageTintList(mReloadButton, tint);
+    }
+
     /**
      * Called when the currently visible New Tab Page changes.
      */
@@ -430,8 +431,6 @@
             mReloadButton.setContentDescription(
                     getContext().getString(R.string.accessibility_btn_refresh));
         }
-        ApiCompatibilityUtils.setImageTintList(
-                mReloadButton, isIncognito() ? mLightModeTint : mDarkModeTint);
         mReloadButton.setEnabled(!mIsInTabSwitcherMode);
     }
 
@@ -439,16 +438,16 @@
     void updateBookmarkButton(boolean isBookmarked, boolean editingAllowed) {
         if (isBookmarked) {
             mBookmarkButton.setImageResource(R.drawable.btn_star_filled);
+            // TODO (huayinz): Ask UX whether night mode should have a white or blue star.
             // Non-incognito mode shows a blue filled star.
             ApiCompatibilityUtils.setImageTintList(mBookmarkButton,
-                    isIncognito() ? mLightModeTint
-                                  : AppCompatResources.getColorStateList(
-                                            getContext(), R.color.blue_mode_tint));
+                    useLight() ? getTint()
+                               : AppCompatResources.getColorStateList(
+                                       getContext(), R.color.blue_mode_tint));
             mBookmarkButton.setContentDescription(getContext().getString(R.string.edit_bookmark));
         } else {
             mBookmarkButton.setImageResource(R.drawable.btn_star);
-            ApiCompatibilityUtils.setImageTintList(
-                    mBookmarkButton, isIncognito() ? mLightModeTint : mDarkModeTint);
+            ApiCompatibilityUtils.setImageTintList(mBookmarkButton, getTint());
             mBookmarkButton.setContentDescription(
                     getContext().getString(R.string.accessibility_menu_bookmark));
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index 1cb644f2..c886339 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.toolbar.ToolbarTabController;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.ToolbarProgressBar;
-import org.chromium.ui.AsyncViewProvider;
 
 /**
  * A coordinator for the top toolbar component.
@@ -38,8 +37,7 @@
 public class TopToolbarCoordinator implements Toolbar {
     static final int TAB_SWITCHER_MODE_NORMAL_ANIMATION_DURATION_MS = 200;
 
-    private final AsyncViewProvider<ToolbarLayout> mToolbarProvider;
-    private @Nullable ToolbarLayout mToolbarLayout;
+    private ToolbarLayout mToolbarLayout;
 
     /**
      * The coordinator for the tab switcher mode toolbar (phones only). This will be lazily created
@@ -51,32 +49,25 @@
             new HomepageManager.HomepageStateListener() {
                 @Override
                 public void onHomepageStateUpdated() {
-                    mToolbarProvider.whenLoaded(
-                            (toolbar)
-                                    -> mToolbarLayout.onHomeButtonUpdate(
-                                            HomepageManager.isHomepageEnabled()
-                                            || FeatureUtilities.isNewTabPageButtonEnabled()));
+                    mToolbarLayout.onHomeButtonUpdate(HomepageManager.isHomepageEnabled()
+                            || FeatureUtilities.isNewTabPageButtonEnabled());
                 }
             };
 
     /**
      * Creates a new {@link TopToolbarCoordinator}.
      * @param controlContainer The {@link ToolbarControlContainer} for the containing activity.
-     * @param toolbarProvider The {@link AsyncViewProvider} for the {@link ToolbarLayout}.
+     * @param toolbarLayout The {@link ToolbarLayout}.
      */
-    public TopToolbarCoordinator(ToolbarControlContainer controlContainer,
-            AsyncViewProvider<ToolbarLayout> toolbarProvider) {
-        mToolbarProvider = toolbarProvider;
-        mToolbarProvider.whenLoaded((toolbar) -> {
-            mToolbarLayout = toolbar;
-            if (mToolbarLayout instanceof ToolbarPhone) {
-                mTabSwitcherModeCoordinatorPhone = new TabSwitcherModeTTCoordinatorPhone(
-                        controlContainer.getRootView().findViewById(
-                                R.id.tab_switcher_toolbar_stub));
-            }
-            controlContainer.setToolbar(this);
-            HomepageManager.getInstance().addListener(mHomepageStateListener);
-        });
+    public TopToolbarCoordinator(
+            ToolbarControlContainer controlContainer, ToolbarLayout toolbarLayout) {
+        mToolbarLayout = toolbarLayout;
+        if (mToolbarLayout instanceof ToolbarPhone) {
+            mTabSwitcherModeCoordinatorPhone = new TabSwitcherModeTTCoordinatorPhone(
+                    controlContainer.getRootView().findViewById(R.id.tab_switcher_toolbar_stub));
+        }
+        controlContainer.setToolbar(this);
+        HomepageManager.getInstance().addListener(mHomepageStateListener);
     }
 
     /**
@@ -130,12 +121,19 @@
     }
 
     /**
+     * @see View#addOnAttachStateChangeListener(View.OnAttachStateChangeListener)
+     */
+    public void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) {
+        mToolbarLayout.addOnAttachStateChangeListener(listener);
+    }
+
+    /**
      * Cleans up any code as necessary.
      */
     public void destroy() {
         if (mToolbarLayout != null) {
             HomepageManager.getInstance().removeListener(mHomepageStateListener);
-            mToolbarProvider.destroy((toolbar) -> mToolbarLayout.destroy());
+            mToolbarLayout.destroy();
         }
         if (mTabSwitcherModeCoordinatorPhone != null) {
             mTabSwitcherModeCoordinatorPhone.destroy();
@@ -207,7 +205,7 @@
      * Sets whether the urlbar should be hidden on first page load.
      */
     public void setUrlBarHidden(boolean hidden) {
-        mToolbarProvider.whenLoaded((toolbar) -> mToolbarLayout.setUrlBarHidden(hidden));
+        mToolbarLayout.setUrlBarHidden(hidden);
     }
 
     /**
@@ -267,12 +265,10 @@
      * @param enabled Whether or not accessibility is enabled.
      */
     public void onAccessibilityStatusChanged(boolean enabled) {
-        mToolbarProvider.whenLoaded((toolbar) -> {
-            mToolbarLayout.onAccessibilityStatusChanged(enabled);
-            if (mTabSwitcherModeCoordinatorPhone != null) {
-                mTabSwitcherModeCoordinatorPhone.onAccessibilityStatusChanged(enabled);
-            }
-        });
+        mToolbarLayout.onAccessibilityStatusChanged(enabled);
+        if (mTabSwitcherModeCoordinatorPhone != null) {
+            mTabSwitcherModeCoordinatorPhone.onAccessibilityStatusChanged(enabled);
+        }
     }
 
     /**
@@ -299,8 +295,7 @@
      * for the current tab changing.
      */
     public void onPrimaryColorChanged(boolean shouldAnimate) {
-        mToolbarProvider.whenLoaded(
-                (toolbar) -> mToolbarLayout.onPrimaryColorChanged(shouldAnimate));
+        mToolbarLayout.onPrimaryColorChanged(shouldAnimate);
     }
 
     /**
@@ -308,7 +303,7 @@
      * @param showTitle Whether a title should be shown.
      */
     public void setShowTitle(boolean showTitle) {
-        mToolbarProvider.whenLoaded((toolbar) -> getLocationBar().setShowTitle(showTitle));
+        getLocationBar().setShowTitle(showTitle);
     }
 
     /**
@@ -316,8 +311,7 @@
      * it if {@code drawable} is {@code null}.
      */
     public void setCloseButtonImageResource(@Nullable Drawable drawable) {
-        mToolbarProvider.whenLoaded(
-                (toolbar) -> mToolbarLayout.setCloseButtonImageResource(drawable));
+        mToolbarLayout.setCloseButtonImageResource(drawable);
     }
 
     /**
@@ -328,8 +322,7 @@
      */
     public void addCustomActionButton(
             Drawable drawable, String description, View.OnClickListener listener) {
-        mToolbarProvider.whenLoaded(
-                (toolbar) -> mToolbarLayout.addCustomActionButton(drawable, description, listener));
+        mToolbarLayout.addCustomActionButton(drawable, description, listener);
     }
 
     /**
@@ -340,8 +333,7 @@
      * @param description The content description for the button.
      */
     public void updateCustomActionButton(int index, Drawable drawable, String description) {
-        mToolbarProvider.whenLoaded(
-                (toolbar) -> mToolbarLayout.updateCustomActionButton(index, drawable, description));
+        mToolbarLayout.updateCustomActionButton(index, drawable, description);
     }
 
     @Override
@@ -434,8 +426,10 @@
      */
     public void setThemeColorProvider(ThemeColorProvider provider) {
         final MenuButton menuButtonWrapper = getMenuButtonWrapper();
-        if (menuButtonWrapper == null) return;
-        menuButtonWrapper.setThemeColorProvider(provider);
+        if (menuButtonWrapper != null) {
+            menuButtonWrapper.setThemeColorProvider(provider);
+        }
+        mToolbarLayout.setThemeColorProvider(provider);
     }
 
     /**
@@ -487,15 +481,14 @@
      * @param enabled Whether the progress bar is enabled.
      */
     public void setProgressBarEnabled(boolean enabled) {
-        mToolbarProvider.whenLoaded(
-                (toolbar) -> getProgressBar().setVisibility(enabled ? View.VISIBLE : View.GONE));
+        getProgressBar().setVisibility(enabled ? View.VISIBLE : View.GONE);
     }
 
     /**
      * @param anchor The view to use as an anchor.
      */
     public void setProgressBarAnchorView(@Nullable View anchor) {
-        mToolbarProvider.whenLoaded(toolbar -> getProgressBar().setAnchorView(anchor));
+        getProgressBar().setAnchorView(anchor);
     }
 
     /**
@@ -550,7 +543,7 @@
 
     @Override
     public void showAppMenuUpdateBadge() {
-        mToolbarProvider.whenLoaded((toolbar) -> mToolbarLayout.showAppMenuUpdateBadge(true));
+        mToolbarLayout.showAppMenuUpdateBadge(true);
     }
 
     @Override
@@ -560,7 +553,7 @@
 
     @Override
     public void removeAppMenuUpdateBadge(boolean animate) {
-        mToolbarProvider.whenLoaded((toolbar) -> mToolbarLayout.removeAppMenuUpdateBadge(animate));
+        mToolbarLayout.removeAppMenuUpdateBadge(animate);
     }
 
     /**
@@ -572,18 +565,15 @@
      */
     public void enableExperimentalButton(View.OnClickListener onClickListener,
             @DrawableRes int drawableResId, @StringRes int contentDescriptionResId) {
-        mToolbarProvider.whenLoaded((toolbar) -> {
-            mToolbarLayout.enableExperimentalButton(
-                    onClickListener, drawableResId, contentDescriptionResId);
-        });
+        mToolbarLayout.enableExperimentalButton(
+                onClickListener, drawableResId, contentDescriptionResId);
     }
 
     /**
      * @param isVisible Whether the bottom toolbar is visible.
      */
     public void onBottomToolbarVisibilityChanged(boolean isVisible) {
-        mToolbarProvider.whenLoaded(
-                (toolbar) -> toolbar.onBottomToolbarVisibilityChanged(isVisible));
+        mToolbarLayout.onBottomToolbarVisibilityChanged(isVisible);
     }
 
     /**
@@ -597,7 +587,7 @@
      * Disable the experimental toolbar button.
      */
     public void disableExperimentalButton() {
-        mToolbarProvider.whenLoaded((toolbarLayout) -> mToolbarLayout.disableExperimentalButton());
+        mToolbarLayout.disableExperimentalButton();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/upgrade/UpgradeIntentService.java b/chrome/android/java/src/org/chromium/chrome/browser/upgrade/UpgradeIntentService.java
index 87842a4..e6d00e9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/upgrade/UpgradeIntentService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/upgrade/UpgradeIntentService.java
@@ -9,9 +9,10 @@
 import android.content.Intent;
 
 import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
 import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin.DocumentModeAssassinObserver;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -43,25 +44,22 @@
         if (!assassin.isMigrationNecessary()) return;
 
         final CountDownLatch finishSignal = new CountDownLatch(1);
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (assassin.isMigrationNecessary()) {
-                    // Kick off migration if it hasn't already started.
-                    DocumentModeAssassinObserver observer = new DocumentModeAssassinObserver() {
-                        @Override
-                        public void onStageChange(int newStage) {
-                            if (newStage != DocumentModeAssassin.STAGE_DONE) return;
-                            assassin.removeObserver(this);
-                            finishSignal.countDown();
-                        }
-                    };
-                    assassin.addObserver(observer);
-                    assassin.migrateFromDocumentToTabbedMode();
-                } else {
-                    // Migration finished in the background.
-                    finishSignal.countDown();
-                }
+        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
+            if (assassin.isMigrationNecessary()) {
+                // Kick off migration if it hasn't already started.
+                DocumentModeAssassinObserver observer = new DocumentModeAssassinObserver() {
+                    @Override
+                    public void onStageChange(int newStage) {
+                        if (newStage != DocumentModeAssassin.STAGE_DONE) return;
+                        assassin.removeObserver(this);
+                        finishSignal.countDown();
+                    }
+                };
+                assassin.addObserver(observer);
+                assassin.migrateFromDocumentToTabbedMode();
+            } else {
+                // Migration finished in the background.
+                finishSignal.countDown();
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java
index 8d3983f55..4cd5025 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/EventTracker.java
@@ -4,53 +4,118 @@
 
 package org.chromium.chrome.browser.usage_stats;
 
+import org.chromium.base.Promise;
+import org.chromium.base.Promise.Function;
+import org.chromium.chrome.browser.usage_stats.WebsiteEventProtos.Timestamp;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * In-memory store of {@link org.chromium.chrome.browser.usage_stats.WebsiteEvent} objects.
  * Allows for addition of events and querying for all events in a time interval.
  */
 public class EventTracker {
-    private final List<WebsiteEvent> mWebsiteList;
+    private final UsageStatsBridge mBridge;
+    private Promise<List<WebsiteEvent>> mRootPromise;
 
-    public EventTracker() {
-        mWebsiteList = new ArrayList<>();
+    public EventTracker(UsageStatsBridge bridge) {
+        mBridge = bridge;
+        mRootPromise = new Promise<>();
+        // We need to add a dummy exception handler so that Promise doesn't complain when we
+        // call variants of then() that don't take a single callback. These variants set an
+        // exception handler on the returned promise, so they expect there to be one on the root
+        // promise.
+        mRootPromise.except((e) -> {});
+        mBridge.getAllEvents((result) -> {
+            List<WebsiteEvent> events = new ArrayList<>(result.size());
+            for (WebsiteEventProtos.WebsiteEvent protoEvent : result) {
+                events.add(new WebsiteEvent(getJavaTimestamp(protoEvent.getTimestamp()),
+                        protoEvent.getFqdn(), protoEvent.getType().getNumber()));
+            }
+            mRootPromise.fulfill(events);
+        });
     }
 
     /** Query all events in the half-open range [start, end) */
-    public List<WebsiteEvent> queryWebsiteEvents(long start, long end) {
-        List<WebsiteEvent> sublist = sublistFromTimeRange(start, end);
-        List<WebsiteEvent> sublistCopy = new ArrayList<>(sublist.size());
-        sublistCopy.addAll(sublist);
-        return sublistCopy;
+    public Promise<List<WebsiteEvent>> queryWebsiteEvents(long start, long end) {
+        assert start < end;
+        return mRootPromise.then((Function<List<WebsiteEvent>, List<WebsiteEvent>>) (result) -> {
+            List<WebsiteEvent> sublist = sublistFromTimeRange(start, end, result);
+            List<WebsiteEvent> sublistCopy = new ArrayList<>(sublist.size());
+            sublistCopy.addAll(sublist);
+            return sublistCopy;
+        });
     }
 
     /**
      * Adds an event to the end of the list of events. Adding an event whose timestamp precedes the
-     * last event in the list is illegal.
+     * last event in the list is illegal. The returned promise will be fulfilled once persistence
+     * succeeds, and rejected if persistence fails.
      */
-    public void addWebsiteEvent(WebsiteEvent event) {
-        if (mWebsiteList.size() > 0) {
-            assert event.getTimestamp() >= mWebsiteList.get(mWebsiteList.size() - 1).getTimestamp();
-        }
+    public Promise<Void> addWebsiteEvent(WebsiteEvent event) {
+        final Promise<Void> writePromise = new Promise<>();
+        mRootPromise.then((result) -> {
+            assert result.size() == 0
+                    || event.getTimestamp() >= result.get(result.size() - 1).getTimestamp();
 
-        mWebsiteList.add(event);
+            List<WebsiteEventProtos.WebsiteEvent> eventsList = Arrays.asList(getProtoEvent(event));
+            mBridge.addEvents(eventsList, (didSucceed) -> {
+                if (didSucceed) {
+                    result.add(event);
+                    writePromise.fulfill(null);
+                } else {
+                    writePromise.reject();
+                }
+            });
+        }, (e) -> {});
+
+        return writePromise;
     }
 
-    private List<WebsiteEvent> sublistFromTimeRange(long start, long end) {
-        return mWebsiteList.subList(indexOf(start), indexOf(end));
+    private WebsiteEventProtos.WebsiteEvent getProtoEvent(WebsiteEvent event) {
+        return WebsiteEventProtos.WebsiteEvent.newBuilder()
+                .setFqdn(event.getFqdn())
+                .setTimestamp(getProtoTimestamp(event.getTimestamp()))
+                .setType(getProtoEventType(event.getType()))
+                .build();
     }
 
-    private int indexOf(long time) {
-        for (int i = 0; i < mWebsiteList.size(); i++) {
-            boolean nextElementGreater =
-                    (i + 1 < mWebsiteList.size()) && mWebsiteList.get(i + 1).getTimestamp() > time;
-            if (mWebsiteList.get(i).getTimestamp() == time || nextElementGreater) {
-                return i;
-            }
-        }
+    private Timestamp getProtoTimestamp(long timestampMs) {
+        return Timestamp.newBuilder()
+                .setSeconds(TimeUnit.MILLISECONDS.toSeconds(timestampMs))
+                .setNanos((int) TimeUnit.MILLISECONDS.toNanos(timestampMs % 1000))
+                .build();
+    }
 
-        return mWebsiteList.size();
+    private WebsiteEventProtos.WebsiteEvent.EventType getProtoEventType(
+            @WebsiteEvent.EventType int eventType) {
+        switch (eventType) {
+            case WebsiteEvent.EventType.START:
+                return WebsiteEventProtos.WebsiteEvent.EventType.START_BROWSING;
+            case WebsiteEvent.EventType.STOP:
+                return WebsiteEventProtos.WebsiteEvent.EventType.STOP_BROWSING;
+            default:
+                return WebsiteEventProtos.WebsiteEvent.EventType.UNKNOWN;
+        }
+    }
+
+    private long getJavaTimestamp(Timestamp protoTimestamp) {
+        return TimeUnit.SECONDS.toMillis(protoTimestamp.getSeconds())
+                + TimeUnit.NANOSECONDS.toMillis(protoTimestamp.getNanos());
+    }
+
+    private static List<WebsiteEvent> sublistFromTimeRange(
+            long start, long end, List<WebsiteEvent> websiteList) {
+        return websiteList.subList(indexOf(start, websiteList), indexOf(end, websiteList));
+    }
+
+    private static int indexOf(long time, List<WebsiteEvent> websiteList) {
+        for (int i = 0; i < websiteList.size(); i++) {
+            if (time <= websiteList.get(i).getTimestamp()) return i;
+        }
+        return websiteList.size();
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
index 11c0f410..a816f68 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
@@ -148,18 +148,19 @@
     }
 
     private void reportToPlatformIfDomainIsTracked(String reportMethodName, String fqdn) {
-        String token = mTokenTracker.getTokenForFqdn(fqdn);
-        if (token == null) return;
+        mTokenTracker.getTokenForFqdn(fqdn).then((token) -> {
+            if (token == null) return;
 
-        try {
-            UsageStatsManager instance =
-                    (UsageStatsManager) mActivity.getSystemService(Context.USAGE_STATS_SERVICE);
-            Method reportMethod = UsageStatsManager.class.getDeclaredMethod(
-                    reportMethodName, Activity.class, String.class);
+            try {
+                UsageStatsManager instance =
+                        (UsageStatsManager) mActivity.getSystemService(Context.USAGE_STATS_SERVICE);
+                Method reportMethod = UsageStatsManager.class.getDeclaredMethod(
+                        reportMethodName, Activity.class, String.class);
 
-            reportMethod.invoke(instance, mActivity, token);
-        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
-            Log.e(TAG, "Failed to report to platform API", e);
-        }
+                reportMethod.invoke(instance, mActivity, token);
+            } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
+                Log.e(TAG, "Failed to report to platform API", e);
+            }
+        });
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
index 06b13c07..c1a8382 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
@@ -4,36 +4,82 @@
 
 package org.chromium.chrome.browser.usage_stats;
 
+import org.chromium.base.Promise;
+import org.chromium.base.Promise.Function;
+
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Class that tracks which sites are currently suspended.
  */
 public class SuspensionTracker {
-    private Set<String> mSuspendedWebsites;
+    private UsageStatsBridge mBridge;
+    private Promise<List<String>> mRootPromise;
+    private Promise<Void> mWritePromise;
 
-    public SuspensionTracker() {
-        mSuspendedWebsites = new HashSet<String>();
+    public SuspensionTracker(UsageStatsBridge bridge) {
+        mBridge = bridge;
+        mRootPromise = new Promise<>();
+        mBridge.getAllSuspensions((result) -> { mRootPromise.fulfill(result); });
+        mWritePromise = Promise.fulfilled(null);
     }
 
-    public void setWebsitesSuspended(List<String> fqdns, boolean suspended) {
-        if (suspended) {
-            mSuspendedWebsites.addAll(fqdns);
-        } else {
-            mSuspendedWebsites.removeAll(fqdns);
-        }
+    /**
+     * Sets the status of <c>fqdns</c> to match <c>suspended</c>.
+     * The returned promise will be fulfilled once persistence succeeds, and rejected if persistence
+     * fails.
+     */
+    public Promise<Void> setWebsitesSuspended(List<String> fqdns, boolean suspended) {
+        Promise<Void> newWritePromise = new Promise<>();
+        mWritePromise.then((dummyResult) -> {
+            mRootPromise.then((result) -> {
+                // We copy result so that the mutation isn't reflected in result until persistence
+                // succeeds.
+                List<String> resultCopy = new ArrayList<>(result);
+                if (suspended) {
+                    resultCopy.addAll(fqdns);
+                } else {
+                    resultCopy.removeAll(fqdns);
+                }
+
+                mBridge.setSuspensions(
+                        resultCopy.toArray(new String[resultCopy.size()]), (didSucceed) -> {
+                            if (didSucceed) {
+                                if (suspended) {
+                                    result.addAll(fqdns);
+                                } else {
+                                    result.removeAll(fqdns);
+                                }
+
+                                newWritePromise.fulfill(null);
+                            } else {
+                                newWritePromise.reject();
+                            }
+                        });
+                // We need to add a dummy exception handler so that Promise doesn't complain when we
+                // call variants of then() that don't take a single callback. These variants set an
+                // exception handler on the returned promise, so they expect there to be one on the
+                // root promise.
+            }, (e) -> {});
+        });
+
+        mWritePromise = newWritePromise;
+        return newWritePromise;
     }
 
-    public List<String> getAllSuspendedWebsites() {
-        List<String> result = new ArrayList<>();
-        result.addAll(mSuspendedWebsites);
-        return result;
+    public Promise<List<String>> getAllSuspendedWebsites() {
+        return mRootPromise.then(
+                (Function<List<String>, List<String>>) (result) -> { return result; });
     }
 
     public boolean isWebsiteSuspended(String fqdn) {
-        return mSuspendedWebsites.contains(fqdn);
+        // We special case isWebsiteSuspended to return a value immediately because its only
+        // consumer(PageViewOsberver) only cares about immediate results.
+        if (mRootPromise.isFulfilled()) {
+            return mRootPromise.getResult().contains(fqdn);
+        }
+
+        return false;
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java
index cd72426..9b4ce2f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/TokenTracker.java
@@ -4,6 +4,9 @@
 
 package org.chromium.chrome.browser.usage_stats;
 
+import org.chromium.base.Promise;
+import org.chromium.base.Promise.Function;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -13,64 +16,109 @@
  * Class that tracks the mapping between tokens and fully-qualified domain names (FQDNs).
  */
 public class TokenTracker {
-    private Map<String, String> mFqdnToTokenMap;
-    private Map<String, String> mTokenToFqdnMap;
+    private Promise<Map<String, String>> mRootPromise;
     private TokenGenerator mTokenGenerator;
+    private UsageStatsBridge mBridge;
 
-    public TokenTracker() {
-        mTokenToFqdnMap = new HashMap<>();
-        mFqdnToTokenMap = new HashMap<>();
-        mTokenGenerator = new TokenGenerator();
+    public TokenTracker(UsageStatsBridge bridge) {
+        mBridge = bridge;
+        mRootPromise = new Promise<>();
+        mBridge.getAllTokenMappings((result) -> {
+            long maxTokenValue = 0;
+            for (Map.Entry<String, String> entry : result.entrySet()) {
+                maxTokenValue = Math.max(maxTokenValue, Long.valueOf(entry.getKey()));
+            }
+
+            mTokenGenerator = new TokenGenerator(maxTokenValue + 1);
+            mRootPromise.fulfill(result);
+        });
+
+        // We need to add a dummy exception handler so that Promise doesn't complain when we
+        // call variants of then() that don't take a single callback. These variants set an
+        // exception handler on the returned promise, so they expect there to be one on the root
+        // promise.
+        mRootPromise.except((e) -> {});
     }
 
     /**
      * Associate a new token with FQDN, and return that token.
      * If we're already tracking FQDN, return the corresponding token.
+     * The returned promise will be fulfilled once persistence succeeds, and rejected if persistence
+     * fails.
      */
-    public String startTrackingWebsite(String fqdn) {
-        if (isTrackingFqdn(fqdn)) {
-            return mFqdnToTokenMap.get(fqdn);
-        } else {
+    public Promise<String> startTrackingWebsite(String fqdn) {
+        Promise<String> writePromise = new Promise<>();
+        mRootPromise.then((result) -> {
+            if (result.containsValue(fqdn)) {
+                writePromise.fulfill(getFirstKeyForValue(result, fqdn));
+                return;
+            }
+
             String token = mTokenGenerator.nextToken();
-            putMapping(token, fqdn);
-            return token;
-        }
+            Map<String, String> resultCopy = new HashMap<>(result);
+            resultCopy.put(token, fqdn);
+            mBridge.setTokenMappings(resultCopy, (didSucceed) -> {
+                if (didSucceed) {
+                    result.put(token, fqdn);
+                    writePromise.fulfill(token);
+                } else {
+                    writePromise.reject();
+                }
+            });
+        }, (e) -> {});
+
+        return writePromise;
     }
 
-    /** Remove token and its associated FQDN, if we're  already tracking token. */
-    public void stopTrackingToken(String token) {
-        if (isTrackingToken(token)) {
-            mFqdnToTokenMap.remove(getFqdnForToken(token));
-            mTokenToFqdnMap.remove(token);
-        }
+    /**
+     * Remove token and its associated FQDN, if we're  already tracking token.
+     * The returned promise will be fulfilled once persistence succeeds, and rejected if persistence
+     * fails.
+     */
+    public Promise<Void> stopTrackingToken(String token) {
+        Promise<Void> writePromise = new Promise<>();
+        mRootPromise.then((result) -> {
+            if (!result.containsKey(token)) {
+                writePromise.fulfill(null);
+                return;
+            }
+
+            Map<String, String> resultCopy = new HashMap<>(result);
+            resultCopy.remove(token);
+            mBridge.setTokenMappings(resultCopy, (didSucceed) -> {
+                if (didSucceed) {
+                    result.remove(token);
+                    writePromise.fulfill(null);
+                } else {
+                    writePromise.reject();
+                }
+            });
+        }, (e) -> {});
+
+        return writePromise;
     }
 
     /** Returns the token for a given FQDN, or null if we're not tracking that FQDN. */
-    public String getTokenForFqdn(String fqdn) {
-        return mFqdnToTokenMap.get(fqdn);
+    public Promise<String> getTokenForFqdn(String fqdn) {
+        return mRootPromise.then((Function<Map<String, String>, String>) (result) -> {
+            return getFirstKeyForValue(result, fqdn);
+        });
     }
 
     /** Get all the tokens we're tracking. */
-    public List<String> getAllTrackedTokens() {
-        List<String> result = new ArrayList<>();
-        result.addAll(mTokenToFqdnMap.keySet());
-        return result;
+    public Promise<List<String>> getAllTrackedTokens() {
+        return mRootPromise.then((Function<Map<String, String>, List<String>>) (result) -> {
+            return new ArrayList<>(result.keySet());
+        });
     }
 
-    private String getFqdnForToken(String token) {
-        return mTokenToFqdnMap.get(token);
-    }
+    private static String getFirstKeyForValue(Map<String, String> map, String value) {
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            if (entry.getValue().equals(value)) {
+                return entry.getKey();
+            }
+        }
 
-    private void putMapping(String token, String fqdn) {
-        mTokenToFqdnMap.put(token, fqdn);
-        mFqdnToTokenMap.put(fqdn, token);
-    }
-
-    private boolean isTrackingFqdn(String fqdn) {
-        return mFqdnToTokenMap.containsKey(fqdn);
-    }
-
-    private boolean isTrackingToken(String token) {
-        return mTokenToFqdnMap.containsKey(token);
+        return null;
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsBridge.java
index 4c94676..3386bb87 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsBridge.java
@@ -80,8 +80,8 @@
 
     public void getAllSuspensions(Callback<List<String>> callback) {
         assert mNativeUsageStatsBridge != 0;
-        nativeGetAllSuspensions(
-                mNativeUsageStatsBridge, arr -> { callback.onResult(Arrays.asList(arr)); });
+        nativeGetAllSuspensions(mNativeUsageStatsBridge,
+                arr -> { callback.onResult(new ArrayList<>(Arrays.asList(arr))); });
     }
 
     public void setSuspensions(String[] domains, Callback<Boolean> callback) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
index 386a04a..a6b45dbd7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsService.java
@@ -6,6 +6,7 @@
 
 import android.app.Activity;
 
+import org.chromium.base.Promise;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.preferences.Pref;
@@ -13,6 +14,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -39,11 +41,11 @@
 
     @VisibleForTesting
     UsageStatsService() {
-        mEventTracker = new EventTracker();
-        mSuspensionTracker = new SuspensionTracker();
-        mTokenTracker = new TokenTracker();
         Profile profile = Profile.getLastUsedProfile().getOriginalProfile();
         mBridge = new UsageStatsBridge(profile);
+        mEventTracker = new EventTracker(mBridge);
+        mSuspensionTracker = new SuspensionTracker(mBridge);
+        mTokenTracker = new TokenTracker(mBridge);
         // TODO(pnoland): listen for preference changes so we can notify DW.
     }
 
@@ -75,13 +77,13 @@
     }
 
     /** Query for all events that occurred in the half-open range [start, end) */
-    public List<WebsiteEvent> queryWebsiteEvents(long start, long end) {
+    public Promise<List<WebsiteEvent>> queryWebsiteEventsAsync(long start, long end) {
         ThreadUtils.assertOnUiThread();
         return mEventTracker.queryWebsiteEvents(start, end);
     }
 
     /** Get all tokens that are currently being tracked. */
-    public List<String> getAllTrackedTokens() {
+    public Promise<List<String>> getAllTrackedTokensAsync() {
         ThreadUtils.assertOnUiThread();
         return mTokenTracker.getAllTrackedTokens();
     }
@@ -90,7 +92,7 @@
      * Start tracking a full-qualified domain name(FQDN), returning the token used to identify it.
      * If the FQDN is already tracked, this will return the existing token.
      */
-    public String startTrackingWebsite(String fqdn) {
+    public Promise<String> startTrackingWebsiteAsync(String fqdn) {
         ThreadUtils.assertOnUiThread();
         return mTokenTracker.startTrackingWebsite(fqdn);
     }
@@ -99,28 +101,49 @@
      * Stops tracking the site associated with the given token.
      * If the token was not associated with a site, this does nothing.
      */
-    public void stopTrackingToken(String token) {
+    public Promise<Void> stopTrackingTokenAsync(String token) {
         ThreadUtils.assertOnUiThread();
-        mTokenTracker.stopTrackingToken(token);
+        return mTokenTracker.stopTrackingToken(token);
     }
 
     /**
      * Suspend or unsuspend every site in FQDNs, depending on the truthiness of <c>suspended</c>.
      */
-    public void setWebsitesSuspended(List<String> fqdns, boolean suspended) {
+    public Promise<Void> setWebsitesSuspendedAsync(List<String> fqdns, boolean suspended) {
         ThreadUtils.assertOnUiThread();
-        mSuspensionTracker.setWebsitesSuspended(fqdns, suspended);
+        return mSuspensionTracker.setWebsitesSuspended(fqdns, suspended);
     }
 
     /** @return all the sites that are currently suspended. */
-    public List<String> getAllSuspendedWebsites() {
+    public Promise<List<String>> getAllSuspendedWebsitesAsync() {
         ThreadUtils.assertOnUiThread();
         return mSuspensionTracker.getAllSuspendedWebsites();
     }
 
-    /** @return whether the given site is suspended. */
-    public boolean isWebsiteSuspended(String fqdn) {
-        ThreadUtils.assertOnUiThread();
-        return mSuspensionTracker.isWebsiteSuspended(fqdn);
+    // The below methods are dummies that are only being retained to avoid breaking the downstream
+    // build. TODO(pnoland): remove these once the downstream change that converts to using promises
+    // lands.
+    public List<WebsiteEvent> queryWebsiteEvents(long start, long end) {
+        return new ArrayList<>();
+    }
+
+    public List<String> getAllTrackedTokens() {
+        return new ArrayList<>();
+    }
+
+    public String startTrackingWebsite(String fqdn) {
+        return "1";
+    }
+
+    public void stopTrackingToken(String token) {
+        return;
+    }
+
+    public void setWebsitesSuspended(List<String> fqdns, boolean suspended) {
+        return;
+    }
+
+    public List<String> getAllSuspendedWebsites() {
+        return new ArrayList<>();
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 47245a9..cb44e6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -78,7 +78,6 @@
     private static Boolean sIsNewTabPageButtonEnabled;
     private static Boolean sIsBottomToolbarEnabled;
     private static Boolean sIsAdaptiveToolbarEnabled;
-    private static Boolean sShouldInflateToolbarOnBackgroundThread;
     private static Boolean sIsNightModeAvailable;
     private static Boolean sIsNightModeForCustomTabsAvailable;
     private static Boolean sShouldPrioritizeBootstrapTasks;
@@ -200,7 +199,6 @@
         cacheNewTabPageButtonEnabled();
         cacheBottomToolbarEnabled();
         cacheAdaptiveToolbarEnabled();
-        cacheInflateToolbarOnBackgroundThread();
         cacheNightModeAvailable();
         cacheNightModeForCustomTabsAvailable();
         cacheDownloadAutoResumptionEnabledInNative();
@@ -311,29 +309,6 @@
     }
 
     /**
-     * Cache whether or not the toolbar should be inflated on a background thread so on next
-     * startup, the value can be made available immediately.
-     */
-    public static void cacheInflateToolbarOnBackgroundThread() {
-        boolean onBackgroundThread =
-                ChromeFeatureList.isEnabled(ChromeFeatureList.INFLATE_TOOLBAR_ON_BACKGROUND_THREAD);
-
-        ChromePreferenceManager.getInstance().writeBoolean(
-                ChromePreferenceManager.INFLATE_TOOLBAR_ON_BACKGROUND_THREAD_KEY,
-                onBackgroundThread);
-    }
-
-    public static boolean shouldInflateToolbarOnBackgroundThread() {
-        if (sShouldInflateToolbarOnBackgroundThread == null) {
-            ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
-
-            sShouldInflateToolbarOnBackgroundThread = prefManager.readBoolean(
-                    ChromePreferenceManager.INFLATE_TOOLBAR_ON_BACKGROUND_THREAD_KEY, false);
-        }
-        return sShouldInflateToolbarOnBackgroundThread;
-    }
-
-    /**
      * @return Whether or not the download auto-resumptions should be enabled in native.
      */
     @CalledByNative
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 052736b..00f79258 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -412,6 +412,7 @@
   "java/src/org/chromium/chrome/browser/contextualsearch/NearTopTapSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/QuickAnswersHeuristic.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/RecentScrollTapSuppression.java",
+  "java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/SecondTapMlOverride.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/ShortTextRunSuppression.java",
@@ -1844,6 +1845,7 @@
     "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPageProperties.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessNewTabPageTopLayout.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessTabObserver.java",
+    "touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHCoordinator.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHMediator.java",
     "touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHProperties.java",
@@ -1857,7 +1859,10 @@
     "touchless/java/src/org/chromium/chrome/browser/touchless/ui/tooltip/TooltipView.java",
   ]
 } else {
-  chrome_java_sources += [ "touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java" ]
+  chrome_java_sources += [
+    "touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessDelegate.java",
+    "touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java",
+  ]
 }
 
 chrome_test_java_sources = [
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java
index cb81e50..ad9d5ec 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser;
 
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.espresso.matcher.ViewMatchers;
 import android.support.test.filters.SmallTest;
 
 import org.junit.Before;
@@ -17,7 +14,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.test.ScreenShooter;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -52,9 +48,7 @@
     @Test
     @SmallTest
     @Feature({"UiCatalogue"})
-    public void testCaptureTabSwitcher() throws IOException, InterruptedException {
+    public void testCaptureNewTabPage() throws IOException, InterruptedException {
         mScreenShooter.shoot("NTP", ScreenShooter.TagsEnum.UiCatalogueExample);
-        Espresso.onView(ViewMatchers.withId(R.id.tab_switcher_button)).perform(ViewActions.click());
-        mScreenShooter.shoot("Tab switcher", ScreenShooter.TagsEnum.UiCatalogueExample);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
index e83df53..5766fd2b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -167,76 +167,121 @@
     /**
      * Class that represents a fake tap triggered contextual search.
      */
+    public class MutableResolvedSearchTerm extends ResolvedSearchTerm {
+        // Fields that we can override in the ResolvedSearchTerm.
+        private String mContextLanguage;
+        private long mLoggedEventId;
+        private int mSelectionStartAdjust;
+
+        /**
+         * Called in response to the
+         * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method.
+         * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all
+         *         other
+         *        parameters should be ignored.
+         * @param responseCode The HTTP response code. If the code is not OK, the query should be
+         *        ignored.
+         * @param searchTerm The term to use in our subsequent search.
+         * @param displayText The text to display in our UX.
+         */
+        MutableResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, String searchTerm,
+                String displayText) {
+            super(isNetworkUnavailable, responseCode, searchTerm, displayText, "", false);
+        }
+
+        /**
+         * Called in response to the
+         * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method.
+         * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all
+         *         other
+         *        parameters should be ignored.
+         * @param responseCode The HTTP response code. If the code is not OK, the query should be
+         *        ignored.
+         * @param searchTerm The term to use in our subsequent search.
+         * @param displayText The text to display in our UX.
+         * @param alternateTerm The alternate term to display on the results page.
+         * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string.
+         *        A MID is a unique identifier for an entity in the Search Knowledge Graph.
+         * @param doPreventPreload Whether we should prevent preloading on this search.
+         * @param selectionStartAdjust A positive number of characters that the start of the
+         *         existing
+         *        selection should be expanded by.
+         * @param selectionEndAdjust A positive number of characters that the end of the existing
+         *        selection should be expanded by.
+         * @param contextLanguage The language of the original search term, or an empty string.
+         * @param thumbnailUrl The URL of the thumbnail to display in our UX.
+         * @param caption The caption to display.
+         * @param quickActionUri The URI for the intent associated with the quick action.
+         * @param quickActionCategory The {@link QuickActionCategory} for the quick action.
+         * @param loggedEventId The EventID logged by the server, which should be recorded and sent
+         *         back
+         *        to the server along with user action results in a subsequent request.
+         * @param searchUrlFull The URL for the full search to present in the overlay, or empty.
+         * @param searchUrlPreload The URL for the search to preload into the overlay, or empty.
+         */
+        MutableResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode,
+                final String searchTerm, final String displayText, final String alternateTerm,
+                final String mid, boolean doPreventPreload, int selectionStartAdjust,
+                int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl,
+                final String caption, final String quickActionUri, final int quickActionCategory,
+                final long loggedEventId, final String searchUrlFull,
+                final String searchUrlPreload) {
+            super(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid,
+                    doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage,
+                    thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId,
+                    searchUrlFull, searchUrlPreload);
+        }
+
+        @Override
+        public String contextLanguage() {
+            return mContextLanguage;
+        }
+
+        void setContextLanguage(String contextLanguage) {
+            this.mContextLanguage = contextLanguage;
+        }
+
+        @Override
+        public long loggedEventId() {
+            return mLoggedEventId;
+        }
+
+        void setLoggedEventId(long loggedEventId) {
+            this.mLoggedEventId = loggedEventId;
+        }
+
+        @Override
+        public int selectionStartAdjust() {
+            return mSelectionStartAdjust;
+        }
+
+        void setSelectionStartAdjust(int selectionStartAdjust) {
+            mSelectionStartAdjust = selectionStartAdjust;
+        }
+    }
+
+    //============================================================================================
+    // FakeTapSearch
+    //============================================================================================
+
+    /**
+     * Class that represents a fake tap triggered contextual search.
+     */
     public class FakeTapSearch extends FakeSearch {
-        private final boolean mIsNetworkUnavailable;
-        private final int mResponseCode;
-        protected final String mSearchTerm;
-        private final String mDisplayText;
-        private final String mAlternateTerm;
-        private final String mMid;
-        private final boolean mDoPreventPreload;
-        private final int mStartAdjust;
-        private final int mEndAdjust;
-        private final String mContextLanguage;
-        private final String mThumbnailUrl;
-        private final String mCaption;
-        private final String mQuickActionUri;
-        private final int mQuickActionCategory;
-        private final long mLoggedEventId;
-        private final String mSearchUrlFull;
-        private final String mSearchUrlPreload;
+        protected final MutableResolvedSearchTerm mResolvedSearchTerm;
 
         boolean mDidStartResolution;
         boolean mDidFinishResolution;
 
         /**
          * @param nodeId                The id of the node where the touch event will be simulated.
-         * @param isNetworkUnavailable  Whether the network is unavailable.
-         * @param responseCode          The HTTP response code of the resolution.
-         * @param searchTerm            The resolved search term.
-         * @param displayText           The display text.
-         * @param alternateTerm         The alternate text.
-         * @param mid                   The MID to specify a KP, or an empty string.
-         * @param doPreventPreload      Whether search preload should be prevented.
-         * @param startAdjust           The start adjustment of the selection.
-         * @param endAdjust             The end adjustment of the selection.
-         * @param contextLanguage       The language of the context determined by the server.
-         * @param thumbnailUrl          The URL of a thumbnail to display.
-         * @param caption               The caption to display.
-         * @param quickActionUri        The URI for the intent associated with the quick action.
-         * @param quickActionCategory   The category for the quick action.
-         * @param loggedEventId         The EventID logged by the server, which should be recorded
-         *                              and sent back to the server along with user action results
-         *                              in a subsequent request.
-         * @param searchUrlFull         The URL for the full search to present in the overlay, or
-         *                              empty.
-         * @param searchUrlPreload      The URL for the search to preload into the overlay, or
-         *                              empty.
+         * @param resolvedSearchTerm    The details of the server's Resolve request response, which
+         *                              tells us what to search for.
          */
-        FakeTapSearch(String nodeId, boolean isNetworkUnavailable, int responseCode,
-                String searchTerm, String displayText, String alternateTerm, String mid,
-                boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage,
-                String thumbnailUrl, String caption, String quickActionUri, int quickActionCategory,
-                long loggedEventId, String searchUrlFull, String searchUrlPreload) {
+        FakeTapSearch(String nodeId, MutableResolvedSearchTerm resolvedSearchTerm) {
             super(nodeId);
 
-            mIsNetworkUnavailable = isNetworkUnavailable;
-            mResponseCode = responseCode;
-            mSearchTerm = searchTerm;
-            mDisplayText = displayText;
-            mAlternateTerm = alternateTerm;
-            mMid = mid;
-            mDoPreventPreload = doPreventPreload;
-            mStartAdjust = startAdjust;
-            mEndAdjust = endAdjust;
-            mContextLanguage = contextLanguage;
-            mThumbnailUrl = thumbnailUrl;
-            mCaption = caption;
-            mQuickActionUri = quickActionUri;
-            mQuickActionCategory = quickActionCategory;
-            mLoggedEventId = loggedEventId;
-            mSearchUrlFull = searchUrlFull;
-            mSearchUrlPreload = searchUrlPreload;
+            mResolvedSearchTerm = resolvedSearchTerm;
         }
 
         /**
@@ -248,9 +293,9 @@
          */
         FakeTapSearch(String nodeId, boolean isNetworkUnavailable, int responseCode,
                 String searchTerm, String displayText) {
-            this(nodeId, isNetworkUnavailable, responseCode, searchTerm, displayText,
-                    "alternate-term", "", false, -7, 0, "", "", "", "", QuickActionCategory.NONE,
-                    0L, "", "");
+            this(nodeId,
+                    new MutableResolvedSearchTerm(
+                            isNetworkUnavailable, responseCode, searchTerm, displayText));
         }
 
         @Override
@@ -263,7 +308,7 @@
             mDidFinishResolution = false;
 
             mManagerTest.clickNode(getNodeId());
-            mManagerTest.waitForSelectionToBe(mSearchTerm);
+            mManagerTest.waitForSelectionToBe(getSearchTerm());
 
             if (mPolicy.shouldPreviousTapResolve()) {
                 // Now wait for the Search Term Resolution to start.
@@ -281,7 +326,7 @@
 
         @Override
         public String getSearchTerm() {
-            return mSearchTerm;
+            return mResolvedSearchTerm.searchTerm();
         }
 
         /**
@@ -320,11 +365,7 @@
                 @Override
                 public void run() {
                     if (!mDidFinishResolution) {
-                        handleSearchTermResolutionResponse(mIsNetworkUnavailable, mResponseCode,
-                                mSearchTerm, mDisplayText, mAlternateTerm, mMid, mDoPreventPreload,
-                                mStartAdjust, mEndAdjust, mContextLanguage, mThumbnailUrl, mCaption,
-                                mQuickActionUri, mQuickActionCategory, mLoggedEventId,
-                                mSearchUrlFull, mSearchUrlPreload);
+                        handleSearchTermResolutionResponse(mResolvedSearchTerm);
 
                         mActiveFakeTapSearch = null;
                         mDidFinishResolution = true;
@@ -332,6 +373,10 @@
                 }
             };
         }
+
+        MutableResolvedSearchTerm getMutableResolvedSearchTerm() {
+            return mResolvedSearchTerm;
+        }
     }
 
     //============================================================================================
@@ -344,37 +389,25 @@
     public class FakeSlowResolveSearch extends FakeTapSearch {
         /**
          * @param nodeId                The id of the node where the touch event will be simulated.
+         * @param resolvedSearchTerm    The details of the server's Resolve request response, which
+         *                              tells us what to search for.
+         */
+        FakeSlowResolveSearch(String nodeId, MutableResolvedSearchTerm resolvedSearchTerm) {
+            super(nodeId, resolvedSearchTerm);
+        }
+
+        /**
+         * @param nodeId                The id of the node where the touch event will be simulated.
          * @param isNetworkUnavailable  Whether the network is unavailable.
          * @param responseCode          The HTTP response code of the resolution.
          * @param searchTerm            The resolved search term.
          * @param displayText           The display text.
-         * @param alternateTerm         The alternate text.
-         * @param mid                   The MID to specify a KP, or an empty string.
-         * @param doPreventPreload      Whether search preload should be prevented.
-         * @param startAdjust           The start adjustment of the selection.
-         * @param endAdjust             The end adjustment of the selection.
-         * @param contextLanguage       The language of the context determined by the server.
-         * @param thumbnailUrl          The URL of a thumbnail to display.
-         * @param caption               The caption to display.
-         * @param quickActionUri        The URI for the intent associated with the quick action.
-         * @param quickActionCategory   The category for the quick action.
-         * @param loggedEventId         The EventID logged by the server, which should be recorded
-         *                              and sent back to the server along with user action results
-         *                              in a subsequent request.
-         * @param searchUrlFull         The URL for the full search to present in the overlay, or
-         *                              empty.
-         * @param searchUrlPreload      The URL for the search to preload into the overlay, or
-         *                              empty.
          */
         FakeSlowResolveSearch(String nodeId, boolean isNetworkUnavailable, int responseCode,
-                String searchTerm, String displayText, String alternateTerm, String mid,
-                boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage,
-                String thumbnailUrl, String caption, String quickActionUri, int quickActionCategory,
-                long loggedEventId, String searchUrlFull, String searchUrlPreload) {
-            super(nodeId, isNetworkUnavailable, responseCode, searchTerm, displayText,
-                    alternateTerm, mid, doPreventPreload, startAdjust, endAdjust, contextLanguage,
-                    thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId,
-                    searchUrlFull, searchUrlPreload);
+                String searchTerm, String displayText) {
+            this(nodeId,
+                    new MutableResolvedSearchTerm(
+                            isNetworkUnavailable, responseCode, searchTerm, displayText));
         }
 
         @Override
@@ -387,7 +420,7 @@
             mDidFinishResolution = false;
 
             mManagerTest.clickNode(getNodeId());
-            mManagerTest.waitForSelectionToBe(mSearchTerm);
+            mManagerTest.waitForSelectionToBe(getSearchTerm());
 
             if (mPolicy.shouldPreviousTapResolve()) {
                 // Now wait for the Search Term Resolution to start.
@@ -596,16 +629,8 @@
     }
 
     @Override
-    public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode,
-            String searchTerm, String displayText, String alternateTerm, String mid,
-            boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust,
-            String contextLanguage, String thumbnailUrl, String caption, String quickActionUri,
-            int quickActionCategory, long loggedEventId, String searchUrlFull,
-            String searchUrlPreload) {
-        mBaseManager.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode,
-                searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust,
-                selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri,
-                quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload);
+    public void handleSearchTermResolutionResponse(ResolvedSearchTerm resolvedSearchTerm) {
+        mBaseManager.handleSearchTermResolutionResponse(resolvedSearchTerm);
     }
 
     @Override
@@ -654,24 +679,29 @@
         registerFakeTapSearch(new FakeTapSearch("term", false, 200, "Term", "Term"));
         registerFakeTapSearch(
                 new FakeTapSearch("resolution", false, 200, "Resolution", "Resolution"));
-        registerFakeTapSearch(
-                new FakeTapSearch("german", false, 200, "Deutsche", "Deutsche", "alternate-term",
-                        "", false, 0, 0, "de", "", "", "", QuickActionCategory.NONE, 0, "", ""));
+
+        FakeTapSearch germanFakeTapSearch =
+                new FakeTapSearch("german", false, 200, "Deutsche", "Deutsche");
+        germanFakeTapSearch.getMutableResolvedSearchTerm().setContextLanguage("de");
+        registerFakeTapSearch(germanFakeTapSearch);
+
         registerFakeTapSearch(
                 new FakeTapSearch("intelligence", false, 200, "Intelligence", "Intelligence"));
 
-        // Register a fake tap search that will fake a logged event ID from the server.
-        registerFakeTapSearch(new FakeTapSearch("intelligence-logged-event-id", false, 200,
-                "Intelligence", "Intelligence", "alternate-term", "", false, 0, 0, "", "", "", "",
-                QuickActionCategory.NONE, LOGGED_EVENT_ID, "", ""));
+        // Register a fake tap search that will fake a logged event ID from the server, when
+        // a fake tap is done on the intelligence-logged-event-id element in the test file.
+        FakeTapSearch loggedIdFakeTapSearch = new FakeTapSearch(
+                "intelligence-logged-event-id", false, 200, "Intelligence", "Intelligence");
+        loggedIdFakeTapSearch.getMutableResolvedSearchTerm().setLoggedEventId(LOGGED_EVENT_ID);
+        registerFakeTapSearch(loggedIdFakeTapSearch);
 
         // Register a resolving search of "States" that expands to "United States".
-        registerFakeSlowResolveSearch(new FakeSlowResolveSearch("states", false, 200, "States",
-                "States", "alternate-term", "", false, -7, 0, "", "", "", "",
-                QuickActionCategory.NONE, 0, "", ""));
-        registerFakeSlowResolveSearch(new FakeSlowResolveSearch("search", false, 200, "Search",
-                "Search", "alternate-term", "", false, 0, 0, "", "", "", "",
-                QuickActionCategory.NONE, 0, "", ""));
+        FakeSlowResolveSearch expandingStatesTapSearch =
+                new FakeSlowResolveSearch("states", false, 200, "States", "States");
+        expandingStatesTapSearch.getMutableResolvedSearchTerm().setSelectionStartAdjust(-7);
+        registerFakeSlowResolveSearch(expandingStatesTapSearch);
+        registerFakeSlowResolveSearch(
+                new FakeSlowResolveSearch("search", false, 200, "Search", "Search"));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 7852f56f..09537a6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -456,56 +456,15 @@
      * Posts a fake response on the Main thread.
      */
     private final class FakeResponseOnMainThread implements Runnable {
+        private final ResolvedSearchTerm mResolvedSearchTerm;
 
-        private final boolean mIsNetworkUnavailable;
-        private final int mResponseCode;
-        private final String mSearchTerm;
-        private final String mDisplayText;
-        private final String mAlternateTerm;
-        private final String mMid;
-        private final boolean mDoPreventPreload;
-        private final int mStartAdjust;
-        private final int mEndAdjust;
-        private final String mContextLanguage;
-        private final String mThumbnailUrl;
-        private final String mCaption;
-        private final String mQuickActionUri;
-        private final int mQuickActionCategory;
-        private final long mLoggedEventId;
-        private final String mSearchUrlFull;
-        private final String mSearchUrlPreload;
-
-        public FakeResponseOnMainThread(boolean isNetworkUnavailable, int responseCode,
-                String searchTerm, String displayText, String alternateTerm, String mid,
-                boolean doPreventPreload, int startAdjust, int endAdjudst, String contextLanguage,
-                String thumbnailUrl, String caption, String quickActionUri, int quickActionCategory,
-                long loggedEventId, String searchUrlFull, String searchUrlPreload) {
-            mIsNetworkUnavailable = isNetworkUnavailable;
-            mResponseCode = responseCode;
-            mSearchTerm = searchTerm;
-            mDisplayText = displayText;
-            mAlternateTerm = alternateTerm;
-            mMid = mid;
-            mDoPreventPreload = doPreventPreload;
-            mStartAdjust = startAdjust;
-            mEndAdjust = endAdjudst;
-            mContextLanguage = contextLanguage;
-            mThumbnailUrl = thumbnailUrl;
-            mCaption = caption;
-            mQuickActionUri = quickActionUri;
-            mQuickActionCategory = quickActionCategory;
-            mLoggedEventId = loggedEventId;
-            mSearchUrlFull = searchUrlFull;
-            mSearchUrlPreload = searchUrlPreload;
+        public FakeResponseOnMainThread(ResolvedSearchTerm resolvedSearchTerm) {
+            mResolvedSearchTerm = resolvedSearchTerm;
         }
 
         @Override
         public void run() {
-            mFakeServer.handleSearchTermResolutionResponse(mIsNetworkUnavailable, mResponseCode,
-                    mSearchTerm, mDisplayText, mAlternateTerm, mMid, mDoPreventPreload,
-                    mStartAdjust, mEndAdjust, mContextLanguage, mThumbnailUrl, mCaption,
-                    mQuickActionUri, mQuickActionCategory, mLoggedEventId, mSearchUrlFull,
-                    mSearchUrlPreload);
+            mFakeServer.handleSearchTermResolutionResponse(mResolvedSearchTerm);
         }
     }
 
@@ -515,25 +474,18 @@
      */
     private void fakeResponse(boolean isNetworkUnavailable, int responseCode,
             String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload) {
-        fakeResponse(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm,
-                null, doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0, "", "");
+        fakeResponse(new ResolvedSearchTerm(isNetworkUnavailable, responseCode, searchTerm,
+                displayText, alternateTerm, doPreventPreload));
     }
 
     /**
      * Fakes a server response with the parameters given.
      * {@See ContextualSearchManager#handleSearchTermResolutionResponse}.
      */
-    private void fakeResponse(boolean isNetworkUnavailable, int responseCode, String searchTerm,
-            String displayText, String alternateTerm, String mid, boolean doPreventPreload,
-            int startAdjust, int endAdjust, String contextLanguage, String thumbnailUrl,
-            String caption, String quickActionUri, int quickActionCategory, long loggedEventId,
-            String searchUrlFull, String searchUrlPreload) {
+    private void fakeResponse(ResolvedSearchTerm resolvedSearchTerm) {
         if (mFakeServer.getSearchTermRequested() != null) {
             InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                    new FakeResponseOnMainThread(isNetworkUnavailable, responseCode, searchTerm,
-                            displayText, alternateTerm, mid, doPreventPreload, startAdjust,
-                            endAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri,
-                            quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload));
+                    new FakeResponseOnMainThread(resolvedSearchTerm));
         }
     }
 
@@ -2395,8 +2347,9 @@
         clickWordNode("intelligence");
         waitForPanelToPeek();
 
-        fakeResponse(false, 200, "Intelligence", "United States Intelligence", "alternate-term",
-                null, false, -14, 0, "", "", "", "", QuickActionCategory.NONE, 0, "", "");
+        fakeResponse(new ResolvedSearchTerm(false, 200, "Intelligence",
+                "United States Intelligence", "alternate-term", null, false, -14, 0, "", "", "", "",
+                QuickActionCategory.NONE, 0, "", ""));
         waitForSelectionToBe("United States Intelligence");
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
index 089bcf55..224fc4cf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -31,6 +33,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestAbortTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_abort_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
index 77200c2..f092a5d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
@@ -14,6 +14,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,6 +30,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -39,6 +41,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestBillingAddressTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
index 4818f4e..aff552c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
@@ -11,6 +11,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -26,6 +27,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -37,6 +39,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestBillingAddressWithoutPhoneTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentGooglePayTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentGooglePayTest.java
index c77452b..d582df3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentGooglePayTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentGooglePayTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -33,6 +35,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=PaymentRequestHasEnrolledInstrument"})
 public class PaymentRequestCanMakePaymentGooglePayTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_can_make_payment_query_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
index 3d49ef8..3a95016 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentMetricsTest.java
@@ -13,6 +13,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,6 +30,7 @@
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -41,6 +43,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=PaymentRequestHasEnrolledInstrument"})
 public class PaymentRequestCanMakePaymentMetricsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_can_make_payment_metrics_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
index 573b859..22953f0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
@@ -11,6 +11,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -36,6 +38,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=PaymentRequestHasEnrolledInstrument"})
 public class PaymentRequestCanMakePaymentQueryNoCardTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_can_make_payment_query_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
index 982bbee..acecb5e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
@@ -11,6 +11,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -35,6 +37,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestCanMakePaymentQueryTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_can_make_payment_query_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
index 5a30550..a139197 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
@@ -8,6 +8,7 @@
 import android.view.View;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -36,6 +38,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestCardEditorAutoAdvanceTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
index bcd66d24..2a4fe4d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestContactDetailsAndFreeShippingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule(
             "payment_request_contact_details_and_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
index 02da3ac7f..a1b1ebc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestContactDetailsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_contact_details_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java
index 85abcc5..d30346b1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -34,6 +36,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=" + ChromeFeatureList.WEB_PAYMENTS_RETURN_GOOGLE_PAY_IN_BASIC_CARD})
 public class PaymentRequestDebitTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_debit_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java
index e0dc466..23aab4e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -35,6 +37,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=" + ChromeFeatureList.WEB_PAYMENTS_RETURN_GOOGLE_PAY_IN_BASIC_CARD})
 public class PaymentRequestDontHaveDebitTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_debit_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java
index c9793ef..5c4ecac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -19,6 +20,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.ArrayList;
 import java.util.concurrent.ExecutionException;
@@ -32,6 +34,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestDynamicShippingMultipleAddressesTest
         implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
index 4b228a72..07c8ad7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -36,6 +38,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestDynamicShippingSingleAddressTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
index 2a1dd2b..1b5c6bf5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -35,6 +37,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestEmailAndFreeShippingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_email_and_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java
index da55c89..120c19a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndPhoneTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -33,6 +35,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestEmailAndPhoneTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_email_and_phone_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java
index 2535deb3..558c3de 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -33,6 +35,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestEmailTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_email_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmptyUpdateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmptyUpdateTest.java
index 13699b5..98dbfe5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmptyUpdateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmptyUpdateTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -20,6 +21,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -31,6 +33,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestEmptyUpdateTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_empty_update_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
index bf8a58b..05e6674 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
@@ -9,6 +9,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.Calendar;
@@ -35,6 +37,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestExpiredLocalCardTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
index 97e2360..0ee5fce 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -20,6 +21,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -32,6 +34,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestExtraShippingOptionsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_extra_shipping_options_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
index bb10772..39e0940 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
@@ -6,10 +6,12 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
@@ -20,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -31,6 +34,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestFailCompleteTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_fail_complete_test.html", this);
@@ -59,8 +66,16 @@
         mPaymentRequestTestRule.clickCardUnmaskButtonAndWait(
                 ModalDialogProperties.ButtonType.POSITIVE,
                 mPaymentRequestTestRule.getResultReady());
-        mPaymentRequestTestRule.clickAndWait(
-                R.id.ok_button, mPaymentRequestTestRule.getDismissed());
+
+        // Dismiss the error message overlay.
+        int callCount = mPaymentRequestTestRule.getDismissed().getCallCount();
+        ThreadUtils.runOnUiThreadBlocking((Runnable) ()
+                                                  -> mPaymentRequestTestRule.getPaymentRequestUI()
+                                                             .getDialogForTest()
+                                                             .findViewById(R.id.ok_button)
+                                                             .performClick());
+        mPaymentRequestTestRule.getDismissed().waitForCallback(callCount);
+
         mPaymentRequestTestRule.expectResultContains(new String[] {"Transaction failed"});
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java
index e34e0f1..fa6e1c60 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java
@@ -9,6 +9,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -20,6 +21,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -30,6 +32,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestFieldTrialTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_bobpay_and_cards_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
index b9b62ad1..3fe3bdd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,6 +26,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.chrome.test.util.RenderTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
@@ -37,6 +39,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestFreeShippingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
index 22b61ef..6033780 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -20,6 +21,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -32,6 +34,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestIdTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_id_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java
index 91b31b3..357796d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -36,6 +38,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestIncompleteContactDetailsAndFreeShippingTest
         implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule(
             "payment_request_contact_details_and_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
index bb1f316..1e3542f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestIncompleteContactDetailsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_contact_details_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java
index ba79e0c..9d22c7cb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestIncompleteEmailTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_email_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java
index f309d70..22d9ecb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestSection;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestIncompletePhoneTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_phone_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
index ecec5db..e15f347a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
@@ -8,6 +8,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -35,6 +37,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=" + ChromeFeatureList.WEB_PAYMENTS_RETURN_GOOGLE_PAY_IN_BASIC_CARD})
 public class PaymentRequestIncompleteServerCardTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_no_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
index 2b8c15e..921545ab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
@@ -15,6 +15,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,6 +33,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -43,6 +45,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestJourneyLoggerTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_metrics_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
index 314319d7..b97a74fe 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
@@ -13,6 +13,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,6 +33,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
@@ -44,6 +46,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestMetricsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_metrics_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
index 890fb49..bbeeff9f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.ArrayList;
 import java.util.concurrent.ExecutionException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestMultipleContactDetailsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_contact_details_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
index cfba731..24e7989 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestNameAndFreeShippingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_name_and_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
index feb7ce5..42834fe3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -33,6 +35,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestNameTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_name_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
index f99534d..a7b0c55 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
@@ -12,6 +12,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,6 +31,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -41,6 +43,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestNoShippingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_no_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoUpdateWithTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoUpdateWithTest.java
index 646255c5..2f0008e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoUpdateWithTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoUpdateWithTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestNoUpdateWithTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mRule =
             new PaymentRequestTestRule("payment_request_no_update_with_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
index e3df244..494d819 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
@@ -20,6 +20,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,6 +36,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.payments.mojom.BasicCardNetwork;
 import org.chromium.payments.mojom.BasicCardType;
 
@@ -50,6 +52,10 @@
         ENABLE_EXPERIMENTAL_WEB_PLATFORM_FEATURES, ENABLE_WEB_PAYMENTS_MODIFIERS,
         "enable-features=" + ChromeFeatureList.WEB_PAYMENTS_RETURN_GOOGLE_PAY_IN_BASIC_CARD})
 public class PaymentRequestPaymentAppAndBasicCardWithModifiersTest {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule(
             "payment_request_bobpay_and_basic_card_with_modifiers_test.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
index 710cbd4..f5982676 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
@@ -12,6 +12,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -26,6 +27,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -37,6 +39,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestPaymentAppAndCardsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_bobpay_and_cards_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppCanMakePaymentQueryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppCanMakePaymentQueryTest.java
index 5e5dc27..eb2773a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppCanMakePaymentQueryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppCanMakePaymentQueryTest.java
@@ -12,6 +12,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -33,6 +35,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=" + ChromeFeatureList.PER_METHOD_CAN_MAKE_PAYMENT_QUOTA})
 public class PaymentRequestPaymentAppCanMakePaymentQueryTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule(
             "payment_request_can_make_payment_query_bobpay_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
index dddcc3d..163e729 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
@@ -12,6 +12,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.TestPay;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestPaymentAppTest {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_bobpay_test.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java
index 8efd04c..a21b71c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipPreloadTest.java
@@ -13,6 +13,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,6 +26,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -42,6 +44,10 @@
         "disable-features=" + ChromeFeatureList.SERVICE_WORKER_PAYMENT_APPS,
 })
 public class PaymentRequestPaymentAppUiSkipPreloadTest {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_bobpay_ui_skip_preload_test.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java
index ca7afbd1..ba911c4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppUiSkipTest.java
@@ -13,6 +13,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -38,6 +40,10 @@
         "disable-features=" + ChromeFeatureList.ANDROID_PAYMENT_APPS,
         "disable-features=" + ChromeFeatureList.SERVICE_WORKER_PAYMENT_APPS})
 public class PaymentRequestPaymentAppUiSkipTest {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_bobpay_ui_skip_test.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
index 99144e56..52e92aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,6 +26,7 @@
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.TestPay;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -33,6 +35,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestPaymentAppsSortingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule(
             "payment_request_alicepay_bobpay_charliepay_and_cards_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java
index cd0636e..df3c257 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentMethodIdentifierTest.java
@@ -11,6 +11,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -25,6 +26,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -37,6 +39,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=PaymentRequestHasEnrolledInstrument"})
 public class PaymentRequestPaymentMethodIdentifierTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_payment_method_identifier_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
index b237f15..934e5c9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -34,6 +36,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestPhoneAndFreeShippingTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_phone_and_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java
index f470fd6..b97ea73b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -33,6 +35,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestPhoneTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_phone_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
index db0f8e1..d9001dc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
@@ -10,6 +10,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -35,6 +37,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestRemoveBillingAddressTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_no_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java
index f9f32897..5994919 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java
@@ -9,6 +9,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +25,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -36,6 +38,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         PaymentRequestTestRule.ENABLE_EXPERIMENTAL_WEB_PLATFORM_FEATURES})
 public class PaymentRequestRetryTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_retry.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
index b6149a2..eb69a0c9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -33,6 +35,10 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=" + ChromeFeatureList.WEB_PAYMENTS_RETURN_GOOGLE_PAY_IN_BASIC_CARD})
 public class PaymentRequestServerCardTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_no_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
index 532e34d..03a21bab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
@@ -10,6 +10,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.payments.mojom.BasicCardNetwork;
 import org.chromium.payments.mojom.BasicCardType;
 
@@ -36,6 +38,10 @@
         // payment instruments instead of showing payment request UI.
         "enable-features=" + ChromeFeatureList.NO_CREDIT_CARD_ABORT})
 public class PaymentRequestServiceWorkerPaymentAppTest {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule = new PaymentRequestTestRule(
             "payment_request_bobpay_and_basic_card_with_modifier_optional_data_test.html");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
index 7a6a74efe..9e5c3aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -32,6 +34,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestShippingAddressAndOptionTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
index 9860578..f9d8a04 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
@@ -6,6 +6,7 @@
 
 import android.support.test.filters.MediumTest;
 
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -31,6 +33,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestShippingAddressChangeTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_shipping_address_change_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
index df90178..4e682ce 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -32,6 +34,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestShowTwiceTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_show_twice_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
index 8474962..2934d7c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -26,6 +27,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.content_public.browser.LoadUrlParams;
 
 import java.util.concurrent.ExecutionException;
@@ -38,6 +40,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestTabTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_dynamic_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
index 8d25a21..ea0ef0ef 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -285,11 +285,17 @@
     }
 
     /** Clicks on an element in the payments UI. */
-    protected void clickAndWait(final int resourceId, CallbackHelper helper)
+    protected void clickAndWait(int resourceId, CallbackHelper helper)
             throws InterruptedException, TimeoutException {
         int callCount = helper.getCallCount();
-        ThreadUtils.runOnUiThreadBlocking(
-                (Runnable) () -> mUI.getDialogForTest().findViewById(resourceId).performClick());
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                boolean canClick = mUI.isAcceptingUserInput();
+                if (canClick) mUI.getDialogForTest().findViewById(resourceId).performClick();
+                return canClick;
+            }
+        });
         helper.waitForCallback(callCount);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java
index be3e6cd..c3d9679 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -32,6 +34,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestUpdateWithTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mRule =
             new PaymentRequestTestRule("payment_request_update_with_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
index 79e3406..f808aa6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
@@ -7,6 +7,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.junit.Assert;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -21,6 +22,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 
 import java.util.concurrent.ExecutionException;
@@ -33,6 +35,10 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class PaymentRequestUseStatsTest implements MainActivityStartCallback {
+    // Disable animations to reduce flakiness.
+    @ClassRule
+    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
+
     @Rule
     public PaymentRequestTestRule mPaymentRequestTestRule =
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
index b41fc710..76f8377 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
@@ -6,7 +6,6 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
-import android.net.Uri;
 import android.os.Build;
 import android.support.test.filters.LargeTest;
 import android.support.v7.widget.RecyclerView;
@@ -69,7 +68,7 @@
 
     // The final set of photos picked by the dialog. Can be an empty array, if
     // nothing was selected.
-    private Uri[] mLastSelectedPhotos;
+    private String[] mLastSelectedPhotos;
 
     // The list of currently selected photos (built piecemeal).
     private List<PickerBitmap> mCurrentPhotoSelection;
@@ -87,12 +86,12 @@
     public void setUp() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
         mTestFiles = new ArrayList<>();
-        mTestFiles.add(new PickerBitmap(Uri.parse("a"), 5L, PickerBitmap.TileTypes.PICTURE));
-        mTestFiles.add(new PickerBitmap(Uri.parse("b"), 4L, PickerBitmap.TileTypes.PICTURE));
-        mTestFiles.add(new PickerBitmap(Uri.parse("c"), 3L, PickerBitmap.TileTypes.PICTURE));
-        mTestFiles.add(new PickerBitmap(Uri.parse("d"), 2L, PickerBitmap.TileTypes.PICTURE));
-        mTestFiles.add(new PickerBitmap(Uri.parse("e"), 1L, PickerBitmap.TileTypes.PICTURE));
-        mTestFiles.add(new PickerBitmap(Uri.parse("f"), 0L, PickerBitmap.TileTypes.PICTURE));
+        mTestFiles.add(new PickerBitmap("a", 5L, PickerBitmap.TileTypes.PICTURE));
+        mTestFiles.add(new PickerBitmap("b", 4L, PickerBitmap.TileTypes.PICTURE));
+        mTestFiles.add(new PickerBitmap("c", 3L, PickerBitmap.TileTypes.PICTURE));
+        mTestFiles.add(new PickerBitmap("d", 2L, PickerBitmap.TileTypes.PICTURE));
+        mTestFiles.add(new PickerBitmap("e", 1L, PickerBitmap.TileTypes.PICTURE));
+        mTestFiles.add(new PickerBitmap("f", 0L, PickerBitmap.TileTypes.PICTURE));
         PickerCategoryView.setTestFiles(mTestFiles);
 
         DecoderServiceHost.setReadyCallback(this);
@@ -101,7 +100,7 @@
     // PhotoPickerDialog.PhotoPickerListener:
 
     @Override
-    public void onPhotoPickerUserAction(@PhotoPickerAction int action, Uri[] photos) {
+    public void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos) {
         mLastActionRecorded = action;
         mLastSelectedPhotos = photos != null ? photos.clone() : null;
         if (mLastSelectedPhotos != null) Arrays.sort(mLastSelectedPhotos);
@@ -234,7 +233,7 @@
 
         Assert.assertEquals(1, mLastSelectedPhotos.length);
         Assert.assertEquals(PhotoPickerAction.PHOTOS_SELECTED, mLastActionRecorded);
-        Assert.assertEquals(mTestFiles.get(1).getUri().getPath(), mLastSelectedPhotos[0]);
+        Assert.assertEquals(mTestFiles.get(1).getFilePath(), mLastSelectedPhotos[0]);
 
         dismissDialog();
     }
@@ -256,9 +255,9 @@
 
         Assert.assertEquals(3, mLastSelectedPhotos.length);
         Assert.assertEquals(PhotoPickerAction.PHOTOS_SELECTED, mLastActionRecorded);
-        Assert.assertEquals(mTestFiles.get(0).getUri().getPath(), mLastSelectedPhotos[0]);
-        Assert.assertEquals(mTestFiles.get(2).getUri().getPath(), mLastSelectedPhotos[1]);
-        Assert.assertEquals(mTestFiles.get(4).getUri().getPath(), mLastSelectedPhotos[2]);
+        Assert.assertEquals(mTestFiles.get(0).getFilePath(), mLastSelectedPhotos[0]);
+        Assert.assertEquals(mTestFiles.get(2).getFilePath(), mLastSelectedPhotos[1]);
+        Assert.assertEquals(mTestFiles.get(4).getFilePath(), mLastSelectedPhotos[2]);
 
         dismissDialog();
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
index c60dd78..7de91fe 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java
@@ -98,11 +98,6 @@
 
     private static final String TEST_ACTION = "com.artificial.package.TEST_ACTION";
 
-    private static enum ShowSettings {
-        YES,
-        NO;
-    }
-
     private static final class TestObserver implements FirstRunActivityObserver {
         public final CallbackHelper flowIsKnownCallback = new CallbackHelper();
 
@@ -144,7 +139,7 @@
         Assert.assertNull(SigninTestUtil.getCurrentAccount());
         Assert.assertFalse(SyncTestUtil.isSyncRequested());
 
-        processFirstRun(testAccount.name, ShowSettings.NO);
+        processFirstRun(testAccount.name, false /* ShowSettings */);
         Assert.assertEquals(testAccount, SigninTestUtil.getCurrentAccount());
         SyncTestUtil.waitForSyncActive();
     }
@@ -159,7 +154,7 @@
     @FlakyTest(message = "https://crbug.com/616456")
     public void testSignInWithOpenSettings() throws Exception {
         final Account testAccount = SigninTestUtil.addTestAccount();
-        final Preferences prefActivity = processFirstRun(testAccount.name, ShowSettings.YES);
+        final Preferences prefActivity = processFirstRun(testAccount.name, true /* ShowSettings */);
 
         // User should be signed in and the sync backend should initialize, but sync should not
         // become fully active until the settings page is closed.
@@ -185,7 +180,7 @@
     public void testNoSignIn() throws Exception {
         SigninTestUtil.addTestAccount();
         Assert.assertFalse(SyncTestUtil.isSyncRequested());
-        processFirstRun(null, ShowSettings.NO);
+        processFirstRun(null, false /* ShowSettings */);
         Assert.assertNull(SigninTestUtil.getCurrentAccount());
         Assert.assertFalse(SyncTestUtil.isSyncRequested());
     }
@@ -197,13 +192,12 @@
      * @param showSettings Whether to show the settings page.
      * @return The Preferences activity if showSettings was YES; null otherwise.
      */
-    private Preferences processFirstRun(String account, ShowSettings showSettings) {
+    private Preferences processFirstRun(String account, boolean showSettings) {
         FirstRunSignInProcessor.setFirstRunFlowSignInComplete(false);
-        FirstRunSignInProcessor.finalizeFirstRunFlowState(
-                account, showSettings == ShowSettings.YES);
+        FirstRunSignInProcessor.finalizeFirstRunFlowState(account, showSettings);
 
         Preferences prefActivity = null;
-        if (showSettings == ShowSettings.YES) {
+        if (showSettings) {
             prefActivity =
                     ActivityUtils.waitForActivity(InstrumentationRegistry.getInstrumentation(),
                             Preferences.class, new Runnable() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java
index 52a1c6e..6c888e6 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/EventTrackerTest.java
@@ -5,14 +5,24 @@
 package org.chromium.chrome.browser.usage_stats;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.Callback;
+import org.chromium.base.Promise;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -23,26 +33,53 @@
 public class EventTrackerTest {
     private EventTracker mEventTracker;
 
+    @Mock
+    private UsageStatsBridge mBridge;
+    @Captor
+    private ArgumentCaptor<
+            Callback<List<org.chromium.chrome.browser.usage_stats.WebsiteEventProtos.WebsiteEvent>>>
+            mLoadCallbackCaptor;
+    @Captor
+    private ArgumentCaptor<Callback<Boolean>> mWriteCallbackCaptor;
+
     @Before
     public void setUp() {
-        mEventTracker = new EventTracker();
+        MockitoAnnotations.initMocks(this);
+        mEventTracker = new EventTracker(mBridge);
+        verify(mBridge, times(1)).getAllEvents(mLoadCallbackCaptor.capture());
     }
 
     @Test
     public void testRangeQueries() {
-        addEntries(100, 1l, 0l);
-        List<WebsiteEvent> result = mEventTracker.queryWebsiteEvents(0l, 50l);
-        assertEquals(result.size(), 50);
-
-        result = mEventTracker.queryWebsiteEvents(0l, 100l);
-        assertEquals(result.size(), 100);
+        resolveLoadCallback();
+        addEntries(100, 2l, 1l);
+        mEventTracker.queryWebsiteEvents(0l, 50l).then(
+                (result) -> { assertEquals(result.size(), 25); });
+        mEventTracker.queryWebsiteEvents(0l, 49l).then(
+                (result) -> { assertEquals(result.size(), 24); });
+        mEventTracker.queryWebsiteEvents(0l, 51l).then(
+                (result) -> { assertEquals(result.size(), 25); });
+        mEventTracker.queryWebsiteEvents(0l, 1000l).then(
+                (result) -> { assertEquals(result.size(), 100); });
+        mEventTracker.queryWebsiteEvents(1l, 99l).then(
+                (result) -> { assertEquals(result.size(), 49); });
     }
 
     private void addEntries(int quantity, long stepSize, long startTime) {
         for (int i = 0; i < quantity; i++) {
-            mEventTracker.addWebsiteEvent(
+            Promise<Void> writePromise = mEventTracker.addWebsiteEvent(
                     new WebsiteEvent(startTime, "", WebsiteEvent.EventType.START));
+            verify(mBridge, times(i + 1)).addEvents(any(), mWriteCallbackCaptor.capture());
+            resolveWriteCallback();
             startTime += stepSize;
         }
     }
+
+    private void resolveLoadCallback() {
+        mLoadCallbackCaptor.getValue().onResult(new ArrayList<>());
+    }
+
+    private void resolveWriteCallback() {
+        mWriteCallbackCaptor.getValue().onResult(true);
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
index d55df2d..3861f0e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -24,6 +25,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.Promise;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
@@ -73,6 +75,7 @@
         doReturn(null).when(mTab).getUrl();
         doReturn(Arrays.asList(mTabModel)).when(mTabModelSelector).getModels();
         doReturn(mTab).when(mTabModelSelector).getCurrentTab();
+        doReturn(Promise.fulfilled("1")).when(mTokenTracker).getTokenForFqdn(anyString());
     }
 
     @Test
diff --git a/chrome/android/touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java b/chrome/android/touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java
new file mode 100644
index 0000000..7ff99ca
--- /dev/null
+++ b/chrome/android/touchless/fallback/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java
@@ -0,0 +1,10 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.touchless;
+
+/**
+ * The fallback version of TouchlessUiController, when touchless mode isn't enabled.
+ */
+public class TouchlessUiController {}
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
index e059c1e..dd6fedbe 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
@@ -12,6 +12,7 @@
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.IntentHandler.IntentHandlerDelegate;
 import org.chromium.chrome.browser.IntentHandler.TabOpenType;
@@ -44,6 +45,9 @@
     private TooltipView mTooltipView;
     private ProgressBarView mProgressBarView;
 
+    /** The class that controls the UI for touchless devices. */
+    private TouchlessUiController mUiController;
+
     /**
      * Internal class which performs the intent handling operations delegated by IntentHandler.
      */
@@ -111,6 +115,7 @@
                 (ViewGroup) findViewById(android.R.id.content), null /* controlContainer */);
 
         getFullscreenManager().setTab(getActivityTab());
+        mUiController = AppHooks.get().createTouchlessUiController(this);
         super.finishNativeInitialization();
     }
 
@@ -208,7 +213,10 @@
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (mProgressBarCoordinator != null) mProgressBarCoordinator.onKeyEvent();
-        return super.dispatchKeyEvent(event);
+
+        boolean consumedEvent = mUiController != null ? mUiController.onKeyEvent(event) : false;
+
+        return consumedEvent || super.dispatchKeyEvent(event);
     }
 
     @Override
@@ -222,5 +230,9 @@
         super.onDestroyInternal();
         if (mKeyFunctionsIPHCoordinator != null) mKeyFunctionsIPHCoordinator.destroy();
         if (mProgressBarCoordinator != null) mProgressBarCoordinator.destroy();
+        if (mUiController != null) {
+            mUiController.destroy();
+            mUiController = null;
+        }
     }
 }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java
new file mode 100644
index 0000000..bfb42b49
--- /dev/null
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessUiController.java
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.touchless;
+
+import android.view.KeyEvent;
+
+/** A controller for touchless UI. */
+public interface TouchlessUiController {
+    /**
+     * A notification that a key event occurred.
+     * @param event The event object.
+     * @return Whether the event was consumed.
+     */
+    boolean onKeyEvent(KeyEvent event);
+
+    /**
+     * Clean up anything that needs to be.
+     */
+    void destroy();
+}
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index 824fe3d..a6e2342 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -43,9 +43,9 @@
 #include "services/preferences/public/cpp/manifest.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
 #include "third_party/blink/public/mojom/badging/badging.mojom.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.h"
 #include "third_party/blink/public/mojom/input/input_host.mojom.h"
 #include "third_party/blink/public/mojom/webshare/webshare.mojom.h"
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.h"
 #include "third_party/blink/public/platform/modules/installedapp/installed_app_provider.mojom.h"
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 8268806..59098e7 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -924,10 +924,10 @@
 
       <if expr="not is_android">
         <message name="IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_BUBBLE_TEXT" desc="The text of a bubble that confirms users allows integrating the accessibility labels service of Google to Chromium.">
-          If an image doesn’t have a useful description, Chromium will try to provide one for you. Images are scanned by Google. You can turn this off in settings at any time.
+          If an image doesn’t have a useful description, Chromium will try to provide one for you. To create descriptions, images are sent to Google. You can turn this off in settings at any time.
         </message>
         <message name="IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_BUBBLE_TEXT_ONCE" desc="The text of a bubble that confirms users allows integrating the accessibility labels service of Google to Chromium just once.">
-          If an image doesn’t have a useful description, Chromium will try to provide one for you. Images are scanned by Google.
+          If an image doesn’t have a useful description, Chromium will try to provide one for you. To create descriptions, images are sent to Google.
         </message>
         <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TEXT" desc="The text of a bubble that confirms users allows integrating the spelling service of Google to Chrome.">
           Chromium can provide smarter spell-checking by sending what you type in the browser to Google servers, allowing you to use the same spell-checking technology used by Google search.
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 9175b6b..99bf2122 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -942,10 +942,10 @@
       <!-- content area context menus. Android does not use it -->
       <if expr="not is_android">
         <message name="IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_BUBBLE_TEXT" desc="The text of a bubble that confirms users allows integrating the accessibility labels service of Google to Chromium.">
-          If an image doesn’t have a useful description, Chrome will try to provide one for you. Images are scanned by Google. You can turn this off in settings at any time.
+          If an image doesn’t have a useful description, Chrome will try to provide one for you. To create descriptions, images are sent to Google. You can turn this off in settings at any time.
         </message>
         <message name="IDS_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_BUBBLE_TEXT_ONCE" desc="The text of a bubble that confirms users allows integrating the accessibility labels service of Google to Chromium just once.">
-          If an image doesn’t have a useful description, Chrome will try to provide one for you. Images are scanned by Google.
+          If an image doesn’t have a useful description, Chrome will try to provide one for you. To create descriptions, images are sent to Google.
         </message>
         <message name="IDS_CONTENT_CONTEXT_SPELLING_BUBBLE_TEXT" desc="The text of a bubble that confirms users allows integrating the spelling service of Google to Chrome.">
           Google Chrome can provide smarter spell-checking by sending what you type in the browser to Google servers, allowing you to use the same spell-checking technology used by Google search.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 65e0aa0..2596575 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -4643,4 +4643,93 @@
       Hide sensitive content
     </message>
   </if>
+
+  <!-- Security Keys -->
+  <message name="IDS_SETTINGS_SECURITY_KEYS_TITLE" desc="Headline in the Settings UI for the subpage handling security keys. Security keys are external physcial devices for user authentication and the translation should match that used in, for example, IDS_WEBAUTHN_USB_ACTIVATE_DESCRIPTION.">
+      Security Keys
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_DESC" desc="Description in the Settings UI for the subpage handling security keys. Security keys are external physcial devices for user authentication.">
+      Reset devices, set &amp; change PINs.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_SET_PIN" desc="A header that appears in the Settings subpage for security keys (which are external devices for user authentication). PINs are often four-digit codes, commonly used to authorise the use of ATM cards. A similar mechanism can be used with security keys and this is the heading for the section about settings them.">
+      Set PIN
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_SET_PIN_DESC" desc="A description that appears in the Settings subpage for security keys (which are external devices for user authentication). PINs are often four-digit codes, commonly used to authorise the use of ATM cards. A similar mechanism can be used with security keys and this is the description for the section about settings them.">
+      Set a PIN on a security key to identify yourself
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET" desc="A header that appears in the Settings subpage for security keys (which are external devices for user authentication). This is the heading for the section about resetting them to factory settings.">
+      Reset
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_DESC" desc="A header that appears in the Settings subpage for security keys (which are external devices for user authentication). This is the description for the section about resetting them to factory settings.">
+      Factory-reset a security key
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_TITLE" desc="The title of a dialog for factory-resetting security keys (which are external devices for user authentication). Resetting in this context means erasing a security key and returning it to an initial, blank state.">
+    Reset Security Key
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_INTRO" desc="A description of resetting security keys (which are external devices for user authentication). Resetting in this context means erasing a security key and returning it to an initial, blank state.">
+    Resetting a Security Key will erase all keys associated with the device and clear all configured PINs.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_STEP1" desc="An instruction to a user to physically unplug a security key from their computer, reinsert it, and then touch the activation button that's on the device.">
+    Please remove, reinsert, and then touch your security key to begin the reset process.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_STEP2" desc="An instruction to a user to press the activation button on their security key a second time to confirm that they wish to reset (i.e. erase) their security key (which is an external device for user authentication).">
+    Please touch the same security key again to confirm the reset. This will erase all credentials stored on the security key and remove any configured PIN.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_NO_RESET" desc="A failure message reporting to the user that it is not possible to reset the security key that they selected because the device does not support that operation.">
+    That security key does not support being reset.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_ERROR" desc="A failure message reporting to the user that the attempt to reset their security key (which is an external device for user authentication) failed. This is message is shown in uncommon cases when we don't have a more specific message to show the user and have fallen back to displaying a numerical error code reported by the device.">
+    Failed to reset device. Error <ph name="ERROR_CODE">$1<ex>22</ex></ph>.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_SUCCESS" desc="A mesasge to the user that they have successfully reset (i.e. erased) their security key (which is an external device for user authentication).">
+    Reset successful.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_RESET_NOTALLOWED" desc="A mesasge to the user that an attempt to reset (i.e. erase) their security key (an external device for user authentication) failed because the security key refused to be reset. This is usually caused because a reset is only allowed within the first few seconds after being plugged in, so the user has to perform the operation quickly.">
+    Reset was not permitted. Some security keys may only allow a reset within the first few seconds after being inserted—you may wish to reattempt the process more quickly.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PINS_DESC" desc="A description of PINs for security keys. PINs are often four-digit codes, commonly used to authorise the use of ATM cards. Security keys are external devices for user authentication">
+    A PIN consists of four or more characters and serves to prove that the owner of a security key is present during certain operations. Once set, a PIN can be changed but cannot be removed without fully resetting the security key.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_TOUCH" desc="An instruction to a user to physically the activation button on their security key (which is an external device for user authentication).">
+    Please insert and touch your security key to begin setting or changing a PIN
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_NO_PIN" desc="A failure message shown to a user when they attempt to set a PIN on a security key that does not support PINs. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    That security key does not support setting a PIN.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_INTRO" desc="A message shown when a user is trying to change the PIN on a security key to prompt the user to enter the current PIN for the device. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    Enter your &lt;i&gt;current&lt;/i&gt; PIN to change it. If you do not know the current PIN then the token has to be reset to clear it.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_INCORRECT" desc="A message shown to the user when they enter an incorrect PIN for a security key. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    PIN incorrect.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_RETRIES_PL" desc="A message shown when a user is trying the change the PIN on a security key to inform them of the number of attempts remaining for them to enter the correct, current PIN. The number in the placeholder will always be more than one. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    You have <ph name="RETRIES">$1<ex>8</ex></ph> attempts remaining.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_RETRIES_SIN" desc="A message shown when a user is trying the change the PIN on a security key to inform them that they only have a single chance to get it right. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    You have only one attempt remaining!
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_NEW_PIN" desc="A message shown when a user is trying to set a PIN on a security key. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    Enter new PIN. A PIN must be at least four characters long and can contain letters, numbers, and other characters.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN" desc="A label shown above a text box where the user is expected to enter the current PIN for a security key. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    Current PIN
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN" desc="A label shown above a text box where the user is expected to enter a new PIN for a security key. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    PIN
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_CONFIRM_PIN" desc="A label shown above a text box where the user is expected to reenter a new PIN for a security key. The text box is a duplicate of an immediately preceeding text box where the user has already entered this value. The user is asked to enter the same value twice in order to ensure that they entered it correctly. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    Confirm PIN
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_SUCCESS" desc="A message shown when the user has successfully set a PIN on a security key. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    PIN successfully set.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_ERROR" desc="A message shown when setting a PIN on a security key failed with an unhandled error code. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    PIN operation failed with code <ph name="RETRIES">$1<ex>18</ex></ph>.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_HARD_LOCK" desc="A message shown when the user attempts to change the PIN on a security key that has been locked due to too many incorrect PIN attempts. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    That security key is locked due to too many incorrect PIN attempts. It must be reset in order to perform any PIN-based operations.
+  </message>
+  <message name="IDS_SETTINGS_SECURITY_KEYS_PIN_SOFT_LOCK" desc="A message shown when the user attempts to change the PIN on a security key that has been locked due to too many incorrect PIN attempts. PINs, in this context, are short, often numeric codes that are often used with, for example, ATM cards. Security keys are external devices used to authenticate people.">
+    That security key is temporarily locked due to too many incorrect PIN attempts. Remove it and reinsert to unlock.
+  </message>
 </grit-part>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3b6177cc..96bd3dc 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -397,16 +397,6 @@
     "data_use_measurement/chrome_data_use_recorder.h",
     "data_use_measurement/data_use_web_contents_observer.cc",
     "data_use_measurement/data_use_web_contents_observer.h",
-    "data_use_measurement/page_load_capping/chrome_page_load_capping_features.cc",
-    "data_use_measurement/page_load_capping/chrome_page_load_capping_features.h",
-    "data_use_measurement/page_load_capping/page_load_capping_blacklist.cc",
-    "data_use_measurement/page_load_capping/page_load_capping_blacklist.h",
-    "data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.cc",
-    "data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h",
-    "data_use_measurement/page_load_capping/page_load_capping_service.cc",
-    "data_use_measurement/page_load_capping/page_load_capping_service.h",
-    "data_use_measurement/page_load_capping/page_load_capping_service_factory.cc",
-    "data_use_measurement/page_load_capping/page_load_capping_service_factory.h",
     "defaults.cc",
     "defaults.h",
     "dom_distiller/dom_distiller_service_factory.cc",
@@ -1009,8 +999,6 @@
     "page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h",
     "page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.cc",
     "page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.h",
-    "page_load_metrics/observers/page_capping_page_load_metrics_observer.cc",
-    "page_load_metrics/observers/page_capping_page_load_metrics_observer.h",
     "page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.cc",
     "page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.h",
     "page_load_metrics/observers/previews_page_load_metrics_observer.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 655c227..9d982c93 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -873,6 +873,16 @@
      security_state::features::
          kMarkHttpAsParameterWarningAndDangerousOnFormEdits}};
 
+// The "Enabled" state for this feature is "0" and representing setting A.
+const FeatureEntry::FeatureParam kTabHoverCardsSettingB[] = {
+    {features::kTabHoverCardsFeatureParameterName, "1"}};
+const FeatureEntry::FeatureParam kTabHoverCardsSettingC[] = {
+    {features::kTabHoverCardsFeatureParameterName, "2"}};
+
+const FeatureEntry::FeatureVariation kTabHoverCardsFeatureVariations[] = {
+    {"B", kTabHoverCardsSettingB, base::size(kTabHoverCardsSettingB), nullptr},
+    {"C", kTabHoverCardsSettingC, base::size(kTabHoverCardsSettingC), nullptr}};
+
 const FeatureEntry::FeatureVariation kMarkHttpAsFeatureVariations[] = {
     {"(mark as actively dangerous)", kMarkHttpAsDangerous,
      base::size(kMarkHttpAsDangerous), nullptr},
@@ -3120,7 +3130,9 @@
 
     {"tab-hover-cards", flag_descriptions::kTabHoverCardsName,
      flag_descriptions::kTabHoverCardsDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kTabHoverCards)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(features::kTabHoverCards,
+                                    kTabHoverCardsFeatureVariations,
+                                    "TabHoverCards")},
 
     {"tab-hover-card-images", flag_descriptions::kTabHoverCardImagesName,
      flag_descriptions::kTabHoverCardImagesDescription, kOsDesktop,
diff --git a/chrome/browser/android/background_sync_launcher_android.cc b/chrome/browser/android/background_sync_launcher_android.cc
index 929db326..8eaedf25 100644
--- a/chrome/browser/android/background_sync_launcher_android.cc
+++ b/chrome/browser/android/background_sync_launcher_android.cc
@@ -8,7 +8,6 @@
 
 #include "base/android/callback_android.h"
 #include "base/barrier_closure.h"
-#include "base/bind.h"
 #include "base/feature_list.h"
 #include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -53,10 +52,12 @@
 }
 
 // static
-void BackgroundSyncLauncherAndroid::LaunchBrowserIfStopped() {
+void BackgroundSyncLauncherAndroid::LaunchBrowserIfStopped(
+    bool launch_when_next_online,
+    int64_t min_delay_ms) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  Get()->LaunchBrowserIfStoppedImpl();
+  Get()->LaunchBrowserIfStoppedImpl(launch_when_next_online, min_delay_ms);
 }
 
 // static
@@ -75,36 +76,24 @@
       base::android::AttachCurrentThread());
 }
 
-void BackgroundSyncLauncherAndroid::LaunchBrowserIfStoppedImpl() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  auto* profile = ProfileManager::GetLastUsedProfile();
-  DCHECK(profile);
-
-  content::BackgroundSyncContext::GetSoonestWakeupDeltaAcrossPartitions(
-      profile, base::BindOnce(
-                   &BackgroundSyncLauncherAndroid::LaunchBrowserWithWakeupDelta,
-                   base::Unretained(this)));
-}
-
-void BackgroundSyncLauncherAndroid::LaunchBrowserWithWakeupDelta(
-    base::TimeDelta soonest_wakeup_delta) {
+void BackgroundSyncLauncherAndroid::LaunchBrowserIfStoppedImpl(
+    bool launch_when_next_online,
+    int64_t min_delay_ms) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   JNIEnv* env = base::android::AttachCurrentThread();
-  int64_t min_delay_ms = soonest_wakeup_delta.InMilliseconds();
 
   if (!base::FeatureList::IsEnabled(
           chrome::android::kBackgroundTaskSchedulerForBackgroundSync)) {
     Java_BackgroundSyncLauncher_launchBrowserIfStopped(
-        env, java_gcm_network_manager_launcher_,
-        /* shouldLaunch= */ soonest_wakeup_delta.is_max(), min_delay_ms);
+        env, java_gcm_network_manager_launcher_, launch_when_next_online,
+        min_delay_ms);
     return;
   }
 
   Java_BackgroundSyncBackgroundTaskScheduler_launchBrowserIfStopped(
       env, java_background_sync_background_task_scheduler_launcher_,
-      soonest_wakeup_delta.is_max(), min_delay_ms);
+      launch_when_next_online, min_delay_ms);
 }
 
 void BackgroundSyncLauncherAndroid::FireBackgroundSyncEvents(
@@ -114,10 +103,51 @@
   auto* profile = ProfileManager::GetLastUsedProfile();
   DCHECK(profile);
 
-  content::BackgroundSyncContext::FireBackgroundSyncEventsAcrossPartitions(
-      profile, j_runnable);
+  int num_partitions = 0;
+  content::BrowserContext::ForEachStoragePartition(
+      profile, base::BindRepeating(
+                   [](int* num_partitions,
+                      content::StoragePartition* storage_partition) {
+                     (*num_partitions)++;
+                   },
+                   &num_partitions));
+
+  // This class is a singleton, which is only destructed on program exit.
+  // Therefore, use of base::Unretained(this) is safe.
+  base::RepeatingClosure done_closure = base::BarrierClosure(
+      num_partitions,
+      base::BindOnce(base::android::RunRunnableAndroid,
+                     base::android::ScopedJavaGlobalRef<jobject>(j_runnable)));
+
+  content::BrowserContext::ForEachStoragePartition(
+      profile,
+      base::BindRepeating(&BackgroundSyncLauncherAndroid::
+                              FireBackgroundSyncEventsForStoragePartition,
+                          base::Unretained(this), done_closure));
 }
 
+void BackgroundSyncLauncherAndroid::FireBackgroundSyncEventsForStoragePartition(
+    base::OnceClosure done_closure,
+    content::StoragePartition* storage_partition) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  content::BackgroundSyncContext* sync_context =
+      storage_partition->GetBackgroundSyncContext();
+  if (!sync_context) {
+    std::move(done_closure).Run();
+    return;
+  }
+
+  sync_context->FireBackgroundSyncEventsForStoragePartition(
+      storage_partition, std::move(done_closure));
+}
+
+void BackgroundSyncLauncherAndroid::OnFiredBackgroundSyncEvents(
+    base::android::ScopedJavaGlobalRef<jobject> j_runnable) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  base::android::RunRunnableAndroid(j_runnable);
+}
 
 BackgroundSyncLauncherAndroid::BackgroundSyncLauncherAndroid() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/android/background_sync_launcher_android.h b/chrome/browser/android/background_sync_launcher_android.h
index 25cfec2..1afb9ba 100644
--- a/chrome/browser/android/background_sync_launcher_android.h
+++ b/chrome/browser/android/background_sync_launcher_android.h
@@ -13,7 +13,10 @@
 #include "base/callback_forward.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
-#include "base/time/time.h"
+
+namespace content {
+class StoragePartition;
+}  // namespace content
 
 // The BackgroundSyncLauncherAndroid singleton owns the Java
 // BackgroundSyncLauncher object and is used to register interest in starting
@@ -23,12 +26,8 @@
  public:
   static BackgroundSyncLauncherAndroid* Get();
 
-  // Calculates the soonest wakeup time across all the storage
-  // partitions for the non-incognito profile and ensures that the browser
-  // is running when the device next goes online after that time has passed.
-  // If this time is set to base::TimeDelta::Max() across all storage
-  // partitions, the wake-up task is cancelled.
-  static void LaunchBrowserIfStopped();
+  static void LaunchBrowserIfStopped(bool launch_when_next_online,
+                                     int64_t min_delay_ms);
 
   static bool ShouldDisableBackgroundSync();
 
@@ -48,8 +47,13 @@
   BackgroundSyncLauncherAndroid();
   ~BackgroundSyncLauncherAndroid();
 
-  void LaunchBrowserIfStoppedImpl();
-  void LaunchBrowserWithWakeupDelta(base::TimeDelta soonest_wakeup_delta);
+  void LaunchBrowserIfStoppedImpl(bool launch_when_next_online,
+                                  int64_t min_delay_ms);
+  void FireBackgroundSyncEventsForStoragePartition(
+      base::OnceClosure done_closure,
+      content::StoragePartition* storage_partition);
+  void OnFiredBackgroundSyncEvents(
+      base::android::ScopedJavaGlobalRef<jobject> j_runnable);
 
   base::android::ScopedJavaGlobalRef<jobject>
       java_gcm_network_manager_launcher_;
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 5758d5b..0d2972b 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -137,7 +137,6 @@
     &kHomepageTile,
     &kHorizontalTabSwitcherAndroid,
     &kImprovedA2HS,
-    &kInflateToolbarOnBackgroundThread,
     &kInlineUpdateFlow,
     &kIntentBlockExternalFormRedirectsNoGesture,
     &kJellyBeanSupported,
@@ -393,9 +392,6 @@
 const base::Feature kImprovedA2HS{"ImprovedA2HS",
                                   base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kInflateToolbarOnBackgroundThread{
-    "BackgroundToolbarInflation", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kInlineUpdateFlow{"InlineUpdateFlow",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 8c80f9e..0a8cc45 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -67,7 +67,6 @@
 extern const base::Feature kHomepageTile;
 extern const base::Feature kHorizontalTabSwitcherAndroid;
 extern const base::Feature kImprovedA2HS;
-extern const base::Feature kInflateToolbarOnBackgroundThread;
 extern const base::Feature kInlineUpdateFlow;
 extern const base::Feature kIntentBlockExternalFormRedirectsNoGesture;
 extern const base::Feature kJellyBeanSupported;
diff --git a/chrome/browser/android/cookies/cookies_fetcher_util.cc b/chrome/browser/android/cookies/cookies_fetcher_util.cc
index e018240..6267b0c 100644
--- a/chrome/browser/android/cookies/cookies_fetcher_util.cc
+++ b/chrome/browser/android/cookies/cookies_fetcher_util.cc
@@ -110,7 +110,13 @@
 
   // Assume HTTPS - since the cookies are being restored from another store,
   // they have already gone through the strict secure check.
+  //
+  // Similarly, permit samesite cookies to be imported.
+  net::CookieOptions options;
+  options.set_include_httponly();
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   GetCookieServiceClient()->SetCanonicalCookie(
-      *cookie, "https", true /* modify_http_only */,
+      *cookie, "https", options,
       network::mojom::CookieManager::SetCanonicalCookieCallback());
 }
diff --git a/chrome/browser/android/usage_stats/usage_stats_database.cc b/chrome/browser/android/usage_stats/usage_stats_database.cc
index c565894..8f099679 100644
--- a/chrome/browser/android/usage_stats/usage_stats_database.cc
+++ b/chrome/browser/android/usage_stats/usage_stats_database.cc
@@ -22,6 +22,9 @@
 using leveldb_proto::ProtoDatabaseProviderFactory;
 
 const char kNamespace[] = "UsageStats";
+const char kEventsDbName[] = "Events";
+const char kSuspensionsDbName[] = "Suspensions";
+const char kTokensDbName[] = "Tokens";
 
 const char kKeySeparator[] = "_";
 
@@ -45,16 +48,16 @@
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
 
   website_event_db_ = db_provider->GetDB<WebsiteEvent>(
-      leveldb_proto::ProtoDbType::USAGE_STATS_WEBSITE_EVENT, usage_stats_dir,
-      db_task_runner);
+      leveldb_proto::ProtoDbType::USAGE_STATS_WEBSITE_EVENT,
+      usage_stats_dir.Append(kEventsDbName), db_task_runner);
 
   suspension_db_ = db_provider->GetDB<Suspension>(
-      leveldb_proto::ProtoDbType::USAGE_STATS_SUSPENSION, usage_stats_dir,
-      db_task_runner);
+      leveldb_proto::ProtoDbType::USAGE_STATS_SUSPENSION,
+      usage_stats_dir.Append(kSuspensionsDbName), db_task_runner);
 
   token_mapping_db_ = db_provider->GetDB<TokenMapping>(
-      leveldb_proto::ProtoDbType::USAGE_STATS_TOKEN_MAPPING, usage_stats_dir,
-      db_task_runner);
+      leveldb_proto::ProtoDbType::USAGE_STATS_TOKEN_MAPPING,
+      usage_stats_dir.Append(kTokensDbName), db_task_runner);
 
   InitializeDBs();
 }
@@ -110,16 +113,15 @@
 void UsageStatsDatabase::InitializeDBs() {
   // Asynchronously initialize databases.
   website_event_db_->Init(
-      kNamespace, base::BindOnce(&UsageStatsDatabase::OnWebsiteEventInitDone,
-                                 weak_ptr_factory_.GetWeakPtr(), true));
+      base::BindOnce(&UsageStatsDatabase::OnWebsiteEventInitDone,
+                     weak_ptr_factory_.GetWeakPtr(), true));
 
-  suspension_db_->Init(kNamespace,
-                       base::BindOnce(&UsageStatsDatabase::OnSuspensionInitDone,
+  suspension_db_->Init(base::BindOnce(&UsageStatsDatabase::OnSuspensionInitDone,
                                       weak_ptr_factory_.GetWeakPtr(), true));
 
   token_mapping_db_->Init(
-      kNamespace, base::BindOnce(&UsageStatsDatabase::OnTokenMappingInitDone,
-                                 weak_ptr_factory_.GetWeakPtr(), true));
+      base::BindOnce(&UsageStatsDatabase::OnTokenMappingInitDone,
+                     weak_ptr_factory_.GetWeakPtr(), true));
 }
 
 void UsageStatsDatabase::GetAllEvents(EventsCallback callback) {
@@ -355,7 +357,6 @@
     if (retry) {
       // Retry unsuccessful initialization.
       website_event_db_->Init(
-          kNamespace,
           base::BindOnce(&UsageStatsDatabase::OnWebsiteEventInitDone,
                          weak_ptr_factory_.GetWeakPtr(), false));
     }
@@ -378,8 +379,8 @@
     if (retry) {
       // Retry unsuccessful initialization.
       suspension_db_->Init(
-          kNamespace, base::BindOnce(&UsageStatsDatabase::OnSuspensionInitDone,
-                                     weak_ptr_factory_.GetWeakPtr(), false));
+          base::BindOnce(&UsageStatsDatabase::OnSuspensionInitDone,
+                         weak_ptr_factory_.GetWeakPtr(), false));
     }
     return;
   }
@@ -401,7 +402,6 @@
     if (retry) {
       // Retry unsuccessful initialization.
       token_mapping_db_->Init(
-          kNamespace,
           base::BindOnce(&UsageStatsDatabase::OnTokenMappingInitDone,
                          weak_ptr_factory_.GetWeakPtr(), false));
     }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
index eeb1323f..0036d66 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -160,11 +160,17 @@
   DCHECK(IsOnGlThread());
   DCHECK(is_initialized_);
 
+  CloseBindingsIfOpen();
+
   mojom::XRFrameDataProviderPtrInfo frame_data_provider_info;
   frame_data_binding_.Bind(mojo::MakeRequest(&frame_data_provider_info));
+  frame_data_binding_.set_connection_error_handler(base::BindOnce(
+      &ArCoreGl::OnBindingDisconnect, weak_ptr_factory_.GetWeakPtr()));
 
   mojom::XRSessionControllerPtrInfo controller_info;
   session_controller_binding_.Bind(mojo::MakeRequest(&controller_info));
+  session_controller_binding_.set_connection_error_handler(base::BindOnce(
+      &ArCoreGl::OnBindingDisconnect, weak_ptr_factory_.GetWeakPtr()));
 
   std::move(callback).Run(std::move(frame_data_provider_info),
                           std::move(display_info), std::move(controller_info),
@@ -318,6 +324,8 @@
   DCHECK(is_initialized_);
 
   environment_binding_.Bind(std::move(environment_request));
+  environment_binding_.set_connection_error_handler(base::BindOnce(
+      &ArCoreGl::OnBindingDisconnect, weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ArCoreGl::UpdateSessionGeometry(
@@ -421,6 +429,20 @@
   arcore_->Resume();
 }
 
+void ArCoreGl::OnBindingDisconnect() {
+  DVLOG(3) << __func__;
+
+  CloseBindingsIfOpen();
+}
+
+void ArCoreGl::CloseBindingsIfOpen() {
+  DVLOG(3) << __func__;
+
+  environment_binding_.Close();
+  frame_data_binding_.Close();
+  session_controller_binding_.Close();
+}
+
 bool ArCoreGl::IsOnGlThread() const {
   return gl_thread_task_runner_->BelongsToCurrentThread();
 }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h
index 3d2f13a..be502556 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.h
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -131,6 +131,9 @@
   mojo::AssociatedBinding<mojom::XREnvironmentIntegrationProvider>
       environment_binding_;
 
+  void OnBindingDisconnect();
+  void CloseBindingsIfOpen();
+
   // Must be last.
   base::WeakPtrFactory<ArCoreGl> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(ArCoreGl);
diff --git a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
index 300b740..5970e29a 100644
--- a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
+++ b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.cc b/chrome/browser/background_sync/background_sync_controller_impl.cc
index f73f95e2..40c86396 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.cc
+++ b/chrome/browser/background_sync/background_sync_controller_impl.cc
@@ -114,13 +114,17 @@
                                           origin.GetURL());
 }
 
-void BackgroundSyncControllerImpl::RunInBackground() {
+void BackgroundSyncControllerImpl::RunInBackground(bool enabled,
+                                                   int64_t min_ms) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (profile_->IsOffTheRecord())
     return;
 #if defined(OS_ANDROID)
-  BackgroundSyncLauncherAndroid::LaunchBrowserIfStopped();
+  BackgroundSyncLauncherAndroid::LaunchBrowserIfStopped(enabled, min_ms);
+#else
+// TODO(jkarlin): Use BackgroundModeManager to enter background mode. See
+// https://crbug.com/484201.
 #endif
 }
 
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.h b/chrome/browser/background_sync/background_sync_controller_impl.h
index e5739a39..6446b77 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl.h
+++ b/chrome/browser/background_sync/background_sync_controller_impl.h
@@ -45,7 +45,7 @@
   void GetParameterOverrides(
       content::BackgroundSyncParameters* parameters) const override;
   void NotifyBackgroundSyncRegistered(const url::Origin& origin) override;
-  void RunInBackground() override;
+  void RunInBackground(bool enabled, int64_t min_ms) override;
 
  protected:
   // Virtual for testing.
diff --git a/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc b/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc
index fafbb23..5217d51 100644
--- a/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc
+++ b/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc
@@ -48,8 +48,9 @@
  protected:
   BackgroundSyncControllerImplTest()
       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        controller_(
-            new TestBackgroundSyncControllerImpl(&profile_, &rappor_service_)) {
+        controller_(std::make_unique<TestBackgroundSyncControllerImpl>(
+            &profile_,
+            &rappor_service_)) {
     ResetFieldTrialList();
 #if defined(OS_ANDROID)
     BackgroundSyncLauncherAndroid::SetPlayServicesVersionCheckDisabledForTests(
@@ -58,8 +59,8 @@
   }
 
   void ResetFieldTrialList() {
-    field_trial_list_.reset(
-        new base::FieldTrialList(nullptr /* entropy provider */));
+    field_trial_list_ =
+        std::make_unique<base::FieldTrialList>(nullptr /* entropy provider */);
     variations::testing::ClearAllVariationParams();
     base::FieldTrialList::CreateFieldTrial(
         BackgroundSyncControllerImpl::kFieldTrialName, kFieldTrialGroup);
diff --git a/chrome/browser/browser_features.cc b/chrome/browser/browser_features.cc
index 2d45c23..965dc634 100644
--- a/chrome/browser/browser_features.cc
+++ b/chrome/browser/browser_features.cc
@@ -33,6 +33,9 @@
 // https://crbug.com/910739
 const base::Feature kTabHoverCards{"TabHoverCards",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
+// Parameter name used for tab hover cards user study.
+// TODO(corising): Removed this after tab hover cards user study.
+const char kTabHoverCardsFeatureParameterName[] = "setting";
 
 // Enables preview images in hover cards. See kTabHoverCards.
 // https://crbug.com/928954
diff --git a/chrome/browser/browser_features.h b/chrome/browser/browser_features.h
index f644b477e6..c46e261 100644
--- a/chrome/browser/browser_features.h
+++ b/chrome/browser/browser_features.h
@@ -27,6 +27,7 @@
 extern const base::Feature kTabGroups;
 
 extern const base::Feature kTabHoverCards;
+extern const char kTabHoverCardsFeatureParameterName[];
 
 extern const base::Feature kTabHoverCardImages;
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 726befb2..af3abeb 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -550,11 +550,10 @@
           </else>
         </if>
         <include name="IDR_CERT_MANAGER_DIALOG_HTML" file="resources\chromeos\certificate_manager_dialog.html" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_SLOW_HTML" file="resources\chromeos\slow.html" flattenhtml="true" type="BINDATA" />
-        <include name="IDR_SLOW_JS" file="resources\chromeos\slow.js" type="BINDATA" />
+        <include name="IDR_SLOW_CSS" file="resources\chromeos\slow.css" type="BINDATA" compress="gzip" />
+        <include name="IDR_SLOW_HTML" file="resources\chromeos\slow.html" type="BINDATA" compress="gzip" />
+        <include name="IDR_SLOW_JS" file="resources\chromeos\slow.js" type="BINDATA" compress="gzip" />
         <include name="IDR_HATS_HTML" file="resources\chromeos\hats\hats.html" flattenhtml="false" type="BINDATA" />
-      </if>
-      <if expr="chromeos">
         <include name="IDR_DEMO_APP_MANIFEST" file="resources\chromeos\demo_app\manifest.json" type="BINDATA" />
         <include name="IDR_WALLPAPERMANAGER_MANIFEST" file="resources\chromeos\wallpaper_manager\manifest.json" type="BINDATA" />
         <include name="IDR_FIRST_RUN_DIALOG_MANIFEST" file="resources\chromeos\first_run\app/manifest.json" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
index 5a311f62..de250a50 100644
--- a/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
@@ -111,35 +111,35 @@
   }
 
   void CreateCookiesForTest() {
-    auto cookie1 =
-        net::CanonicalCookie::Create(GURL("https://www.google.com"), "A=1",
-                                     base::Time::Now(), net::CookieOptions());
-    auto cookie2 = net::CanonicalCookie::Create(
-        GURL("https://www.gmail.google.com"), "B=1", base::Time::Now(),
-        net::CookieOptions());
+    net::CookieOptions options;
+    auto cookie1 = net::CanonicalCookie::Create(
+        GURL("https://www.google.com"), "A=1", base::Time::Now(), options);
+    auto cookie2 =
+        net::CanonicalCookie::Create(GURL("https://www.gmail.google.com"),
+                                     "B=1", base::Time::Now(), options);
 
     network::mojom::CookieManager* cookie_manager =
         storage_partition()->GetCookieManagerForBrowserProcess();
-    cookie_manager->SetCanonicalCookie(
-        *cookie1, "https", false /* modify_http_only */, base::DoNothing());
-    cookie_manager->SetCanonicalCookie(
-        *cookie2, "https", false /* modify_http_only */, base::DoNothing());
+    cookie_manager->SetCanonicalCookie(*cookie1, "https", options,
+                                       base::DoNothing());
+    cookie_manager->SetCanonicalCookie(*cookie2, "https", options,
+                                       base::DoNothing());
   }
 
   void CreateCookiesForDomainCookieTest() {
-    auto cookie1 =
-        net::CanonicalCookie::Create(GURL("https://www.google.com"), "A=1",
-                                     base::Time::Now(), net::CookieOptions());
-    auto cookie2 = net::CanonicalCookie::Create(
-        GURL("https://www.google.com"), "A=2; Domain=.www.google.com ",
-        base::Time::Now(), net::CookieOptions());
+    net::CookieOptions options;
+    auto cookie1 = net::CanonicalCookie::Create(
+        GURL("https://www.google.com"), "A=1", base::Time::Now(), options);
+    auto cookie2 = net::CanonicalCookie::Create(GURL("https://www.google.com"),
+                                                "A=2; Domain=.www.google.com ",
+                                                base::Time::Now(), options);
 
     network::mojom::CookieManager* cookie_manager =
         storage_partition()->GetCookieManagerForBrowserProcess();
-    cookie_manager->SetCanonicalCookie(
-        *cookie1, "https", false /* modify_http_only */, base::DoNothing());
-    cookie_manager->SetCanonicalCookie(
-        *cookie2, "https", false /* modify_http_only */, base::DoNothing());
+    cookie_manager->SetCanonicalCookie(*cookie1, "https", options,
+                                       base::DoNothing());
+    cookie_manager->SetCanonicalCookie(*cookie2, "https", options,
+                                       base::DoNothing());
   }
 
   void FetchCallback(const net::CookieList& cookies) {
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
index 664d37e..682536b 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -282,7 +282,9 @@
   network::mojom::CookieManager* cookie_manager =
       content::BrowserContext::GetDefaultStoragePartition(profile)
           ->GetCookieManagerForBrowserProcess();
-  cookie_manager->SetCanonicalCookie(cookie, "https", true,
+  net::CookieOptions options;
+  options.set_include_httponly();
+  cookie_manager->SetCanonicalCookie(cookie, "https", options,
                                      std::move(callback));
   loop.Run();
   return success;
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 75633bcd..341ecdd 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -34,9 +34,6 @@
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.h"
 #include "chrome/browser/domain_reliability/service_factory.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
@@ -561,14 +558,6 @@
     if (previews_service)
       previews_service->ClearBlackList(delete_begin_, delete_end_);
 
-    // |previews_service| is null if |profile_| is off the record.
-    PageLoadCappingService* page_load_capping_service =
-        PageLoadCappingServiceFactory::GetForBrowserContext(profile_);
-    if (page_load_capping_service &&
-        page_load_capping_service->page_load_capping_blacklist()) {
-      page_load_capping_service->page_load_capping_blacklist()->ClearBlackList(
-          delete_begin_, delete_end_);
-    }
 
 #if defined(OS_ANDROID)
     OomInterventionDecider* oom_intervention_decider =
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 7b26235..d8458a8d 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -280,11 +280,11 @@
 
   void AddCookie() {
     base::RunLoop run_loop;
-    auto cookie = net::CanonicalCookie::Create(
-        kOrigin1, "A=1", base::Time::Now(), net::CookieOptions());
+    net::CookieOptions options;
+    auto cookie = net::CanonicalCookie::Create(kOrigin1, "A=1",
+                                               base::Time::Now(), options);
     cookie_manager_->SetCanonicalCookie(
-        *cookie, "http", /*modify_http_only=*/false,
-        base::BindLambdaForTesting([&](bool result) {
+        *cookie, "http", options, base::BindLambdaForTesting([&](bool result) {
           EXPECT_TRUE(result);
           run_loop.Quit();
         }));
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
index 6b3e8b0..4e22479 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper_unittest.cc
@@ -56,8 +56,10 @@
               url, "name", "A=1", url.host(), url.path(), time, base::Time(),
               time, url.SchemeIsCryptographic(), false,
               net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT);
+      net::CookieOptions options;
+      options.set_include_httponly();
       cookie_manager->SetCanonicalCookie(
-          *cookie, url.scheme(), true /*modify_http_only*/,
+          *cookie, url.scheme(), options,
           base::BindLambdaForTesting([&](bool result) {
             if (--tasks == 0)
               run_loop.Quit();
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 8847e02..cc016c9 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4998,12 +4998,6 @@
   return {user_data_dir, cache_dir};
 }
 
-#if defined(OS_ANDROID)
-bool ChromeContentBrowserClient::NeedURLRequestContext() {
-  return false;
-}
-#endif
-
 bool ChromeContentBrowserClient::AllowRenderingMhtmlOverHttp(
     content::NavigationUIData* navigation_ui_data) {
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 3bfa5c5..977c8cf 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -494,9 +494,6 @@
       bool in_memory,
       const base::FilePath& relative_partition_path) override;
   std::vector<base::FilePath> GetNetworkContextsParentDirectory() override;
-#if defined(OS_ANDROID)
-  bool NeedURLRequestContext() override;
-#endif
   bool AllowRenderingMhtmlOverHttp(
       content::NavigationUIData* navigation_ui_data) override;
   bool ShouldForceDownloadResource(const GURL& url,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 5b79d7a..6f2ebe88 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -96,6 +96,7 @@
     "//chromeos/dbus:oobe_config_proto",
     "//chromeos/dbus:plugin_vm_service_proto",
     "//chromeos/dbus/constants",
+    "//chromeos/dbus/kerberos",
     "//chromeos/dbus/services:services",
     "//chromeos/dbus/system_clock",
     "//chromeos/disks",
diff --git a/chrome/browser/chromeos/OWNERS b/chrome/browser/chromeos/OWNERS
index 903e60a..808c3cf 100644
--- a/chrome/browser/chromeos/OWNERS
+++ b/chrome/browser/chromeos/OWNERS
@@ -13,3 +13,4 @@
 xiyuan@chromium.org
 per-file *active_directory*=rsorokin@chromium.org
 per-file *active_directory*=ljusten@chromium.org
+per-file tpm_firmware_update*=mnissler@chromium.org
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
index 044c8c0e..fcd4605 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
@@ -79,6 +79,9 @@
   PA_LOG(VERBOSE) << "AndroidSmsAppSetupControllerImpl::SetUpApp(): Setting "
                   << "DefaultToPersist cookie at " << app_url << " before PWA "
                   << "installation.";
+  net::CookieOptions options;
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   pwa_delegate_->GetCookieManager(app_url, profile_)
       ->SetCanonicalCookie(
           *net::CanonicalCookie::CreateSanitizedCookie(
@@ -89,7 +92,7 @@
               base::Time::Now() /* last_access_time */,
               !net::IsLocalhost(app_url) /* secure */, false /* http_only */,
               net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT),
-          "https", false /* modify_http_only */,
+          "https", options,
           base::BindOnce(&AndroidSmsAppSetupControllerImpl::
                              OnSetRememberDeviceByDefaultCookieResult,
                          weak_ptr_factory_.GetWeakPtr(), app_url, install_url,
@@ -266,6 +269,9 @@
   // The client checks for this cookie to redirect users to the new domain. This
   // prevents unwanted connection stealing between old and new clients should
   // the user try to open old client.
+  net::CookieOptions options;
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   pwa_delegate_->GetCookieManager(app_url, profile_)
       ->SetCanonicalCookie(
           *net::CanonicalCookie::CreateSanitizedCookie(
@@ -276,7 +282,7 @@
               base::Time::Now() /* last_access_time */,
               !net::IsLocalhost(app_url) /* secure */, false /* http_only */,
               net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT),
-          "https", false /* modify_http_only */,
+          "https", options,
           base::BindOnce(
               &AndroidSmsAppSetupControllerImpl::OnSetMigrationCookieResult,
               weak_ptr_factory_.GetWeakPtr(), app_url, std::move(callback)));
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
index e92ecc0d..7eddcc6 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
@@ -63,6 +63,7 @@
       const std::string& expected_cookie_value,
       const std::string& expected_source_scheme,
       bool expected_modify_http_only,
+      net::CookieOptions::SameSiteCookieContext expect_same_site_context,
       bool success) {
     ASSERT_FALSE(set_canonical_cookie_calls_.empty());
     auto params = std::move(set_canonical_cookie_calls_.front());
@@ -71,7 +72,10 @@
     EXPECT_EQ(expected_cookie_name, std::get<0>(params).Name());
     EXPECT_EQ(expected_cookie_value, std::get<0>(params).Value());
     EXPECT_EQ(expected_source_scheme, std::get<1>(params));
-    EXPECT_EQ(expected_modify_http_only, std::get<2>(params));
+    EXPECT_EQ(expected_modify_http_only,
+              !std::get<2>(params).exclude_httponly());
+    EXPECT_EQ(expect_same_site_context,
+              std::get<2>(params).same_site_cookie_context());
 
     std::move(std::get<3>(params)).Run(success);
   }
@@ -93,10 +97,10 @@
   // network::mojom::CookieManager
   void SetCanonicalCookie(const net::CanonicalCookie& cookie,
                           const std::string& source_scheme,
-                          bool modify_http_only,
+                          const net::CookieOptions& options,
                           SetCanonicalCookieCallback callback) override {
-    set_canonical_cookie_calls_.emplace_back(
-        cookie, source_scheme, modify_http_only, std::move(callback));
+    set_canonical_cookie_calls_.emplace_back(cookie, source_scheme, options,
+                                             std::move(callback));
   }
 
   void DeleteCookies(network::mojom::CookieDeletionFilterPtr filter,
@@ -107,7 +111,7 @@
  private:
   std::vector<std::tuple<net::CanonicalCookie,
                          std::string,
-                         bool,
+                         net::CookieOptions,
                          SetCanonicalCookieCallback>>
       set_canonical_cookie_calls_;
   std::vector<
@@ -210,7 +214,9 @@
         "default_to_persist" /* expected_cookie_name */,
         "true" /* expected_cookie_value */,
         "https" /* expected_source_scheme */,
-        false /* expected_modify_http_only */, true /* success */);
+        false /* expected_modify_http_only */,
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
+        true /* success */);
 
     fake_cookie_manager_->InvokePendingDeleteCookiesCallback(
         app_url, "cros_migrated_to" /* expected_cookie_name */,
@@ -282,7 +288,9 @@
           "cros_migrated_to" /* expected_cookie_name */,
           migrated_to_app_url.GetContent() /* expected_cookie_value */,
           "https" /* expected_source_scheme */,
-          false /* expected_modify_http_only */, true /* success */);
+          false /* expected_modify_http_only */,
+          net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
+          true /* success */);
 
       fake_cookie_manager_->InvokePendingDeleteCookiesCallback(
           app_url, "default_to_persist" /* expected_cookie_name */,
diff --git a/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc
index 05c3accf1..a883586 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc
@@ -25,7 +25,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "extensions/common/value_builder.h"
 #include "extensions/test/extension_test_message_listener.h"
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
index 3609ba1..5b3c3044 100644
--- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
@@ -20,7 +20,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_session_runner.h"
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 980e291..4e7c1ad 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -38,7 +38,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_data_remover.h"
 #include "components/arc/arc_features.h"
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index 3c6e427..17b51d1 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -14,7 +14,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/policy/android_management_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_stop_reason.h"
 
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
index 0c1a65a..014eeb1 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
@@ -41,8 +41,8 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/power/power_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_features.h"
diff --git a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
index 897478a5..24cdfc3 100644
--- a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
+++ b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/arc/arc_prefs.h"
diff --git a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
index bce6ceb..c74c8933 100644
--- a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
index fea7cc1a..0bc6b77 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
@@ -278,13 +278,14 @@
 void SelectFileDialogScriptExecutor::ExecuteJavaScript(
     const std::string& script,
     content::RenderFrameHost::JavaScriptResultCallback callback) {
-  content::RenderFrameHost* frame_host =
+  content::RenderViewHost* view_host =
       static_cast<SelectFileDialogExtension*>(select_file_dialog_)
-          ->GetRenderViewHost()
-          ->GetMainFrame();
+          ->GetRenderViewHost();
+  content::RenderFrameHost* frame_host =
+      view_host ? view_host->GetMainFrame() : nullptr;
 
   if (!frame_host) {
-    LOG(ERROR) << "Failed to get RenderFrameHost of SelectFileDialogExtension";
+    LOG(ERROR) << "Can't execute a script. SelectFileDialog is not ready.";
     if (callback)
       std::move(callback).Run(base::Value());
     return;
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
index 86a20dc7..6ea7f2e 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
@@ -25,7 +25,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 967c4a5aa..d12bce7 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -135,7 +135,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "chromeos/dbus/services/cros_dbus_service.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/util/version_loader.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "chromeos/login/auth/login_event_recorder.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path.cc b/chrome/browser/chromeos/crostini/crostini_share_path.cc
index 1e60135d..99622b2 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path.cc
+++ b/chrome/browser/chromeos/crostini/crostini_share_path.cc
@@ -43,13 +43,13 @@
 
 void OnVmRestartedForSeneschal(
     Profile* profile,
-    std::string vm_name,
+    const std::string& vm_name,
     crostini::CrostiniSharePath::SharePathCallback callback,
     vm_tools::seneschal::SharePathRequest request,
     crostini::CrostiniResult result) {
   auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile);
   base::Optional<crostini::VmInfo> vm_info =
-      crostini_manager->GetVmInfo(std::move(vm_name));
+      crostini_manager->GetVmInfo(vm_name);
   if (!vm_info || vm_info->state != crostini::VmState::STARTED) {
     std::move(callback).Run(base::FilePath(), false, "VM could not be started");
     return;
@@ -129,8 +129,9 @@
 CrostiniSharePath::CrostiniSharePath(Profile* profile)
     : profile_(profile),
       mount_event_seneschal_callback_(base::BindRepeating(LogErrorResult)) {
-  if (auto* vmgr = file_manager::VolumeManager::Get(profile_))
+  if (auto* vmgr = file_manager::VolumeManager::Get(profile_)) {
     vmgr->AddObserver(this);
+  }
 }
 
 CrostiniSharePath::~CrostiniSharePath() {}
@@ -139,7 +140,7 @@
   observers_.AddObserver(obs);
 }
 
-void CrostiniSharePath::CallSeneschalSharePath(std::string vm_name,
+void CrostiniSharePath::CallSeneschalSharePath(const std::string& vm_name,
                                                const base::FilePath& path,
                                                bool persist,
                                                SharePathCallback callback) {
@@ -259,7 +260,7 @@
   if (!vm_info || vm_info->state != crostini::VmState::STARTED) {
     crostini_manager->RestartCrostini(
         vm_name, crostini::kCrostiniDefaultContainerName,
-        base::BindOnce(&OnVmRestartedForSeneschal, profile_, std::move(vm_name),
+        base::BindOnce(&OnVmRestartedForSeneschal, profile_, vm_name,
                        std::move(callback), std::move(request)));
     return;
   }
@@ -271,13 +272,13 @@
 }
 
 void CrostiniSharePath::CallSeneschalUnsharePath(
-    std::string vm_name,
+    const std::string& vm_name,
     const base::FilePath& path,
     base::OnceCallback<void(bool, std::string)> callback) {
   // Return success if VM is not currently running.
   auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_);
   base::Optional<crostini::VmInfo> vm_info =
-      crostini_manager->GetVmInfo(std::move(vm_name));
+      crostini_manager->GetVmInfo(vm_name);
   if (!vm_info || vm_info->state != crostini::VmState::STARTED) {
     std::move(callback).Run(true, "VM not running");
     return;
@@ -312,17 +313,16 @@
       base::BindOnce(&OnSeneschalUnsharePathResponse, std::move(callback)));
 }
 
-void CrostiniSharePath::SharePath(std::string vm_name,
+void CrostiniSharePath::SharePath(const std::string& vm_name,
                                   const base::FilePath& path,
                                   bool persist,
                                   SharePathCallback callback) {
   DCHECK(callback);
-  CallSeneschalSharePath(std::move(vm_name), path, persist,
-                         std::move(callback));
+  CallSeneschalSharePath(vm_name, path, persist, std::move(callback));
 }
 
 void CrostiniSharePath::SharePaths(
-    std::string vm_name,
+    const std::string& vm_name,
     std::vector<base::FilePath> paths,
     bool persist,
     base::OnceCallback<void(bool, std::string)> callback) {
@@ -338,15 +338,16 @@
 }
 
 void CrostiniSharePath::UnsharePath(
-    std::string vm_name,
+    const std::string& vm_name,
     const base::FilePath& path,
     base::OnceCallback<void(bool, std::string)> callback) {
   PrefService* pref_service = profile_->GetPrefs();
   ListPrefUpdate update(pref_service, crostini::prefs::kCrostiniSharedPaths);
   base::ListValue* shared_paths = update.Get();
-  if (!shared_paths->Remove(base::Value(path.value()), nullptr))
+  if (!shared_paths->Remove(base::Value(path.value()), nullptr)) {
     LOG(WARNING) << "Unshared path not in prefs: " << path.value();
-  CallSeneschalUnsharePath(std::move(vm_name), path, std::move(callback));
+  }
+  CallSeneschalUnsharePath(vm_name, path, std::move(callback));
   for (Observer& observer : observers_) {
     observer.OnUnshare(path);
   }
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path.h b/chrome/browser/chromeos/crostini/crostini_share_path.h
index 2599f0c9..5f0d7c04 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path.h
+++ b/chrome/browser/chromeos/crostini/crostini_share_path.h
@@ -47,7 +47,7 @@
   // Share specified absolute |path| with vm. If |persist| is set, the path will
   // be automatically shared at container startup. Callback receives path mapped
   // in container, success bool and failure reason string.
-  void SharePath(std::string vm_name,
+  void SharePath(const std::string& vm_name,
                  const base::FilePath& path,
                  bool persist,
                  SharePathCallback callback);
@@ -55,14 +55,14 @@
   // Share specified absolute |paths| with vm. If |persist| is set, the paths
   // will be automatically shared at container startup. Callback receives
   // success bool and failure reason string of the first error.
-  void SharePaths(std::string vm_name,
+  void SharePaths(const std::string& vm_name,
                   std::vector<base::FilePath> paths,
                   bool persist,
                   base::OnceCallback<void(bool, std::string)> callback);
 
   // Unshare specified |path| with vm.
   // Callback receives success bool and failure reason string.
-  void UnsharePath(std::string vm_name,
+  void UnsharePath(const std::string& vm_name,
                    const base::FilePath& path,
                    base::OnceCallback<void(bool, std::string)> callback);
 
@@ -87,19 +87,19 @@
                          const file_manager::Volume& volume) override;
 
   // Allow seneschal callback for mount events to be overridden for testing.
-  void SetMountEventSeneschalCallbackForTesting(
+  void set_mount_event_seneschal_callback_for_testing(
       MountEventSeneschalCallback callback) {
     mount_event_seneschal_callback_ = std::move(callback);
   }
 
  private:
-  void CallSeneschalSharePath(std::string vm_name,
+  void CallSeneschalSharePath(const std::string& vm_name,
                               const base::FilePath& path,
                               bool persist,
                               SharePathCallback callback);
 
   void CallSeneschalUnsharePath(
-      std::string vm_name,
+      const std::string& vm_name,
       const base::FilePath& path,
       base::OnceCallback<void(bool, std::string)> callback);
 
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc b/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
index 26d5bab..ff8415f3 100644
--- a/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_share_path_unittest.cc
@@ -765,7 +765,7 @@
   SetUpVolume();
   CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
       kCrostiniDefaultVmName);
-  crostini_share_path_->SetMountEventSeneschalCallbackForTesting(
+  crostini_share_path_->set_mount_event_seneschal_callback_for_testing(
       base::BindRepeating(&CrostiniSharePathTest::MountEventSharePathCallback,
                           base::Unretained(this), "share-on-mount",
                           shared_path_, Persist::NO, SeneschalClientCalled::YES,
@@ -783,7 +783,7 @@
       kCrostiniDefaultVmName);
   auto volume_shared_path =
       file_manager::Volume::CreateForDownloads(shared_path_);
-  crostini_share_path_->SetMountEventSeneschalCallbackForTesting(
+  crostini_share_path_->set_mount_event_seneschal_callback_for_testing(
       base::BindRepeating(&CrostiniSharePathTest::MountEventSharePathCallback,
                           base::Unretained(this), "share-on-mount",
                           shared_path_, Persist::NO, SeneschalClientCalled::YES,
@@ -829,7 +829,7 @@
   SetUpVolume();
   CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
       kCrostiniDefaultVmName);
-  crostini_share_path_->SetMountEventSeneschalCallbackForTesting(
+  crostini_share_path_->set_mount_event_seneschal_callback_for_testing(
       base::BindRepeating(&CrostiniSharePathTest::MountEventUnsharePathCallback,
                           base::Unretained(this), "unshare-on-unmount",
                           shared_path_, Persist::YES,
@@ -847,7 +847,7 @@
       kCrostiniDefaultVmName);
   auto volume_shared_path =
       file_manager::Volume::CreateForDownloads(shared_path_);
-  crostini_share_path_->SetMountEventSeneschalCallbackForTesting(
+  crostini_share_path_->set_mount_event_seneschal_callback_for_testing(
       base::BindRepeating(&CrostiniSharePathTest::MountEventUnsharePathCallback,
                           base::Unretained(this), "unshare-on-unmount",
                           shared_path_, Persist::YES,
diff --git a/chrome/browser/chromeos/dbus/dbus_helper.cc b/chrome/browser/chromeos/dbus/dbus_helper.cc
index 488b8ba1..dc041ea 100644
--- a/chrome/browser/chromeos/dbus/dbus_helper.cc
+++ b/chrome/browser/chromeos/dbus/dbus_helper.cc
@@ -9,6 +9,7 @@
 #include "chromeos/dbus/biod/biod_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/hammerd/hammerd_client.h"
+#include "chromeos/dbus/kerberos/kerberos_client.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/system_clock/system_clock_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
@@ -42,10 +43,12 @@
 
   if (bus) {
     BiodClient::Initialize(bus);  // For device::Fingerprint.
+    KerberosClient::Initialize(bus);
     SystemClockClient::Initialize(bus);
     UpstartClient::Initialize(bus);
   } else {
     BiodClient::InitializeFake();  // For device::Fingerprint.
+    KerberosClient::InitializeFake();
     SystemClockClient::InitializeFake();
     UpstartClient::InitializeFake();
   }
@@ -61,6 +64,7 @@
   UpstartClient::Shutdown();
   SystemClockClient::Shutdown();
   PowerManagerClient::Shutdown();
+  KerberosClient::Shutdown();
   BiodClient::Shutdown();
 
   // See comment in InitializeDBus() for MultiProcessMash behavior.
diff --git a/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc b/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc
index 89826ff..da60d2e 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service_unittest.cc
@@ -33,7 +33,9 @@
   TestingProfileManager profile_manager_;
 };
 
-TEST_F(DriveIntegrationServiceTest, ServiceInstanceIdentity) {
+// This test is flaky on chromeos.
+// https://crbug.com/943376
+TEST_F(DriveIntegrationServiceTest, DISABLED_ServiceInstanceIdentity) {
   TestingProfile* user1 = profile_manager_.CreateTestingProfile("user1");
 
   // Integration Service is created as a profile keyed service.
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 0e5dbf0..8cf063c9 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -53,8 +53,9 @@
 #include "chrome/browser/ui/views/crostini/crostini_uninstaller_view.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/api/autotest_private.h"
+#include "chrome/common/pref_names.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/printing/printer_configuration.h"
 #include "chromeos/services/assistant/public/mojom/constants.mojom.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
@@ -190,6 +191,8 @@
     }
   } else if (pref_name == ash::prefs::kAccessibilityVirtualKeyboardEnabled) {
     DCHECK(value.is_bool());
+  } else if (pref_name == prefs::kLanguagePreloadEngines) {
+    DCHECK(value.is_string());
   } else {
     return "The pref " + pref_name + "is not whitelisted.";
   }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 111adbe4..c1eba732 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -61,6 +61,7 @@
   }
 
   TestCase& EnableDocumentsProvider() {
+    enable_arc = true;
     enable_documents_provider.emplace(true);
     return *this;
   }
@@ -70,6 +71,11 @@
     return *this;
   }
 
+  TestCase& EnableArc() {
+    enable_arc = true;
+    return *this;
+  }
+
   TestCase& Offline() {
     offline = true;
     return *this;
@@ -130,6 +136,7 @@
   base::Optional<bool> enable_drivefs;
   base::Optional<bool> enable_myfiles_volume;
   base::Optional<bool> enable_documents_provider;
+  bool enable_arc = false;
   bool with_browser = false;
   bool needs_zip = false;
   bool offline = false;
@@ -190,6 +197,8 @@
         FileManagerBrowserTestBase::GetEnableDocumentsProvider());
   }
 
+  bool GetEnableArc() const override { return GetParam().enable_arc; }
+
   bool GetRequiresStartupBrowser() const override {
     return GetParam().with_browser;
   }
@@ -587,6 +596,7 @@
         TestCase("dirContextMenuDocumentsProvider").EnableDocumentsProvider(),
         TestCase("dirContextMenuUsbDcim"),
         TestCase("dirContextMenuMtp"),
+        TestCase("dirContextMenuMediaView").EnableArc(),
         TestCase("dirContextMenuShortcut")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
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 19cecaeb..9848ef5 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -29,6 +29,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_media_view_util.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
@@ -1281,13 +1282,22 @@
 class DocumentsProviderTestVolume : public TestVolume {
  public:
   DocumentsProviderTestVolume(
+      const std::string& name,
       arc::FakeFileSystemInstance* const file_system_instance,
       const std::string& authority,
       const std::string& root_document_id)
-      : TestVolume("DocumentsProvider"),
+      : TestVolume(name),
         file_system_instance_(file_system_instance),
         authority_(authority),
         root_document_id_(root_document_id) {}
+  DocumentsProviderTestVolume(
+      arc::FakeFileSystemInstance* const file_system_instance,
+      const std::string& authority,
+      const std::string& root_document_id)
+      : DocumentsProviderTestVolume("DocumentsProvider",
+                                    file_system_instance,
+                                    authority,
+                                    root_document_id) {}
   ~DocumentsProviderTestVolume() override = default;
 
   virtual void CreateEntry(const AddEntriesMessage::TestEntryInfo& entry) {
@@ -1299,12 +1309,8 @@
     file_system_instance_->AddDocument(document);
   }
 
-  bool Mount(Profile* profile) {
-    // Register a root document of this volume.
-    arc::FakeFileSystemInstance::Document document(
-        authority_, root_document_id_, "", "", arc::kAndroidDirectoryMimeType,
-        0, 0);
-    file_system_instance_->AddDocument(document);
+  virtual bool Mount(Profile* profile) {
+    RegisterRoot();
 
     // Tell VolumeManager that a new DocumentsProvider volume is added.
     VolumeManager::Get(profile)->OnDocumentsProviderRootAdded(
@@ -1312,11 +1318,20 @@
     return true;
   }
 
- private:
+ protected:
   arc::FakeFileSystemInstance* const file_system_instance_;
   std::string authority_;
   std::string root_document_id_;
 
+  // Register a root document of this volume.
+  void RegisterRoot() {
+    arc::FakeFileSystemInstance::Document document(
+        authority_, root_document_id_, "", "", arc::kAndroidDirectoryMimeType,
+        0, 0);
+    file_system_instance_->AddDocument(document);
+  }
+
+ private:
   int64_t GetFileSize(const AddEntriesMessage::TestEntryInfo& entry) {
     if (entry.type != AddEntriesMessage::FILE)
       return 0;
@@ -1333,6 +1348,32 @@
                ? entry.mime_type
                : arc::kAndroidDirectoryMimeType;
   }
+
+  DISALLOW_COPY_AND_ASSIGN(DocumentsProviderTestVolume);
+};
+
+// MediaViewTestVolume: Test volume for the "media views": Audio, Images and
+// Videos.
+class MediaViewTestVolume : public DocumentsProviderTestVolume {
+ public:
+  MediaViewTestVolume(arc::FakeFileSystemInstance* const file_system_instance,
+                      const std::string& authority,
+                      const std::string& root_document_id)
+      : DocumentsProviderTestVolume(root_document_id,
+                                    file_system_instance,
+                                    authority,
+                                    root_document_id) {}
+
+  ~MediaViewTestVolume() override = default;
+
+  bool Mount(Profile* profile) override {
+    RegisterRoot();
+    return VolumeManager::Get(profile)->RegisterMediaViewForTesting(
+        root_document_id_);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MediaViewTestVolume);
 };
 
 FileManagerBrowserTestBase::FileManagerBrowserTestBase() = default;
@@ -1401,8 +1442,11 @@
     disabled_features.emplace_back(chromeos::features::kMyFilesVolume);
   }
 
-  if (IsDocumentsProviderTest()) {
+  if (IsArcTest()) {
     arc::SetArcAvailableCommandLineForTesting(command_line);
+  }
+
+  if (IsDocumentsProviderTest()) {
     enabled_features.emplace_back(
         arc::kEnableDocumentsProviderInFilesAppFeature);
   } else {
@@ -1501,13 +1545,16 @@
           arc::ArcServiceManager::Get()->arc_bridge_service()->file_system());
       ASSERT_TRUE(arc_file_system_instance_->InitCalled());
 
-      // Though we can have multiple DocumentsProvider volumes, only one volume
-      // is created and mounted for now.
-      documents_provider_volume_ =
-          std::make_unique<DocumentsProviderTestVolume>(
-              arc_file_system_instance_.get(), "com.example.documents", "root");
-      if (!DoesTestStartWithNoVolumesMounted()) {
-        documents_provider_volume_->Mount(profile());
+      if (IsDocumentsProviderTest()) {
+        // Though we can have multiple DocumentsProvider volumes, only one
+        // volume is created and mounted for now.
+        documents_provider_volume_ =
+            std::make_unique<DocumentsProviderTestVolume>(
+                arc_file_system_instance_.get(), "com.example.documents",
+                "root");
+        if (!DoesTestStartWithNoVolumesMounted()) {
+          documents_provider_volume_->Mount(profile());
+        }
       }
     } else {
       // When ARC is not available, "Android Files" will not be mounted.
@@ -1567,6 +1614,10 @@
   return false;
 }
 
+bool FileManagerBrowserTestBase::GetEnableArc() const {
+  return false;
+}
+
 bool FileManagerBrowserTestBase::GetRequiresStartupBrowser() const {
   return false;
 }
@@ -1869,6 +1920,26 @@
     return;
   }
 
+  if (name == "mountMediaView") {
+    CHECK(arc::IsArcAvailable())
+        << "ARC required for mounting media view volumes";
+
+    media_view_images_ = std::make_unique<MediaViewTestVolume>(
+        arc_file_system_instance_.get(),
+        "com.android.providers.media.documents", arc::kImagesRootDocumentId);
+    media_view_videos_ = std::make_unique<MediaViewTestVolume>(
+        arc_file_system_instance_.get(),
+        "com.android.providers.media.documents", arc::kVideosRootDocumentId);
+    media_view_audio_ = std::make_unique<MediaViewTestVolume>(
+        arc_file_system_instance_.get(),
+        "com.android.providers.media.documents", arc::kAudioRootDocumentId);
+
+    ASSERT_TRUE(media_view_images_->Mount(profile()));
+    ASSERT_TRUE(media_view_videos_->Mount(profile()));
+    ASSERT_TRUE(media_view_audio_->Mount(profile()));
+    return;
+  }
+
   if (name == "setDriveEnabled") {
     bool enabled;
     ASSERT_TRUE(value.GetBoolean("enabled", &enabled));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
index 4e3523b2..2d47e0a3 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -34,6 +34,7 @@
 class AndroidFilesTestVolume;
 class RemovableTestVolume;
 class DocumentsProviderTestVolume;
+class MediaViewTestVolume;
 
 class FileManagerBrowserTestBase : public extensions::ExtensionApiTest {
  protected:
@@ -59,6 +60,7 @@
   virtual bool GetEnableDriveFs() const;
   virtual bool GetEnableMyFilesVolume() const;
   virtual bool GetEnableDocumentsProvider() const;
+  virtual bool GetEnableArc() const;
   virtual bool GetRequiresStartupBrowser() const;
   virtual bool GetNeedsZipSupport() const;
   virtual bool GetIsOffline() const;
@@ -86,6 +88,9 @@
   // Returns true if the test requires Android documents providers.
   bool IsDocumentsProviderTest() const { return GetEnableDocumentsProvider(); }
 
+  // Returns true if the test requires ARC++.
+  bool IsArcTest() const { return GetEnableArc(); }
+
   // Returns true if the test MyFilesVolume feature is enabled.
   bool IsMyFilesVolume() const { return GetEnableMyFilesVolume(); }
 
@@ -148,6 +153,9 @@
   std::unique_ptr<RemovableTestVolume> partition_1_;
   std::unique_ptr<RemovableTestVolume> partition_2_;
   std::unique_ptr<DocumentsProviderTestVolume> documents_provider_volume_;
+  std::unique_ptr<MediaViewTestVolume> media_view_images_;
+  std::unique_ptr<MediaViewTestVolume> media_view_videos_;
+  std::unique_ptr<MediaViewTestVolume> media_view_audio_;
 
   drive::DriveIntegrationServiceFactory::FactoryCallback
       create_drive_integration_service_;
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
index 0656ac6..1facea88 100644
--- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -432,7 +432,6 @@
 TEST_F(FileManagerPathUtilTest, ConvertFileSystemURLToPathInsideCrostini) {
   base::test::ScopedFeatureList initial_features;
   initial_features.InitAndEnableFeature(chromeos::features::kDriveFs);
-  content::TestServiceManagerContext service_manager_context;
 
   storage::ExternalMountPoints* mount_points =
       storage::ExternalMountPoints::GetSystemInstance();
@@ -588,18 +587,17 @@
 }
 
 TEST_F(FileManagerPathUtilTest, ExtractMountNameFileSystemNameFullPath) {
-  content::TestServiceManagerContext service_manager_context;
   storage::ExternalMountPoints* mount_points =
       storage::ExternalMountPoints::GetSystemInstance();
   std::string downloads_mount_name = GetDownloadsMountPointName(profile_.get());
   base::FilePath downloads = GetDownloadsFolderForProfile(profile_.get());
-  mount_points->RegisterFileSystem(downloads_mount_name,
-                                   storage::kFileSystemTypeNativeLocal,
-                                   storage::FileSystemMountOption(), downloads);
+  EXPECT_TRUE(mount_points->RegisterFileSystem(
+      downloads_mount_name, storage::kFileSystemTypeNativeLocal,
+      storage::FileSystemMountOption(), downloads));
   base::FilePath removable = base::FilePath(kRemovableMediaPath);
-  mount_points->RegisterFileSystem(
+  EXPECT_TRUE(mount_points->RegisterFileSystem(
       chromeos::kSystemMountNameRemovable, storage::kFileSystemTypeNativeLocal,
-      storage::FileSystemMountOption(), base::FilePath(kRemovableMediaPath));
+      storage::FileSystemMountOption(), base::FilePath(kRemovableMediaPath)));
   std::string relative_path_1 = "foo";
   std::string relative_path_2 = "foo/bar";
   std::string mount_name;
@@ -634,9 +632,12 @@
       removable, &mount_name, &file_system_name, &full_path));
 
   // <removable>/foo/
+  // TODO(crbug.com/942371): Extra debugging to detect what is causing flakes.
+  base::FilePath absolute_path = removable.Append(relative_path_1);
+  base::FilePath virtual_path;
+  EXPECT_TRUE(mount_points->GetVirtualPath(absolute_path, &virtual_path));
   EXPECT_TRUE(ExtractMountNameFileSystemNameFullPath(
-      removable.Append(relative_path_1), &mount_name, &file_system_name,
-      &full_path));
+      absolute_path, &mount_name, &file_system_name, &full_path));
   EXPECT_EQ(mount_name, "removable/foo");
   EXPECT_EQ(file_system_name, "foo");
   EXPECT_EQ(full_path, "/");
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index c90b65d4..38a8af14 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -678,6 +678,14 @@
   return true;
 }
 
+bool VolumeManager::RegisterMediaViewForTesting(
+    const std::string& root_document_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DoMountEvent(chromeos::MOUNT_ERROR_NONE,
+               Volume::CreateForMediaView(root_document_id));
+  return true;
+}
+
 bool VolumeManager::RemoveAndroidFilesDirectoryForTesting(
     const base::FilePath& path) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h
index 52dda8b9..fa956f5 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -106,6 +106,9 @@
                                               bool read_only);
   static std::unique_ptr<Volume> CreateForMediaView(
       const std::string& root_document_id);
+  static std::unique_ptr<Volume> CreateMediaViewForTesting(
+      base::FilePath mount_path,
+      const std::string& root_document_id);
   static std::unique_ptr<Volume> CreateForSshfsCrostini(
       const base::FilePath& crostini_path);
   static std::unique_ptr<Volume> CreateForAndroidFiles(
@@ -317,23 +320,27 @@
   // Removes Downloads volume used for testing.
   void RemoveDownloadsDirectoryForTesting();
 
-  // For testing purpose, registers a native local file system pointing to
+  // For testing purposes, registers a native local file system pointing to
   // |path| with DOWNLOADS type, and adds its volume info.
   bool RegisterDownloadsDirectoryForTesting(const base::FilePath& path);
 
-  // For testing purpose, registers a native local file system pointing to
+  // For testing purposes, registers a native local file system pointing to
   // |path| with CROSTINI type, and adds its volume info.
   bool RegisterCrostiniDirectoryForTesting(const base::FilePath& path);
 
-  // For testing purpose, registers a native local file system pointing to
+  // For testing purposes, registers a native local file system pointing to
   // |path| with ANDROID_FILES type, and adds its volume info.
   bool RegisterAndroidFilesDirectoryForTesting(const base::FilePath& path);
 
-  // For testing purpose, removes a registered native local file system
+  // For testing purposes, register a DocumentsProvider root with
+  // VOLUME_TYPE_MEDIA_VIEW, and adds its volume info
+  bool RegisterMediaViewForTesting(const std::string& root_document_id);
+
+  // For testing purposes, removes a registered native local file system
   // pointing to |path| with ANDROID_FILES type, and removes its volume info.
   bool RemoveAndroidFilesDirectoryForTesting(const base::FilePath& path);
 
-  // For testing purpose, adds a volume info pointing to |path|, with TESTING
+  // For testing purposes, adds a volume info pointing to |path|, with TESTING
   // type. Assumes that the mount point is already registered.
   void AddVolumeForTesting(const base::FilePath& path,
                            VolumeType volume_type,
@@ -342,7 +349,7 @@
                            const base::FilePath& device_path = base::FilePath(),
                            const std::string& drive_label = "");
 
-  // For testing purpose, adds the volume info to the volume manager.
+  // For testing purposes, adds the volume info to the volume manager.
   void AddVolumeForTesting(std::unique_ptr<Volume> volume);
 
   void RemoveVolumeForTesting(
diff --git a/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc b/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
index 1314c23..efba4651 100644
--- a/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
@@ -34,7 +34,7 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/shill_manager_client.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index b954a67..fd16241c 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -31,7 +31,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/policy_switches.h"
 #include "components/prefs/json_pref_store.h"
diff --git a/chrome/browser/chromeos/login/crash_restore_browsertest.cc b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
index 73a5aff..f45c581 100644
--- a/chrome/browser/chromeos/login/crash_restore_browsertest.cc
+++ b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
@@ -28,8 +28,8 @@
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 7c10fb71..bdd0511 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -18,6 +18,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
+#include "base/scoped_observer.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
@@ -74,7 +75,7 @@
 #include "chromeos/cryptohome/cryptohome_util.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/auth/authpolicy_login_helper.h"
 #include "chromeos/login/auth/key.h"
 #include "chromeos/settings/cros_settings_names.h"
@@ -339,6 +340,42 @@
 
 }  // namespace
 
+// Utility class used to wait for a Public Session policy store load if public
+// session login is requested before the associated policy store is loaded.
+// When the store gets loaded, it will run the callback passed to the
+// constructor.
+class ExistingUserController::PolicyStoreLoadWaiter
+    : public policy::CloudPolicyStore::Observer {
+ public:
+  PolicyStoreLoadWaiter(policy::CloudPolicyStore* store,
+                        base::OnceClosure callback)
+      : callback_(std::move(callback)) {
+    DCHECK(!store->is_initialized());
+    scoped_observer_.Add(store);
+  }
+  ~PolicyStoreLoadWaiter() override = default;
+
+  PolicyStoreLoadWaiter(const PolicyStoreLoadWaiter& other) = delete;
+  PolicyStoreLoadWaiter& operator=(const PolicyStoreLoadWaiter& other) = delete;
+
+  // policy::CloudPolicyStore::Observer:
+  void OnStoreLoaded(policy::CloudPolicyStore* store) override {
+    scoped_observer_.RemoveAll();
+    std::move(callback_).Run();
+  }
+  void OnStoreError(policy::CloudPolicyStore* store) override {
+    // If store load fails, run the callback to unblock public session login
+    // attempt, which will likely fail.
+    scoped_observer_.RemoveAll();
+    std::move(callback_).Run();
+  }
+
+ private:
+  base::OnceClosure callback_;
+  ScopedObserver<policy::CloudPolicyStore, PolicyStoreLoadWaiter>
+      scoped_observer_{this};
+};
+
 // static
 ExistingUserController* ExistingUserController::current_controller() {
   auto* host = LoginDisplayHost::default_host();
@@ -1339,6 +1376,36 @@
     return;
   }
 
+  // Public session login will fail if attempted if the associated policy store
+  // is not initialized - wait for the policy store load before starting the
+  // auto-login timer.
+  policy::CloudPolicyStore* policy_store =
+      g_browser_process->platform_part()
+          ->browser_policy_connector_chromeos()
+          ->GetDeviceLocalAccountPolicyService()
+          ->GetBrokerForUser(user->GetAccountId().GetUserEmail())
+          ->core()
+          ->store();
+
+  if (!policy_store->is_initialized()) {
+    VLOG(2) << "Public session policy store not yet initialized";
+    policy_store_waiter_ = std::make_unique<PolicyStoreLoadWaiter>(
+        policy_store,
+        base::BindOnce(
+            &ExistingUserController::LoginAsPublicSessionWithPolicyStoreReady,
+            base::Unretained(this), user_context));
+
+    return;
+  }
+
+  LoginAsPublicSessionWithPolicyStoreReady(user_context);
+}
+
+void ExistingUserController::LoginAsPublicSessionWithPolicyStoreReady(
+    const UserContext& user_context) {
+  VLOG(2) << "LoginAsPublicSessionWithPolicyStoreReady";
+  policy_store_waiter_.reset();
+
   UserContext new_user_context = user_context;
   std::string locale = user_context.GetPublicSessionLocale();
   if (locale.empty()) {
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index 4cb575d..cb7b35f 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -150,6 +150,8 @@
 
   FRIEND_TEST_ALL_PREFIXES(ExistingUserControllerTest, ExistingUserLogin);
 
+  class PolicyStoreLoadWaiter;
+
   void LoginAsGuest();
   void LoginAsPublicSession(const UserContext& user_context);
   void LoginAsKioskApp(const std::string& app_id, bool diagnostic_mode);
@@ -246,6 +248,14 @@
   // Sends an accessibility alert event to extension listeners.
   void SendAccessibilityAlert(const std::string& alert_text);
 
+  // Continues public session login if the associated user cloud policy store is
+  // loaded.
+  // This is intended to delay public session login if the login is requested
+  // before the policy store is initialized (in which case the login attempt
+  // would fail).
+  void LoginAsPublicSessionWithPolicyStoreReady(
+      const UserContext& user_context);
+
   // Callback invoked when the keyboard layouts available for a public session
   // have been retrieved. Selects the first layout from the list and continues
   // login.
@@ -410,6 +420,10 @@
 
   std::unique_ptr<policy::PreSigninPolicyFetcher> pre_signin_policy_fetcher_;
 
+  // Used to wait for cloud policy store load during public session login, if
+  // the store is not yet initialized when the login is attempted.
+  std::unique_ptr<PolicyStoreLoadWaiter> policy_store_waiter_;
+
   // Factory of callbacks.
   base::WeakPtrFactory<ExistingUserController> weak_factory_;
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 6f6b3b7..262a162 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -40,7 +40,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "chromeos/login/auth/key.h"
 #include "chromeos/login/auth/mock_url_fetchers.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index bb2472ed..817a8cee 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -49,7 +49,7 @@
 #include "chromeos/audio/chromeos_sounds.h"
 #include "chromeos/dbus/biod/constants.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/auth/authenticator.h"
 #include "chromeos/login/auth/authpolicy_login_helper.h"
 #include "chromeos/login/auth/extended_authenticator.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
index 1862985..dce35e0 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -24,7 +24,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/dbus/biod/fake_biod_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_names.h"
diff --git a/chrome/browser/chromeos/login/profile_auth_data.cc b/chrome/browser/chromeos/login/profile_auth_data.cc
index ff6cd96..f3b52535 100644
--- a/chrome/browser/chromeos/login/profile_auth_data.cc
+++ b/chrome/browser/chromeos/login/profile_auth_data.cc
@@ -79,9 +79,14 @@
   for (const auto& cookie : cookies) {
     // Assume secure_source - since the cookies are being restored from
     // another store, they have already gone through the strict secure check.
+    // Likewise for permitting same-site marked cookies.
     DCHECK(cookie.IsCanonical());
+    net::CookieOptions options;
+    options.set_include_httponly();
+    options.set_same_site_cookie_context(
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
     cookie_manager->SetCanonicalCookie(
-        cookie, "https", true /*modify_http_only*/,
+        cookie, "https", options,
         base::BindOnce(&OnCookieSet, cookie_completion_callback));
   }
 }
diff --git a/chrome/browser/chromeos/login/profile_auth_data_unittest.cc b/chrome/browser/chromeos/login/profile_auth_data_unittest.cc
index 29adacc..cc45403 100644
--- a/chrome/browser/chromeos/login/profile_auth_data_unittest.cc
+++ b/chrome/browser/chromeos/login/profile_auth_data_unittest.cc
@@ -181,27 +181,29 @@
       [&](const net::CookieList& cookies) { run_loop.Quit(); }));
   run_loop.Run();
 
+  net::CookieOptions options;
+  options.set_include_httponly();
   cookies->SetCanonicalCookie(
       *net::CanonicalCookie::CreateSanitizedCookie(
           GURL(kSAMLIdPCookieURL), kCookieName, cookie_value,
           kSAMLIdPCookieDomainWithWildcard, std::string(), base::Time(),
           base::Time(), base::Time(), true, false,
           net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT),
-      "https", true /*modify_http_only*/, base::DoNothing());
+      "https", options, base::DoNothing());
 
   cookies->SetCanonicalCookie(
       *net::CanonicalCookie::CreateSanitizedCookie(
           GURL(kSAMLIdPCookieURL), kCookieName, cookie_value, std::string(),
           std::string(), base::Time(), base::Time(), base::Time(), true, false,
           net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT),
-      "https", true /*modify_http_only*/, base::DoNothing());
+      "https", options, base::DoNothing());
 
   cookies->SetCanonicalCookie(
       *net::CanonicalCookie::CreateSanitizedCookie(
           GURL(kGAIACookieURL), kCookieName, cookie_value, std::string(),
           std::string(), base::Time(), base::Time(), base::Time(), true, false,
           net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT),
-      "https", true /*modify_http_only*/, base::DoNothing());
+      "https", options, base::DoNothing());
 }
 
 net::URLRequestContext* ProfileAuthDataTest::GetRequestContext(
diff --git a/chrome/browser/chromeos/login/reset_browsertest.cc b/chrome/browser/chromeos/login/reset_browsertest.cc
index 6039bd9..f2307f1 100644
--- a/chrome/browser/chromeos/login/reset_browsertest.cc
+++ b/chrome/browser/chromeos/login/reset_browsertest.cc
@@ -16,9 +16,9 @@
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test_utils.h"
 
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index 78d2740..4b99313 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -62,8 +62,8 @@
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/shill_manager_client.h"
 #include "chromeos/login/auth/key.h"
 #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/login/screens/demo_setup_screen.cc b/chrome/browser/chromeos/login/screens/demo_setup_screen.cc
index f1d70fa..d2de28a 100644
--- a/chrome/browser/chromeos/login/screens/demo_setup_screen.cc
+++ b/chrome/browser/chromeos/login/screens/demo_setup_screen.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/chromeos/login/screens/demo_setup_screen_view.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 namespace {
 
diff --git a/chrome/browser/chromeos/login/screens/error_screen.cc b/chrome/browser/chromeos/login/screens/error_screen.cc
index 0156f14..1385dd80 100644
--- a/chrome/browser/chromeos/login/screens/error_screen.cc
+++ b/chrome/browser/chromeos/login/screens/error_screen.cc
@@ -34,7 +34,7 @@
 #include "chrome/grit/browser_resources.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/network/network_connection_handler.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.h b/chrome/browser/chromeos/login/screens/mock_update_screen.h
index 0d7362f4..49ab20d 100644
--- a/chrome/browser/chromeos/login/screens/mock_update_screen.h
+++ b/chrome/browser/chromeos/login/screens/mock_update_screen.h
@@ -39,6 +39,15 @@
   MOCK_METHOD1(MockBind, void(UpdateScreen* screen));
   MOCK_METHOD0(MockUnbind, void());
 
+  MOCK_METHOD1(SetEstimatedTimeLeft, void(int value));
+  MOCK_METHOD1(SetShowEstimatedTimeLeft, void(bool value));
+  MOCK_METHOD1(SetUpdateCompleted, void(bool value));
+  MOCK_METHOD1(SetShowCurtain, void(bool value));
+  MOCK_METHOD1(SetProgressMessage, void(const base::string16& value));
+  MOCK_METHOD1(SetProgress, void(int value));
+  MOCK_METHOD1(SetRequiresPermissionForCellular, void(bool value));
+  MOCK_METHOD1(SetCancelUpdateShortcutEnabled, void(bool value));
+
  private:
   UpdateScreen* screen_ = nullptr;
 };
diff --git a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
index 588e745..4340078 100644
--- a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
@@ -22,7 +22,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/shill_manager_client.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.cc b/chrome/browser/chromeos/login/screens/reset_screen.cc
index 2121f07..73d4efbe 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.cc
+++ b/chrome/browser/chromeos/login/screens/reset_screen.cc
@@ -21,7 +21,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index f9d8756..5331785 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -36,16 +36,6 @@
 
 namespace {
 
-constexpr const char kContextKeyEstimatedTimeLeftSec[] = "time-left-sec";
-constexpr const char kContextKeyShowEstimatedTimeLeft[] = "show-time-left";
-constexpr const char kContextKeyUpdateCompleted[] = "update-completed";
-constexpr const char kContextKeyShowCurtain[] = "show-curtain";
-constexpr const char kContextKeyShowProgressMessage[] = "show-progress-msg";
-constexpr const char kContextKeyProgress[] = "progress";
-constexpr const char kContextKeyProgressMessage[] = "progress-msg";
-constexpr const char kContextKeyRequiresPermissionForCelluar[] =
-    "requires-permission-for-cellular";
-
 constexpr const char kUserActionAcceptUpdateOverCellular[] =
     "update-accept-cellular";
 constexpr const char kUserActionRejectUpdateOverCellular[] =
@@ -53,8 +43,6 @@
 
 #if !defined(OFFICIAL_BUILD)
 constexpr const char kUserActionCancelUpdateShortcut[] = "cancel-update";
-constexpr const char kContextKeyCancelUpdateShortcutEnabled[] =
-    "cancel-update-enabled";
 #endif
 
 // If reboot didn't happen, ask user to reboot device manually.
@@ -176,19 +164,20 @@
       break;
     case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
       MakeSureScreenIsShown();
-      GetContextEditor()
-          .SetInteger(kContextKeyProgress, kBeforeDownloadProgress)
-          .SetBoolean(kContextKeyShowEstimatedTimeLeft, false);
+      if (view_) {
+        view_->SetProgress(kBeforeDownloadProgress);
+        view_->SetShowEstimatedTimeLeft(false);
+      }
       if (!HasCriticalUpdate()) {
         VLOG(1) << "Noncritical update available: " << status.new_version;
         ExitUpdate(Result::UPDATE_NOT_REQUIRED);
       } else {
         VLOG(1) << "Critical update available: " << status.new_version;
-        GetContextEditor()
-            .SetString(kContextKeyProgressMessage,
-                       l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE))
-            .SetBoolean(kContextKeyShowProgressMessage, true)
-            .SetBoolean(kContextKeyShowCurtain, false);
+        if (view_) {
+          view_->SetProgressMessage(
+              l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE));
+          view_->SetShowCurtain(false);
+        }
       }
       break;
     case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
@@ -207,38 +196,40 @@
           ExitUpdate(Result::UPDATE_NOT_REQUIRED);
         } else {
           VLOG(1) << "Critical update available: " << status.new_version;
-          GetContextEditor()
-              .SetString(kContextKeyProgressMessage,
-                         l10n_util::GetStringUTF16(IDS_INSTALLING_UPDATE))
-              .SetBoolean(kContextKeyShowProgressMessage, true)
-              .SetBoolean(kContextKeyShowCurtain, false);
+          if (view_) {
+            view_->SetProgressMessage(
+                l10n_util::GetStringUTF16(IDS_INSTALLING_UPDATE));
+            view_->SetShowCurtain(false);
+          }
         }
       }
       UpdateDownloadingStats(status);
       break;
     case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
       MakeSureScreenIsShown();
-      GetContextEditor()
-          .SetInteger(kContextKeyProgress, kBeforeVerifyingProgress)
-          .SetString(kContextKeyProgressMessage,
-                     l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING))
-          .SetBoolean(kContextKeyShowProgressMessage, true);
+      if (view_) {
+        view_->SetProgress(kBeforeVerifyingProgress);
+        view_->SetProgressMessage(
+            l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING));
+      }
       break;
     case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
       MakeSureScreenIsShown();
-      GetContextEditor()
-          .SetInteger(kContextKeyProgress, kBeforeFinalizingProgress)
-          .SetString(kContextKeyProgressMessage,
-                     l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING))
-          .SetBoolean(kContextKeyShowProgressMessage, true);
+      if (view_) {
+        view_->SetProgress(kBeforeFinalizingProgress);
+        view_->SetProgressMessage(
+            l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING));
+      }
       break;
     case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
       MakeSureScreenIsShown();
-      GetContextEditor()
-          .SetInteger(kContextKeyProgress, kProgressComplete)
-          .SetBoolean(kContextKeyShowEstimatedTimeLeft, false);
+      if (view_) {
+        view_->SetProgress(kProgressComplete);
+        view_->SetShowEstimatedTimeLeft(false);
+      }
       if (HasCriticalUpdate()) {
-        GetContextEditor().SetBoolean(kContextKeyShowCurtain, false);
+        if (view_)
+          view_->SetShowCurtain(false);
         VLOG(1) << "Initiate reboot after update";
         DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate();
         reboot_timer_.Start(FROM_HERE,
@@ -257,9 +248,10 @@
       DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
 
       MakeSureScreenIsShown();
-      GetContextEditor()
-          .SetBoolean(kContextKeyRequiresPermissionForCelluar, true)
-          .SetBoolean(kContextKeyShowCurtain, false);
+      if (view_) {
+        view_->SetRequiresPermissionForCellular(true);
+        view_->SetShowCurtain(false);
+      }
       break;
     case UpdateEngineClient::UPDATE_STATUS_ATTEMPTING_ROLLBACK:
       VLOG(1) << "Attempting rollback";
@@ -351,15 +343,15 @@
   is_shown_ = true;
   histogram_helper_->OnScreenShow();
 
+  if (view_) {
 #if !defined(OFFICIAL_BUILD)
-  GetContextEditor().SetBoolean(kContextKeyCancelUpdateShortcutEnabled, true);
+    view_->SetCancelUpdateShortcutEnabled(true);
 #endif
-  GetContextEditor()
-      .SetInteger(kContextKeyProgress, kBeforeUpdateCheckProgress)
-      .SetBoolean(kContextKeyRequiresPermissionForCelluar, false);
+    view_->SetProgress(kBeforeUpdateCheckProgress);
+    view_->SetRequiresPermissionForCellular(false);
 
-  if (view_)
     view_->Show();
+  }
 }
 
 void UpdateScreen::Hide() {
@@ -385,9 +377,10 @@
   } else if (action_id == kUserActionRejectUpdateOverCellular) {
     // Reset UI context to show curtain again when the user goes back to the
     // update screen.
-    GetContextEditor()
-        .SetBoolean(kContextKeyShowCurtain, true)
-        .SetBoolean(kContextKeyRequiresPermissionForCelluar, false);
+    if (view_) {
+      view_->SetShowCurtain(true);
+      view_->SetRequiresPermissionForCellular(false);
+    }
     ExitUpdate(Result::UPDATE_ERROR);
   } else {
     BaseScreen::OnUserAction(action_id);
@@ -397,15 +390,16 @@
 void UpdateScreen::RetryUpdateWithUpdateOverCellularPermissionSet(
     bool success) {
   if (success) {
-    GetContextEditor().SetBoolean(kContextKeyRequiresPermissionForCelluar,
-                                  false);
+    if (view_)
+      view_->SetRequiresPermissionForCellular(false);
     StartUpdateCheck();
   } else {
     // Reset UI context to show curtain again when the user goes back to the
     // update screen.
-    GetContextEditor()
-        .SetBoolean(kContextKeyShowCurtain, true)
-        .SetBoolean(kContextKeyRequiresPermissionForCelluar, false);
+    if (view_) {
+      view_->SetShowCurtain(true);
+      view_->SetRequiresPermissionForCellular(false);
+    }
     ExitUpdate(Result::UPDATE_ERROR);
   }
 }
@@ -442,21 +436,23 @@
           (status.download_progress - download_start_progress_) / time_delta;
     }
     double work_left = progress_left * status.new_size;
+    // time_left is in seconds.
     double time_left = work_left / download_average_speed_;
     // |time_left| may be large enough or even +infinity. So we must
     // |bound possible estimations.
     time_left = std::min(time_left, kMaxTimeLeft);
 
-    GetContextEditor()
-        .SetBoolean(kContextKeyShowEstimatedTimeLeft, true)
-        .SetInteger(kContextKeyEstimatedTimeLeftSec,
-                    static_cast<int>(time_left));
+    if (view_) {
+      view_->SetShowEstimatedTimeLeft(true);
+      view_->SetEstimatedTimeLeft(static_cast<int>(time_left));
+    }
   }
 
-  int download_progress =
-      static_cast<int>(status.download_progress * kDownloadProgressIncrement);
-  GetContextEditor().SetInteger(kContextKeyProgress,
-                                kBeforeDownloadProgress + download_progress);
+  if (view_) {
+    int download_progress =
+        static_cast<int>(status.download_progress * kDownloadProgressIncrement);
+    view_->SetProgress(kBeforeDownloadProgress + download_progress);
+  }
 }
 
 bool UpdateScreen::HasCriticalUpdate() {
@@ -481,7 +477,8 @@
 void UpdateScreen::OnWaitForRebootTimeElapsed() {
   LOG(ERROR) << "Unable to reboot - asking user for a manual reboot.";
   MakeSureScreenIsShown();
-  GetContextEditor().SetBoolean(kContextKeyUpdateCompleted, true);
+  if (view_)
+    view_->SetUpdateCompleted(true);
 }
 
 void UpdateScreen::MakeSureScreenIsShown() {
diff --git a/chrome/browser/chromeos/login/screens/update_view.h b/chrome/browser/chromeos/login/screens/update_view.h
index dc9c851..8381a85 100644
--- a/chrome/browser/chromeos/login/screens/update_view.h
+++ b/chrome/browser/chromeos/login/screens/update_view.h
@@ -31,6 +31,16 @@
 
   // Unbinds the screen from the view.
   virtual void Unbind() = 0;
+
+  // Set the estimated time left, in seconds.
+  virtual void SetEstimatedTimeLeft(int value) = 0;
+  virtual void SetShowEstimatedTimeLeft(bool value) = 0;
+  virtual void SetUpdateCompleted(bool value) = 0;
+  virtual void SetShowCurtain(bool value) = 0;
+  virtual void SetProgressMessage(const base::string16& value) = 0;
+  virtual void SetProgress(int value) = 0;
+  virtual void SetRequiresPermissionForCellular(bool value) = 0;
+  virtual void SetCancelUpdateShortcutEnabled(bool value) = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 734d72c..67fc6076 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -42,7 +42,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 4d7ea1b..96c274a 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -114,7 +114,7 @@
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "chromeos/login/auth/stub_authenticator.h"
 #include "chromeos/network/network_cert_loader.h"
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h
index dfffd5c..ba445358 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.h
+++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -28,7 +28,7 @@
 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
 #include "chrome/browser/chromeos/login/signin/token_handle_util.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/auth/authenticator.h"
 #include "chromeos/login/auth/user_context.h"
 #include "components/arc/net/always_on_vpn_manager.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index 7a79546..4517c81d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -66,7 +66,7 @@
 #include "chromeos/constants/chromeos_constants.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/settings/cros_settings_provider.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.h b/chrome/browser/chromeos/login/ui/login_display_host_webui.h
index e18ec7d..186c5f6 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.h
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.h
@@ -23,7 +23,7 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_client.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
index 8c021c6..ae5753a0 100644
--- a/chrome/browser/chromeos/login/ui/login_display_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/user_manager/known_user.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 8392681..33a4bd3 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -34,7 +34,7 @@
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
index 1368b07..6f297e2 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
@@ -52,8 +52,8 @@
 #include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
diff --git a/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
index 8f785ecd..7953e6b 100644
--- a/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper_policy_browsertest.cc
@@ -44,8 +44,8 @@
 #include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 006854e..66a7a325 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -35,7 +35,7 @@
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/content_settings/core/common/pref_names.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "components/onc/onc_constants.h"
@@ -92,7 +92,7 @@
                            "/", base::Time(), base::Time(), base::Time(), false,
                            false, net::CookieSameSite::NO_RESTRICTION,
                            net::COOKIE_PRIORITY_MEDIUM),
-      "http", false,
+      "http", net::CookieOptions(),
       base::Bind(&InjectCookieDoneCallback, run_loop.QuitClosure()));
   run_loop.Run();
 }
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index effddd1e..dba326ea 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -102,7 +102,7 @@
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/geolocation/simple_geolocation_provider.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_handler_callbacks.h"
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 3000cc9..daa322a 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -73,8 +73,8 @@
 #include "chromeos/dbus/constants/dbus_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/fake_shill_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/system_clock/system_clock_client.h"
 #include "chromeos/geolocation/simple_geolocation_provider.h"
 #include "chromeos/network/network_state.h"
diff --git a/chrome/browser/chromeos/note_taking_helper_unittest.cc b/chrome/browser/chromeos/note_taking_helper_unittest.cc
index 076ce70..9dab808 100644
--- a/chrome/browser/chromeos/note_taking_helper_unittest.cc
+++ b/chrome/browser/chromeos/note_taking_helper_unittest.cc
@@ -30,7 +30,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h
index d1ac28e..be8ee37 100644
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h
+++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/ownership/owner_key_util.h"
 #include "components/ownership/owner_settings_service.h"
diff --git a/chrome/browser/chromeos/policy/affiliation_test_helper.cc b/chrome/browser/chromeos/policy/affiliation_test_helper.cc
index 12d07e81..9a4033af 100644
--- a/chrome/browser/chromeos/policy/affiliation_test_helper.cc
+++ b/chrome/browser/chromeos/policy/affiliation_test_helper.cc
@@ -25,8 +25,8 @@
 #include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/auth/key.h"
 #include "chromeos/login/auth/user_context.h"
 #include "components/account_id/account_id.h"
diff --git a/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc b/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc
index b388382..4bc91a5 100644
--- a/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/component_active_directory_policy_browsertest.cc
@@ -18,8 +18,8 @@
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/login_manager/policy_descriptor.pb.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/policy_builder.h"
diff --git a/chrome/browser/chromeos/policy/component_active_directory_policy_retriever.h b/chrome/browser/chromeos/policy/component_active_directory_policy_retriever.h
index a643341..2485f8f 100644
--- a/chrome/browser/chromeos/policy/component_active_directory_policy_retriever.h
+++ b/chrome/browser/chromeos/policy/component_active_directory_policy_retriever.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/login_manager/policy_descriptor.pb.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/core/common/policy_namespace.h"
 
 namespace policy {
diff --git a/chrome/browser/chromeos/policy/component_active_directory_policy_retriever_unittest.cc b/chrome/browser/chromeos/policy/component_active_directory_policy_retriever_unittest.cc
index d5f08cc..99bc358 100644
--- a/chrome/browser/chromeos/policy/component_active_directory_policy_retriever_unittest.cc
+++ b/chrome/browser/chromeos/policy/component_active_directory_policy_retriever_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/bind.h"
 #include "base/test/scoped_task_environment.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/core/common/cloud/policy_builder.h"
 #include "components/policy/core/common/policy_test_utils.h"
 #include "components/policy/proto/device_management_backend.pb.h"
diff --git a/chrome/browser/chromeos/policy/component_active_directory_policy_service_unittest.cc b/chrome/browser/chromeos/policy/component_active_directory_policy_service_unittest.cc
index c2e4d0d..40bc155 100644
--- a/chrome/browser/chromeos/policy/component_active_directory_policy_service_unittest.cc
+++ b/chrome/browser/chromeos/policy/component_active_directory_policy_service_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/test/scoped_task_environment.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/policy_builder.h"
 #include "components/policy/core/common/policy_bundle.h"
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
index d506e6fd..b42fbb9 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
@@ -33,7 +33,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/ownership/owner_key_util.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index fef238b..010d073 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -40,7 +40,7 @@
 #include "chromeos/dbus/dbus_client_implementation_type.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "chromeos/system/statistics_provider.h"
 #include "chromeos/tpm/install_attributes.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index e29e9a40..d087cd8 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -93,7 +93,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/login/auth/mock_auth_status_consumer.h"
 #include "chromeos/login/auth/user_context.h"
 #include "chromeos/network/policy_certificate_provider.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index 79b4f33..dc7afe13 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -28,7 +28,7 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chromeos/constants/chromeos_paths.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/settings/cros_settings_provider.h"
 #include "components/policy/core/common/chrome_schema.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.h b/chrome/browser/chromeos/policy/device_local_account_policy_store.h
index b711a6c6..f027b9d 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_store.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.h
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
 #include "components/policy/core/common/cloud/user_cloud_policy_store_base.h"
 
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
index 8b64b6b..b833959 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -18,7 +18,7 @@
 #include "chromeos/constants/chromeos_paths.h"
 #include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "chromeos/tpm/install_attributes.h"
 #include "crypto/rsa_private_key.h"
diff --git a/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc b/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc
index 780a447..6f39fa10 100644
--- a/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc
@@ -23,8 +23,8 @@
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "extensions/browser/api/system_display/display_info_provider.h"
diff --git a/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc b/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
index 7f472f5..a1a59d5c 100644
--- a/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
@@ -25,8 +25,8 @@
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
index cf39866b..6f8bcc6 100644
--- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -38,10 +38,10 @@
 #include "chromeos/dbus/constants/dbus_paths.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
 #include "chromeos/dbus/power_manager/policy.pb.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
diff --git a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.h b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.h
index 41834e9..27188e8 100644
--- a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.h
+++ b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher.h
@@ -16,7 +16,7 @@
 #include "chrome/browser/chromeos/policy/cached_policy_key_loader_chromeos.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
diff --git a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc
index 8a9cde4..7653d0d 100644
--- a/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc
+++ b/chrome/browser/chromeos/policy/pre_signin_policy_fetcher_unittest.cc
@@ -21,7 +21,7 @@
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
 #include "components/policy/core/common/cloud/policy_builder.h"
diff --git a/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc b/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc
index 2c64c32a..f707d3a 100644
--- a/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc
+++ b/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc
@@ -8,7 +8,7 @@
 #include "base/location.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 namespace policy {
 
diff --git a/chrome/browser/chromeos/policy/server_backed_state_keys_broker_unittest.cc b/chrome/browser/chromeos/policy/server_backed_state_keys_broker_unittest.cc
index c4c4102..2706031e 100644
--- a/chrome/browser/chromeos/policy/server_backed_state_keys_broker_unittest.cc
+++ b/chrome/browser/chromeos/policy/server_backed_state_keys_broker_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace policy {
diff --git a/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc b/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc
index 6732e80..d0172dca 100644
--- a/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/signin_profile_apps_policy_browsertest.cc
@@ -24,7 +24,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/version_info/channel.h"
 #include "components/version_info/version_info.h"
diff --git a/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc b/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
index 049c5f0..b774252b 100644
--- a/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
+++ b/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
@@ -29,7 +29,7 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
diff --git a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
index be3a59e..6988a6e 100644
--- a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
@@ -25,8 +25,8 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
index 2a4b63f2..8f9c660 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
 #include "components/policy/core/common/cloud/user_cloud_policy_store_base.h"
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
index cf76ca5..39c6695 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
@@ -21,7 +21,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/util/account_identifier_operators.h"
 #include "chromeos/network/onc/onc_test_utils.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
diff --git a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
index bf39ef7..706eafa 100644
--- a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
+++ b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
@@ -142,22 +142,22 @@
       power_manager::SuspendImminent_Reason_OTHER);
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   FakePowerManagerClient::Get()->SendDarkSuspendImminent();
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 }
 
 // Tests that the ExtensionEventObserver properly handles a canceled suspend
@@ -167,7 +167,7 @@
       power_manager::SuspendImminent_Reason_OTHER);
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   FakePowerManagerClient::Get()->SendSuspendDone();
   EXPECT_FALSE(test_api_->MaybeRunSuspendReadinessCallback());
@@ -193,12 +193,12 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   extension_event_observer_->OnBackgroundEventAcked(host, kSuspendPushId);
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   // Now test receiving the suspend attempt before the push message.
   const int kDarkSuspendPushId = 56674;
@@ -209,12 +209,12 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   extension_event_observer_->OnBackgroundEventAcked(host, kDarkSuspendPushId);
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   // Test that non-push messages do not delay the suspend.
   const int kNonPushId = 5687;
@@ -225,7 +225,7 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 }
 
 // Tests that messages sent for apps that don't use GCM are ignored.
@@ -241,7 +241,7 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 }
 
 // Tests that network requests started by an app while it is processing a push
@@ -263,7 +263,7 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   // Test that network requests started while a push message is pending delay
   // the suspend even after the push message has been acked.
@@ -276,18 +276,18 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   extension_event_observer_->OnNetworkRequestStarted(host, kNetworkRequestId);
   extension_event_observer_->OnBackgroundEventAcked(host, kPushMessageId);
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   extension_event_observer_->OnNetworkRequestDone(host, kNetworkRequestId);
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 }
 
 // Tests that any outstanding push messages or network requests for an
@@ -320,7 +320,7 @@
   EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 }
 
 // Tests that the ExtensionEventObserver does not delay suspend attempts when it
@@ -341,20 +341,20 @@
       power_manager::SuspendImminent_Reason_OTHER);
   EXPECT_EQ(
       1,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   extension_event_observer_->SetShouldDelaySuspend(false);
   EXPECT_FALSE(test_api_->MaybeRunSuspendReadinessCallback());
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 
   // Test that the ExtensionEventObserver does not delay suspend attempts when
   // it is disabled.
   FakePowerManagerClient::Get()->SendDarkSuspendImminent();
   EXPECT_EQ(
       0,
-      FakePowerManagerClient::Get()->GetNumPendingSuspendReadinessCallbacks());
+      FakePowerManagerClient::Get()->num_pending_suspend_readiness_callbacks());
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
index 3b0b2275..16ebb3b0 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -26,7 +26,7 @@
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "components/prefs/testing_pref_service.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/settings/device_settings_service.h b/chrome/browser/chromeos/settings/device_settings_service.h
index 74d1455..1e7c54e 100644
--- a/chrome/browser/chromeos/settings/device_settings_service.h
+++ b/chrome/browser/chromeos/settings/device_settings_service.h
@@ -15,7 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/ownership/owner_settings_service.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.h b/chrome/browser/chromeos/settings/device_settings_test_helper.h
index 9025aea5..e129e06 100644
--- a/chrome/browser/chromeos/settings/device_settings_test_helper.h
+++ b/chrome/browser/chromeos/settings/device_settings_test_helper.h
@@ -14,7 +14,7 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h b/chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h
index 8f0513e..31824f1e 100644
--- a/chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h
+++ b/chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/chromeos/settings/stub_install_attributes.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/settings/cros_settings_provider.h"
 
 class Profile;
diff --git a/chrome/browser/chromeos/settings/session_manager_operation.h b/chrome/browser/chromeos/settings/session_manager_operation.h
index a46ff4a..f36b3dc 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation.h
+++ b/chrome/browser/chromeos/settings/session_manager_operation.h
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_validator.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "net/cert/x509_util_nss.h"
 
 namespace enterprise_management {
diff --git a/chrome/browser/chromeos/shutdown_policy_browsertest.cc b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
index 28a6bc74..77e5e34 100644
--- a/chrome/browser/chromeos/shutdown_policy_browsertest.cc
+++ b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
@@ -33,8 +33,8 @@
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/chromeos/system/device_disabling_browsertest.cc b/chrome/browser/chromeos/system/device_disabling_browsertest.cc
index 216d6b8..ac9dd682 100644
--- a/chrome/browser/chromeos/system/device_disabling_browsertest.cc
+++ b/chrome/browser/chromeos/system/device_disabling_browsertest.cc
@@ -23,9 +23,9 @@
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/fake_shill_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/shill_manager_client.h"
 #include "chromeos/dbus/shill_service_client.h"
 #include "chromeos/settings/cros_settings_names.h"
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc b/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
index 15792333..37a09d66 100644
--- a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
+++ b/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
@@ -21,7 +21,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.cc b/chrome/browser/chromeos/usb/cros_usb_detector.cc
index 06e928b..ab564ab 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.cc
@@ -217,6 +217,15 @@
       UsbFilterByClassCode(USB_CLASS_VIDEO));
   guest_os_classes_without_notif_.emplace_back(
       UsbFilterByClassCode(USB_CLASS_PERSONAL_HEALTHCARE));
+
+  // If a device has an adb interface, we always allow it.
+  const int kAdbSubclass = 0x42;
+  const int kAdbProtocol = 0x1;
+  adb_device_filter_ = UsbFilterByClassCode(USB_CLASS_VENDOR_SPEC);
+  adb_device_filter_->has_subclass_code = true;
+  adb_device_filter_->subclass_code = kAdbSubclass;
+  adb_device_filter_->has_protocol_code = true;
+  adb_device_filter_->protocol_code = kAdbProtocol;
 }
 
 CrosUsbDetector::~CrosUsbDetector() {
@@ -274,6 +283,24 @@
                                         weak_ptr_factory_.GetWeakPtr()));
 }
 
+bool CrosUsbDetector::ShouldShowNotification(
+    const device::mojom::UsbDeviceInfo& device_info) {
+  if (device::UsbDeviceFilterMatches(*adb_device_filter_, device_info)) {
+    return true;
+  }
+  return !device::UsbDeviceFilterMatchesAny(guest_os_classes_without_notif_,
+                                            device_info);
+}
+
+bool CrosUsbDetector::IsDeviceSharable(
+    const device::mojom::UsbDeviceInfo& device_info) {
+  if (device::UsbDeviceFilterMatches(*adb_device_filter_, device_info)) {
+    return true;
+  }
+  return !device::UsbDeviceFilterMatchesAny(guest_os_classes_blocked_,
+                                            device_info);
+}
+
 void CrosUsbDetector::OnDeviceChecked(
     device::mojom::UsbDeviceInfoPtr device_info,
     bool hide_notification,
@@ -297,8 +324,7 @@
   SignalSharedUsbDeviceObservers();
 
   // Some devices should not trigger the notification.
-  if (hide_notification || device::UsbDeviceFilterMatchesAny(
-                               guest_os_classes_without_notif_, *device_info)) {
+  if (hide_notification || !ShouldShowNotification(*device_info)) {
     return;
   }
   ShowNotificationForDevice(std::move(device_info));
@@ -310,8 +336,7 @@
 
 void CrosUsbDetector::OnDeviceAdded(device::mojom::UsbDeviceInfoPtr device_info,
                                     bool hide_notification) {
-  if (device::UsbDeviceFilterMatchesAny(guest_os_classes_blocked_,
-                                        *device_info)) {
+  if (!IsDeviceSharable(*device_info)) {
     return;  // Guest OS does not handle this kind of device.
   }
   device_manager_->CheckAccess(
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.h b/chrome/browser/chromeos/usb/cros_usb_detector.h
index f4651df..426678f 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.h
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.h
@@ -140,6 +140,11 @@
       uint8_t guest_port,
       crostini::CrostiniResult result);
 
+  // Returns true when a device should show a notification when attached.
+  bool ShouldShowNotification(const device::mojom::UsbDeviceInfo& device_info);
+  // Returns true when a device can be shared.
+  bool IsDeviceSharable(const device::mojom::UsbDeviceInfo& device_info);
+
   device::mojom::UsbDeviceManagerPtr device_manager_;
   mojo::AssociatedBinding<device::mojom::UsbDeviceManagerClient>
       client_binding_;
@@ -147,6 +152,7 @@
   std::vector<device::mojom::UsbDeviceFilterPtr> guest_os_classes_blocked_;
   std::vector<device::mojom::UsbDeviceFilterPtr>
       guest_os_classes_without_notif_;
+  device::mojom::UsbDeviceFilterPtr adb_device_filter_;
 
   // A mapping from GUID -> UsbDeviceInfo for each attached USB device
   std::map<std::string, device::mojom::UsbDeviceInfoPtr> available_device_info_;
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
index 9db1527..5ab7f4f 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
@@ -45,26 +45,40 @@
 
 const int kUsbConfigWithInterfaces = 1;
 
-scoped_refptr<device::FakeUsbDeviceInfo> CreateTestDeviceOfClass(
-    uint8_t device_class) {
+struct InterfaceCodes {
+  InterfaceCodes(uint8_t device_class,
+                 uint8_t subclass_code,
+                 uint8_t protocol_code)
+      : device_class(device_class),
+        subclass_code(subclass_code),
+        protocol_code(protocol_code) {}
+  uint8_t device_class;
+  uint8_t subclass_code;
+  uint8_t protocol_code;
+};
+
+scoped_refptr<device::FakeUsbDeviceInfo> CreateTestDeviceFromCodes(
+    uint8_t device_class,
+    const std::vector<InterfaceCodes>& interface_codes) {
+  auto config = device::mojom::UsbConfigurationInfo::New();
+  config->configuration_value = kUsbConfigWithInterfaces;
   // The usb_utils do not filter by device class, only by configurations, and
   // the FakeUsbDeviceInfo does not set up configurations for a fake device's
   // class code. This helper sets up a configuration to match a devices class
   // code so that USB devices can be filtered out.
-  auto alternate = device::mojom::UsbAlternateInterfaceInfo::New();
-  alternate->alternate_setting = 0;
-  alternate->class_code = device_class;
-  alternate->subclass_code = 0xff;
-  alternate->protocol_code = 0xff;
+  for (size_t i = 0; i < interface_codes.size(); ++i) {
+    auto alternate = device::mojom::UsbAlternateInterfaceInfo::New();
+    alternate->alternate_setting = 0;
+    alternate->class_code = interface_codes[i].device_class;
+    alternate->subclass_code = interface_codes[i].subclass_code;
+    alternate->protocol_code = interface_codes[i].protocol_code;
 
-  auto interface = device::mojom::UsbInterfaceInfo::New();
-  interface->interface_number = 0;
-  interface->alternates.push_back(std::move(alternate));
+    auto interface = device::mojom::UsbInterfaceInfo::New();
+    interface->interface_number = i;
+    interface->alternates.push_back(std::move(alternate));
 
-  auto config = device::mojom::UsbConfigurationInfo::New();
-  config->configuration_value = kUsbConfigWithInterfaces;
-
-  config->interfaces.push_back(std::move(interface));
+    config->interfaces.push_back(std::move(interface));
+  }
 
   std::vector<device::mojom::UsbConfigurationInfoPtr> configs;
   configs.push_back(std::move(config));
@@ -76,6 +90,12 @@
   return device;
 }
 
+scoped_refptr<device::FakeUsbDeviceInfo> CreateTestDeviceOfClass(
+    uint8_t device_class) {
+  return CreateTestDeviceFromCodes(device_class,
+                                   {InterfaceCodes(device_class, 0xff, 0xff)});
+}
+
 }  // namespace
 
 class CrosUsbDetectorTest : public BrowserWithTestWindowTest {
@@ -201,6 +221,27 @@
   // TODO(jopra): Check that the device is not available for sharing.
 }
 
+TEST_F(CrosUsbDetectorTest, UsbDeviceClassAdbAdded) {
+  ConnectToDeviceManager();
+  base::RunLoop().RunUntilIdle();
+
+  const int kAdbClass = 0xff;
+  const int kAdbSubclass = 0x42;
+  const int kAdbProtocol = 0x1;
+  // Adb interface as well as a forbidden interface
+  scoped_refptr<device::FakeUsbDeviceInfo> device = CreateTestDeviceFromCodes(
+      /* USB_CLASS_HID */ 0x03,
+      {InterfaceCodes(kAdbClass, kAdbSubclass, kAdbProtocol),
+       InterfaceCodes(0x03, 0xff, 0xff)});
+
+  device_manager_.AddDevice(device);
+  base::RunLoop().RunUntilIdle();
+
+  std::string notification_id =
+      chromeos::CrosUsbDetector::MakeNotificationId(device->guid());
+  ASSERT_TRUE(display_service_->GetNotification(notification_id));
+}
+
 TEST_F(CrosUsbDetectorTest, UsbDeviceClassWithoutNotificationAdded) {
   ConnectToDeviceManager();
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index 7937aa9..1a60624 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -37,9 +37,9 @@
      "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"},
     {"cros-termina", "750.1",
      "e9d960f84f628e1f42d05de4046bb5b3154b6f1f65c08412c6af57a29aecaffb"},
-    {"rtanalytics-light", "9.0",
+    {"rtanalytics-light", "10.0",
      "69f09d33c439c2ab55bbbe24b47ab55cb3f6c0bd1f1ef46eefea3216ec925038"},
-    {"rtanalytics-full", "9.0",
+    {"rtanalytics-full", "10.0",
      "c93c3e1013c52100a20038b405ac854d69fa889f6dc4fa6f188267051e05e444"},
     {"star-cups-driver", "1.1",
      "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"},
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index cc3e50a..1a77634 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -59,11 +59,6 @@
   DCHECK(main_render_frame_entry_map_.empty());
   DCHECK(subframe_to_mainframe_map_.empty());
 
-  if (page_capping_observer_) {
-    // Remove the |page_capping_observer_| before the ObserverList is deleted.
-    RemoveObserver(page_capping_observer_.get());
-  }
-
   // DCHECK(pending_navigation_data_use_map_.empty());
   // DCHECK(data_use_recorders_.empty());
 }
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
index 039c8a4..f9969bfe 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.h
@@ -222,9 +222,6 @@
   std::map<content::GlobalRequestID, DataUseRecorderEntry>
       pending_navigation_data_use_map_;
 
-  // Detects heavy pages. Can be null when the feature is disabled.
-  std::unique_ptr<DataUseAscriber::PageLoadObserver> page_capping_observer_;
-
   // True if the data use ascriber should be disabled. The ascriber is disabled
   // by default.
   bool disable_ascriber_ = true;
diff --git a/chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.cc b/chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.cc
deleted file mode 100644
index dee82425..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.cc
+++ /dev/null
@@ -1,17 +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 "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-
-namespace data_use_measurement {
-namespace page_load_capping {
-namespace features {
-
-// Enables tracking heavy pages in Chrome.
-const base::Feature kDetectingHeavyPages{"DetectingHeavyPages",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
-
-}  // namespace features
-}  // namespace page_load_capping
-}  // namespace data_use_measurement
diff --git a/chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h b/chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h
deleted file mode 100644
index 922c4c8..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h
+++ /dev/null
@@ -1,20 +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 CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_CHROME_PAGE_LOAD_CAPPING_FEATURES_H_
-#define CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_CHROME_PAGE_LOAD_CAPPING_FEATURES_H_
-
-#include "base/feature_list.h"
-
-namespace data_use_measurement {
-namespace page_load_capping {
-namespace features {
-
-extern const base::Feature kDetectingHeavyPages;
-
-}  // namespace features
-}  // namespace page_load_capping
-}  // namespace data_use_measurement
-
-#endif  // CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_CHROME_PAGE_LOAD_CAPPING_FEATURES_H_
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.cc
deleted file mode 100644
index d022f47..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.cc
+++ /dev/null
@@ -1,93 +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 "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h"
-
-#include <string>
-
-#include "base/metrics/field_trial_params.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_store.h"
-
-namespace {
-
-const char kSessionDurationSeconds[] = "session-duration-seconds";
-const char kSessionHistory[] = "session-history";
-const char kSessionThreshold[] = "session-threshold";
-
-const char kPersistentDurationDays[] = "persistent-duration-days";
-const char kPersistentHistory[] = "persistent-history";
-const char kPersistentThreshold[] = "persistent-threshold";
-
-const char kHostDurationDays[] = "host-duration-days";
-const char kHostHistory[] = "host-history";
-const char kHostThreshold[] = "host-threshold";
-const char kHostsInMemory[] = "hosts-in-memory";
-
-const char kTypeVersion[] = "type-version";
-
-int GetCappingValue(const std::string& param, int default_value) {
-  return base::GetFieldTrialParamByFeatureAsInt(
-      data_use_measurement::page_load_capping::features::kDetectingHeavyPages,
-      param, default_value);
-}
-
-}  // namespace
-
-PageLoadCappingBlacklist::PageLoadCappingBlacklist(
-    std::unique_ptr<blacklist::OptOutStore> opt_out_store,
-    base::Clock* clock,
-    blacklist::OptOutBlacklistDelegate* blacklist_delegate)
-    : OptOutBlacklist(std::move(opt_out_store), clock, blacklist_delegate) {
-  Init();
-}
-
-PageLoadCappingBlacklist::~PageLoadCappingBlacklist() {}
-
-bool PageLoadCappingBlacklist::ShouldUseSessionPolicy(base::TimeDelta* duration,
-                                                      size_t* history,
-                                                      int* threshold) const {
-  *duration = base::TimeDelta::FromSeconds(
-      GetCappingValue(kSessionDurationSeconds, 600));
-  *history = GetCappingValue(kSessionHistory, 3);
-  *threshold = GetCappingValue(kSessionThreshold, 2);
-  return true;
-}
-
-bool PageLoadCappingBlacklist::ShouldUsePersistentPolicy(
-    base::TimeDelta* duration,
-    size_t* history,
-    int* threshold) const {
-  *duration =
-      base::TimeDelta::FromDays(GetCappingValue(kPersistentDurationDays, 30));
-  *history = GetCappingValue(kPersistentHistory, 10);
-  *threshold = GetCappingValue(kPersistentThreshold, 9);
-  return true;
-}
-
-bool PageLoadCappingBlacklist::ShouldUseHostPolicy(base::TimeDelta* duration,
-                                                   size_t* history,
-                                                   int* threshold,
-                                                   size_t* max_hosts) const {
-  *max_hosts = GetCappingValue(kHostsInMemory, 50);
-  *duration = base::TimeDelta::FromDays(GetCappingValue(kHostDurationDays, 30));
-  *history = GetCappingValue(kHostHistory, 7);
-  *threshold = GetCappingValue(kHostThreshold, 6);
-  return true;
-}
-
-bool PageLoadCappingBlacklist::ShouldUseTypePolicy(base::TimeDelta* duration,
-                                                   size_t* history,
-                                                   int* threshold) const {
-  return false;
-}
-
-blacklist::BlacklistData::AllowedTypesAndVersions
-PageLoadCappingBlacklist::GetAllowedTypes() const {
-  blacklist::BlacklistData::AllowedTypesAndVersions allowed_types;
-  allowed_types[static_cast<int>(
-      PageCappingBlacklistType::kPageCappingOnlyType)] =
-      GetCappingValue(kTypeVersion, 0);
-  return allowed_types;
-}
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h
deleted file mode 100644
index f73c712..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_BLACKLIST_H_
-#define CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_BLACKLIST_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_blacklist.h"
-
-namespace base {
-class Clock;
-}
-
-namespace blacklist {
-class OptOutBlacklistDelegate;
-class OptOutStore;
-}  // namespace blacklist
-
-// Page load capping only supports one type for the blacklist.
-enum PageCappingBlacklistType {
-  kPageCappingOnlyType = 0,
-};
-
-// A class that managers opt out blacklist parameters for the capping heavy
-// pages feature.
-class PageLoadCappingBlacklist : public blacklist::OptOutBlacklist {
- public:
-  PageLoadCappingBlacklist(
-      std::unique_ptr<blacklist::OptOutStore> opt_out_store,
-      base::Clock* clock,
-      blacklist::OptOutBlacklistDelegate* blacklist_delegate);
-  ~PageLoadCappingBlacklist() override;
-
- protected:
-  // OptOutBlacklist (virtual for testing):
-  bool ShouldUseSessionPolicy(base::TimeDelta* duration,
-                              size_t* history,
-                              int* threshold) const override;
-  bool ShouldUsePersistentPolicy(base::TimeDelta* duration,
-                                 size_t* history,
-                                 int* threshold) const override;
-  bool ShouldUseHostPolicy(base::TimeDelta* duration,
-                           size_t* history,
-                           int* threshold,
-                           size_t* max_hosts) const override;
-  bool ShouldUseTypePolicy(base::TimeDelta* duration,
-                           size_t* history,
-                           int* threshold) const override;
-  blacklist::BlacklistData::AllowedTypesAndVersions GetAllowedTypes()
-      const override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PageLoadCappingBlacklist);
-};
-
-#endif  // CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_BLACKLIST_H_
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist_unittest.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist_unittest.cc
deleted file mode 100644
index 9fa0195..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist_unittest.cc
+++ /dev/null
@@ -1,233 +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 "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h"
-
-#include <stdint.h>
-
-#include <map>
-#include <string>
-
-#include "base/strings/string_number_conversions.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/simple_test_clock.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_blacklist_delegate.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_store.h"
-#include "components/variations/variations_associated_data.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace previews {
-
-namespace {
-
-// Mock class to test that PageLoadCappingBlacklist notifies the delegate with
-// correct events (e.g. New host blacklisted, user blacklisted, and blacklist
-// cleared).
-class TestOptOutBlacklistDelegate : public blacklist::OptOutBlacklistDelegate {
- public:
-  TestOptOutBlacklistDelegate() {}
-
-  // PageLoadCappingBlacklistDelegate:
-  void OnNewBlacklistedHost(const std::string& host, base::Time time) override {
-  }
-  void OnUserBlacklistedStatusChange(bool blacklisted) override {}
-  void OnBlacklistCleared(base::Time time) override {}
-};
-
-class TestPageLoadCappingBlacklist : public PageLoadCappingBlacklist {
- public:
-  TestPageLoadCappingBlacklist(
-      std::unique_ptr<blacklist::OptOutStore> opt_out_store,
-      base::Clock* clock,
-      blacklist::OptOutBlacklistDelegate* blacklist_delegate)
-      : PageLoadCappingBlacklist(std::move(opt_out_store),
-                                 clock,
-                                 blacklist_delegate) {}
-  ~TestPageLoadCappingBlacklist() override {}
-
-  using PageLoadCappingBlacklist::ShouldUseSessionPolicy;
-  using PageLoadCappingBlacklist::ShouldUsePersistentPolicy;
-  using PageLoadCappingBlacklist::ShouldUseHostPolicy;
-  using PageLoadCappingBlacklist::ShouldUseTypePolicy;
-  using PageLoadCappingBlacklist::GetAllowedTypes;
-};
-
-class PageLoadCappingBlacklistTest : public testing::Test {
- public:
-  PageLoadCappingBlacklistTest() {}
-  ~PageLoadCappingBlacklistTest() override {}
-
-  void TearDown() override { variations::testing::ClearAllVariationParams(); }
-
-  void StartTest() {
-    scoped_feature_list_.InitAndEnableFeatureWithParameters(
-        data_use_measurement::page_load_capping::features::kDetectingHeavyPages,
-        params_);
-
-    black_list_ = std::make_unique<TestPageLoadCappingBlacklist>(
-        nullptr, &test_clock_, &blacklist_delegate_);
-  }
-
-  void SetParam(const std::string& param, int value) {
-    params_[param] = base::NumberToString(value);
-  }
-
-  blacklist::BlacklistData::AllowedTypesAndVersions GetAllowedTypes() const {
-    return black_list_->GetAllowedTypes();
-  }
-
- protected:
-  base::SimpleTestClock test_clock_;
-
-  std::unique_ptr<TestPageLoadCappingBlacklist> black_list_;
-
- private:
-  // Observer to |black_list_|.
-  TestOptOutBlacklistDelegate blacklist_delegate_;
-
-  std::map<std::string, std::string> params_;
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageLoadCappingBlacklistTest);
-};
-
-TEST_F(PageLoadCappingBlacklistTest, DefaultParams) {
-  StartTest();
-  {
-    base::TimeDelta duration;
-    size_t history = 0;
-    int threshold = 0;
-
-    EXPECT_TRUE(
-        black_list_->ShouldUseSessionPolicy(&duration, &history, &threshold));
-    EXPECT_EQ(base::TimeDelta::FromSeconds(600), duration);
-    EXPECT_EQ(3u, history);
-    EXPECT_EQ(2, threshold);
-  }
-
-  {
-    base::TimeDelta duration;
-    size_t history = 0;
-    int threshold = 0;
-
-    EXPECT_TRUE(black_list_->ShouldUsePersistentPolicy(&duration, &history,
-                                                       &threshold));
-    EXPECT_EQ(base::TimeDelta::FromDays(30), duration);
-    EXPECT_EQ(10u, history);
-    EXPECT_EQ(9, threshold);
-  }
-
-  {
-    base::TimeDelta duration;
-    size_t history = 0;
-    int threshold = 0;
-    size_t max_hosts = 0;
-
-    EXPECT_TRUE(black_list_->ShouldUseHostPolicy(&duration, &history,
-                                                 &threshold, &max_hosts));
-    EXPECT_EQ(base::TimeDelta::FromDays(30), duration);
-    EXPECT_EQ(7u, history);
-    EXPECT_EQ(6, threshold);
-    EXPECT_EQ(50u, max_hosts);
-  }
-
-  EXPECT_FALSE(black_list_->ShouldUseTypePolicy(nullptr, nullptr, nullptr));
-
-  blacklist::BlacklistData::AllowedTypesAndVersions types = GetAllowedTypes();
-  EXPECT_EQ(1u, types.size());
-  const auto iter = types.begin();
-  EXPECT_EQ(0, iter->first);
-  EXPECT_EQ(0, iter->second);
-}
-
-TEST_F(PageLoadCappingBlacklistTest, SessionParams) {
-  int session_duration_seconds = 5;
-  int session_history = 6;
-  int session_threshold = 7;
-
-  SetParam("session-duration-seconds", session_duration_seconds);
-  SetParam("session-history", session_history);
-  SetParam("session-threshold", session_threshold);
-
-  StartTest();
-
-  base::TimeDelta duration;
-  size_t history = 0;
-  int threshold = 0;
-
-  EXPECT_TRUE(
-      black_list_->ShouldUseSessionPolicy(&duration, &history, &threshold));
-  EXPECT_EQ(base::TimeDelta::FromSeconds(session_duration_seconds), duration);
-  EXPECT_EQ(session_history, static_cast<int>(history));
-  EXPECT_EQ(session_threshold, threshold);
-}
-
-TEST_F(PageLoadCappingBlacklistTest, PersistentParams) {
-  int persistent_duration_seconds = 5;
-  int persistent_history = 6;
-  int persistent_threshold = 7;
-
-  SetParam("persistent-duration-days", persistent_duration_seconds);
-  SetParam("persistent-history", persistent_history);
-  SetParam("persistent-threshold", persistent_threshold);
-
-  StartTest();
-
-  base::TimeDelta duration;
-  size_t history = 0;
-  int threshold = 0;
-
-  EXPECT_TRUE(
-      black_list_->ShouldUsePersistentPolicy(&duration, &history, &threshold));
-  EXPECT_EQ(base::TimeDelta::FromDays(persistent_duration_seconds), duration);
-  EXPECT_EQ(persistent_history, static_cast<int>(history));
-  EXPECT_EQ(persistent_threshold, threshold);
-}
-
-TEST_F(PageLoadCappingBlacklistTest, HostParams) {
-  int host_max_hosts = 11;
-  int host_duration_days = 5;
-  int host_history = 6;
-  int host_threshold = 7;
-
-  SetParam("host-duration-days", host_duration_days);
-  SetParam("host-history", host_history);
-  SetParam("host-threshold", host_threshold);
-  SetParam("hosts-in-memory", host_max_hosts);
-
-  StartTest();
-
-  base::TimeDelta duration;
-  size_t history = 0;
-  int threshold = 0;
-  size_t max_hosts = 0;
-
-  EXPECT_TRUE(black_list_->ShouldUseHostPolicy(&duration, &history, &threshold,
-                                               &max_hosts));
-  EXPECT_EQ(base::TimeDelta::FromDays(host_duration_days), duration);
-  EXPECT_EQ(host_history, static_cast<int>(history));
-  EXPECT_EQ(host_threshold, threshold);
-  EXPECT_EQ(host_max_hosts, static_cast<int>(max_hosts));
-}
-
-TEST_F(PageLoadCappingBlacklistTest, TypeParams) {
-  StartTest();
-  EXPECT_FALSE(black_list_->ShouldUseTypePolicy(nullptr, nullptr, nullptr));
-}
-
-TEST_F(PageLoadCappingBlacklistTest, TypeVersionParam) {
-  int version = 17;
-  SetParam("type-version", version);
-  StartTest();
-  blacklist::BlacklistData::AllowedTypesAndVersions types = GetAllowedTypes();
-  EXPECT_EQ(1u, types.size());
-  const auto iter = types.begin();
-  EXPECT_EQ(0, iter->first);
-  EXPECT_EQ(version, iter->second);
-}
-
-}  // namespace
-
-}  // namespace previews
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_browsertest.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_browsertest.cc
deleted file mode 100644
index 3f561b7..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_browsertest.cc
+++ /dev/null
@@ -1,509 +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 <memory>
-
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_param_associator.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar.h"
-#include "components/infobars/core/infobar_delegate.h"
-#include "components/infobars/core/infobar_manager.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browsing_data_remover.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/common/content_features.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_navigation_observer.h"
-#include "net/http/http_status_code.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 "net/test/embedded_test_server/simple_connection_listener.h"
-#include "services/network/public/cpp/features.h"
-#include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h"
-
-namespace {
-const base::FilePath::CharType kDocRoot[] =
-    FILE_PATH_LITERAL("chrome/test/data/data_use_measurement");
-const char kImagePrefix[] = "/image";
-
-class TestInfoBarObserver : public infobars::InfoBarManager::Observer {
- public:
-  explicit TestInfoBarObserver(base::RunLoop* run_loop) : run_loop_(run_loop) {}
-  ~TestInfoBarObserver() override {}
-
-  void OnInfoBarAdded(infobars::InfoBar* infobar) override {}
-  void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override {
-    run_loop_->QuitWhenIdle();
-  }
-  void OnInfoBarReplaced(infobars::InfoBar* old_infobar,
-                         infobars::InfoBar* new_infobar) override {}
-  void OnManagerShuttingDown(infobars::InfoBarManager* manager) override {
-    NOTREACHED();
-  }
-
- private:
-  base::RunLoop* run_loop_;
-};
-
-}  // namespace
-
-class PageLoadCappingBrowserTest : public InProcessBrowserTest {
- public:
-  PageLoadCappingBrowserTest()
-      : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
-
-  ~PageLoadCappingBrowserTest() override {}
-
-  void PostToSelf() {
-    EXPECT_FALSE(waiting_for_infobar_event_ || waiting_for_request_);
-    base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
-  void WaitForRequest() {
-    EXPECT_FALSE(waiting_for_infobar_event_ || waiting_for_request_);
-    waiting_for_request_ = true;
-    run_loop_ = std::make_unique<base::RunLoop>();
-    run_loop_->Run();
-    run_loop_.reset();
-  }
-
-  void WaitForInfoBarRemoved() {
-    EXPECT_FALSE(waiting_for_infobar_event_ || waiting_for_request_);
-    waiting_for_infobar_event_ = true;
-    run_loop_ = std::make_unique<base::RunLoop>();
-    TestInfoBarObserver test_observer(run_loop_.get());
-    InfoBarService::FromWebContents(contents())->AddObserver(&test_observer);
-    run_loop_->Run();
-    InfoBarService::FromWebContents(contents())->RemoveObserver(&test_observer);
-    waiting_for_infobar_event_ = false;
-    run_loop_.reset();
-  }
-
-  GURL GetURL(const std::string& url_string) {
-    return https_test_server_.GetURL(url_string);
-  }
-
-  void NavigateToHeavyPage() { NavigateToHeavyPageAnchor(std::string()); }
-
-  void NavigateToHeavyPageAnchor(const std::string& anchor) {
-    NavigateToHeavyPageAnchorInBrowser(browser(), anchor);
-  }
-
-  void NavigateToHeavyPageAnchorInBrowser(Browser* browser,
-                                          const std::string& anchor) {
-    ui_test_utils::NavigateToURL(
-        browser, GetURL(std::string("/page_capping.html").append(anchor)));
-  }
-
-  size_t images_attempted() const { return images_attempted_; }
-
-  content::WebContents* contents() const {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  size_t InfoBarCount() const {
-    return InfoBarService::FromWebContents(contents())->infobar_count();
-  }
-
-  void ClickInfoBarLink() {
-    InfoBarService::FromWebContents(contents())
-        ->infobar_at(0)
-        ->delegate()
-        ->AsConfirmInfoBarDelegate()
-        ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  }
-
-  void EnableDataSaver(bool enabled) {
-    browser()->profile()->GetPrefs()->SetBoolean(prefs::kDataSaverEnabled,
-                                                 enabled);
-    base::RunLoop().RunUntilIdle();
-  }
-
- private:
-  void SetUp() override {
-    std::map<std::string, std::string> feature_parameters = {
-        {"PageCapMiB", "0"},
-        {"PageFuzzingKiB", "0"},
-        {"OptOutStoreDisabled", "true"},
-        {"InfoBarTimeoutInMilliseconds", "500000"}};
-    ChangeParams(&feature_parameters);
-
-    scoped_parameterized_feature_list_.InitAndEnableFeatureWithParameters(
-        data_use_measurement::page_load_capping::features::kDetectingHeavyPages,
-        feature_parameters);
-    scoped_feature_list_.InitAndEnableFeature(
-        data_reduction_proxy::features::
-            kDataReductionProxyEnabledWithNetworkService);
-
-    https_test_server_.RegisterRequestHandler(base::BindRepeating(
-        &PageLoadCappingBrowserTest::HandleRequest, base::Unretained(this)));
-    https_test_server_.ServeFilesFromSourceDirectory(base::FilePath(kDocRoot));
-    ASSERT_TRUE(https_test_server_.Start());
-
-    InProcessBrowserTest::SetUp();
-  }
-
-  virtual void ChangeParams(std::map<std::string, std::string>* params) {}
-
-  std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
-      const net::test_server::HttpRequest& request) {
-    // Check if this matches the image requests from the test suite.
-    if (!StartsWith(request.relative_url, kImagePrefix,
-                    base::CompareCase::SENSITIVE)) {
-      return nullptr;
-    }
-    // This request should match "/image.*" for this test suite.
-    images_attempted_++;
-
-    // Return a 404. This is expected in the test, but embedded test server will
-    // create warnings when serving its own 404 responses.
-    std::unique_ptr<net::test_server::BasicHttpResponse> not_found_response =
-        std::make_unique<net::test_server::BasicHttpResponse>();
-    not_found_response->set_code(net::HTTP_NOT_FOUND);
-    if (waiting_for_request_) {
-      run_loop_->QuitWhenIdle();
-      waiting_for_request_ = false;
-    }
-    return not_found_response;
-  }
-
-  net::EmbeddedTestServer https_test_server_;
-  size_t images_attempted_ = 0u;
-  bool waiting_for_request_ = false;
-  bool waiting_for_infobar_event_ = false;
-  std::unique_ptr<base::RunLoop> run_loop_;
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-  base::test::ScopedFeatureList scoped_parameterized_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest, PageLoadCappingBlocksLoads) {
-  // Tests that subresource loading can be blocked from the browser process.
-
-  EnableDataSaver(true);
-  // Load a mostly empty page.
-  NavigateToHeavyPage();
-  // Pause subresource loading.
-  ClickInfoBarLink();
-
-  // Adds images to the page. They should not be allowed to load.
-  // Running this 20 times makes 20 round trips to the renderer, making it very
-  // likely the earliest request would have made it to the network by the time
-  // all of the calls have been made.
-  for (size_t i = 0; i < 20; ++i) {
-    std::string create_image_script =
-        std::string(
-            "var image = document.createElement('img'); "
-            "document.body.appendChild(image); image.src = '")
-            .append(kImagePrefix)
-            .append(base::NumberToString(i))
-            .append(".png';");
-    EXPECT_TRUE(content::ExecuteScript(contents(), create_image_script));
-  }
-
-  // No images should be loaded as subresource loading was paused.
-  EXPECT_EQ(0u, images_attempted());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest,
-                       PageLoadCappingBlocksLoadsAndResume) {
-  // Tests that after triggerring subresource pausing, resuming allows deferred
-  // requests to be initiated.
-
-  EnableDataSaver(true);
-  // Load a mostly empty page.
-  NavigateToHeavyPage();
-  // Pause subresource loading.
-  ClickInfoBarLink();
-
-  // Adds an image to the page. It should not be allowed to load at first.
-  // PageLoadCappingBlocksLoads tests that it is not loaded more robustly
-  std::string create_image_script =
-      std::string(
-          "var image = document.createElement('img'); "
-          "document.body.appendChild(image); image.src = '")
-          .append(kImagePrefix)
-          .append(".png';");
-  ASSERT_TRUE(content::ExecuteScript(contents(), create_image_script));
-
-  // Previous image should be allowed to load now.
-  ClickInfoBarLink();
-
-  // An image should be fetched because subresource loading was paused then
-  // resumed.
-  if (images_attempted() < 1u)
-    WaitForRequest();
-  EXPECT_EQ(1u, images_attempted());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest, PageLoadCappingAllowLoads) {
-  // Tests that the image request loads normally when the page has not been
-  // paused.
-
-  EnableDataSaver(true);
-  // Load a mostly empty page.
-  NavigateToHeavyPage();
-
-  // Adds an image to the page. It should be allowed to load.
-  std::string create_image_script =
-      std::string(
-          "var image = document.createElement('img'); "
-          "document.body.appendChild(image); image.src = '")
-          .append(kImagePrefix)
-          .append(".png';");
-  ASSERT_TRUE(content::ExecuteScript(contents(), create_image_script));
-
-  // An image should be fetched because subresource loading was never paused.
-  if (images_attempted() < 1u)
-    WaitForRequest();
-  EXPECT_EQ(1u, images_attempted());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest,
-                       PageLoadCappingBlockNewFrameLoad) {
-  // Tests that the image request loads normally when the page has not been
-  // paused.
-
-  EnableDataSaver(true);
-  // Load a mostly empty page.
-  NavigateToHeavyPage();
-  // Pause subresource loading.
-  ClickInfoBarLink();
-  content::TestNavigationObserver load_observer(contents());
-
-  // Adds an image to the page. It should be allowed to load.
-  std::string create_iframe_script = std::string(
-      "var iframe = document.createElement('iframe');"
-      "var html = '<body>NewFrame</body>';"
-      "iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);"
-      "document.body.appendChild(iframe);");
-  content::ExecuteScriptAsync(contents(), create_iframe_script);
-
-  // Make sure the DidFinishNavigation occured.
-  load_observer.Wait();
-  PostToSelf();
-
-  size_t j = 0;
-  for (auto* frame : contents()->GetAllFrames()) {
-    for (size_t i = 0; i < 20; ++i) {
-      std::string create_image_script =
-          std::string(
-              "var image = document.createElement('img'); "
-              "document.body.appendChild(image); image.src = '")
-              .append(GetURL(std::string(kImagePrefix)
-                                 .append(base::NumberToString(++j))
-                                 .append(".png';"))
-                          .spec());
-
-      EXPECT_TRUE(content::ExecuteScript(frame, create_image_script));
-    }
-  }
-
-  // An image should not be fetched because subresource loading was paused in
-  // both frames.
-  EXPECT_EQ(0u, images_attempted());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest,
-                       PageLoadCappingBlockNewFrameLoadResume) {
-  // Tests that the image request loads normally when the page has not been
-  // paused.
-
-  EnableDataSaver(true);
-  // Load a mostly empty page.
-  NavigateToHeavyPage();
-  // Pause subresource loading.
-  ClickInfoBarLink();
-  content::TestNavigationObserver load_observer(contents());
-
-  // Adds an image to the page. It should be allowed to load.
-  std::string create_iframe_script = std::string(
-      "var iframe = document.createElement('iframe');"
-      "var html = '<body>NewFrame</body>';"
-      "iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);"
-      "document.body.appendChild(iframe);");
-  content::ExecuteScriptAsync(contents(), create_iframe_script);
-
-  // Make sure the DidFinishNavigation occured.
-  load_observer.Wait();
-  PostToSelf();
-
-  for (auto* frame : contents()->GetAllFrames()) {
-    if (contents()->GetMainFrame() == frame)
-      continue;
-    std::string create_image_script =
-        std::string(
-            "var image = document.createElement('img'); "
-            "document.body.appendChild(image); image.src = '")
-            .append(GetURL(std::string(kImagePrefix).append(".png';")).spec());
-    ASSERT_TRUE(content::ExecuteScript(frame, create_image_script));
-  }
-
-  // An image should not be fetched because subresource loading was paused in
-  // both frames.
-  EXPECT_EQ(0u, images_attempted());
-
-  // Previous image should be allowed to load now.
-  ClickInfoBarLink();
-
-  // An image should be fetched because subresource loading was resumed.
-  if (images_attempted() < 1u)
-    WaitForRequest();
-  EXPECT_EQ(1u, images_attempted());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest,
-                       PageLoadCappingInfobarShownAfterSamePageNavigation) {
-  // Verifies that same page navigations do not dismiss the InfoBar.
-
-  EnableDataSaver(true);
-  // Load a page.
-  NavigateToHeavyPage();
-
-  ASSERT_EQ(1u, InfoBarCount());
-  infobars::InfoBar* infobar =
-      InfoBarService::FromWebContents(contents())->infobar_at(0);
-
-  // Navigate on the page to an anchor.
-  NavigateToHeavyPageAnchor("#anchor");
-
-  EXPECT_EQ(1u, InfoBarCount());
-  EXPECT_EQ(infobar,
-            InfoBarService::FromWebContents(contents())->infobar_at(0));
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest,
-                       PageLoadCappingInfoBarNotShownAfterBlacklisted) {
-  // Verifies the blacklist prevents over-showing the InfoBar.
-
-  EnableDataSaver(true);
-  // Load a page and ignore the InfoBar.
-  NavigateToHeavyPage();
-  ASSERT_EQ(1u, InfoBarCount());
-
-  // Load a page and ignore the InfoBar.
-  NavigateToHeavyPage();
-  ASSERT_EQ(1u, InfoBarCount());
-
-  // Load a page and due to session policy blacklisting, the InfoBar should not
-  // show.
-  NavigateToHeavyPage();
-  ASSERT_EQ(0u, InfoBarCount());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest,
-                       NavigationDataRemovedFromBlacklist) {
-  // Verifies that clearing browsing data resets blacklist rules.
-
-  EnableDataSaver(true);
-  // Load a page and ignore the InfoBar.
-  NavigateToHeavyPage();
-  ASSERT_EQ(1u, InfoBarCount());
-
-  // Load a page and ignore the InfoBar.
-  NavigateToHeavyPage();
-  ASSERT_EQ(1u, InfoBarCount());
-
-  // Load a page and due to session policy blacklisting, the InfoBar should not
-  // show.
-  NavigateToHeavyPage();
-  ASSERT_EQ(0u, InfoBarCount());
-
-  // Clear the navigation history.
-  content::BrowserContext::GetBrowsingDataRemover(browser()->profile())
-      ->Remove(base::Time(), base::Time::Max(),
-               ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY,
-               content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB);
-
-  // After clearing history, the InfoBar should be allowed again.
-  NavigateToHeavyPage();
-  EXPECT_EQ(1u, InfoBarCount());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest, IncognitoTest) {
-  // Verifies the InfoBar is not shown in incognito.
-
-  EnableDataSaver(true);
-  auto* browser = CreateIncognitoBrowser();
-
-  // Navigate to the page.
-  NavigateToHeavyPageAnchorInBrowser(browser, std::string());
-
-  EXPECT_EQ(0u, InfoBarService::FromWebContents(
-                    browser->tab_strip_model()->GetActiveWebContents())
-                    ->infobar_count());
-}
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTest, DataSaverOffTest) {
-  // Verifies that non-data saver users do not see the InfoBar.
-
-  // Navigate to the page.
-  NavigateToHeavyPage();
-
-  EXPECT_EQ(0u, InfoBarCount());
-}
-
-class PageLoadCappingBrowserTestDismissAfterNetworkUse
-    : public PageLoadCappingBrowserTest {
- public:
-  PageLoadCappingBrowserTestDismissAfterNetworkUse() {}
-  ~PageLoadCappingBrowserTestDismissAfterNetworkUse() override {}
-
-  void ChangeParams(std::map<std::string, std::string>* params) override {
-    (*params)["InfoBarTimeoutInMilliseconds"] = "50";
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(PageLoadCappingBrowserTestDismissAfterNetworkUse,
-                       TestInfoBarDismiss) {
-  // Verifies the InfoBar dismisses shortly (5ms) after the last resource is
-  // loaded.
-  EnableDataSaver(true);
-
-  base::HistogramTester histogram_tester;
-
-  // Load a page and ignore the InfoBar.
-  NavigateToHeavyPage();
-
-  // Verify the InfoBar was shown (it might be dismissed already by the
-  // InfoBarTimeout logic).
-  histogram_tester.ExpectBucketCount("HeavyPageCapping.InfoBarInteraction", 0,
-                                     1);
-  bool is_dismissed = histogram_tester.GetBucketCount(
-                          "HeavyPageCapping.InfoBarInteraction", 3) > 0;
-  if (!is_dismissed) {
-    ASSERT_EQ(1u, InfoBarCount());
-    WaitForInfoBarRemoved();
-  }
-
-  histogram_tester.ExpectBucketCount("HeavyPageCapping.InfoBarInteraction", 3,
-                                     1);
-
-  ASSERT_EQ(0u, InfoBarCount());
-}
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.cc
deleted file mode 100644
index e29d89dd..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.cc
+++ /dev/null
@@ -1,191 +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 "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram_macros.h"
-#include "build/build_config.h"
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/infobars/core/infobar.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace {
-
-void RecordInteractionUMA(
-    PageLoadCappingInfoBarDelegate::InfoBarInteraction interaction) {
-  UMA_HISTOGRAM_ENUMERATION("HeavyPageCapping.InfoBarInteraction", interaction);
-}
-
-// The infobar that allows the user to resume resource loading on the page.
-class ResumeDelegate : public PageLoadCappingInfoBarDelegate {
- public:
-  // |pause_callback| will either pause subresource loading or resume it based
-  // on the passed in bool.
-  explicit ResumeDelegate(const PauseCallback& pause_callback)
-      : pause_callback_(pause_callback) {
-    DCHECK(!pause_callback_.is_null());
-  }
-  ~ResumeDelegate() override = default;
-
- private:
-  // PageLoadCappingInfoBarDelegate:
-  base::string16 GetMessageText() const override {
-    return l10n_util::GetStringUTF16(IDS_PAGE_CAPPING_STOPPED_TITLE);
-  }
-  base::string16 GetLinkText() const override {
-    return l10n_util::GetStringUTF16(IDS_PAGE_CAPPING_CONTINUE_MESSAGE);
-  }
-  bool LinkClicked(WindowOpenDisposition disposition) override {
-    RecordInteractionUMA(InfoBarInteraction::kResumedPage);
-    // Pass false to resume subresource loading.
-    pause_callback_.Run(false);
-    return true;
-  }
-
-  // |pause_callback| will either pause subresource loading or resume it based
-  // on the passed in bool.
-  const PauseCallback pause_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(ResumeDelegate);
-};
-
-// The infobar that allows the user to pause resoruce loading on the page.
-class PauseDelegate : public PageLoadCappingInfoBarDelegate {
- public:
-  // This object is destroyed when the page is terminated, and methods related
-  // to functionality of the InfoBar (E.g., LinkClicked()), are not called from
-  // page destructors. This object is also destroyed on all non-same page
-  // navigations.
-  // |pause_callback| is a callback that will pause subresource loading on the
-  // page.
-  // |time_to_expire_callback| is used to get the earliest time at which the
-  // page is considered to have stopped using data.
-  explicit PauseDelegate(const PauseCallback& pause_callback,
-                         const TimeToExpireCallback& time_to_expire_callback)
-      : pause_callback_(pause_callback),
-        time_to_expire_callback_(time_to_expire_callback),
-        weak_factory_(this) {
-    // When creating the InfoBar, it should not already be expired.
-    DCHECK(!time_to_expire_callback_.is_null());
-    DCHECK(!pause_callback_.is_null());
-    base::TimeDelta time_to_expire;
-    time_to_expire_callback_.Run(&time_to_expire);
-    RunDelayedCheck(time_to_expire);
-  }
-  ~PauseDelegate() override = default;
-
- private:
-  // PageLoadCappingInfoBarDelegate:
-  base::string16 GetMessageText() const override {
-    return l10n_util::GetStringUTF16(IDS_PAGE_CAPPING_TITLE);
-  }
-
-  base::string16 GetLinkText() const override {
-    return l10n_util::GetStringUTF16(IDS_PAGE_CAPPING_STOP_MESSAGE);
-  }
-
-  bool LinkClicked(WindowOpenDisposition disposition) override {
-    RecordInteractionUMA(InfoBarInteraction::kPausedPage);
-
-      // Pause subresouce loading on the page.
-      pause_callback_.Run(true);
-
-    auto* infobar_manager = infobar()->owner();
-    // |this| will be gone after this call.
-    infobar_manager->ReplaceInfoBar(
-        infobar(), infobar_manager->CreateConfirmInfoBar(
-                       std::make_unique<ResumeDelegate>(pause_callback_)));
-
-    return false;
-  }
-
-  void RunDelayedCheck(base::TimeDelta time_to_expire) {
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&PauseDelegate::ExpireIfNecessary,
-                       weak_factory_.GetWeakPtr()),
-        time_to_expire);
-  }
-
-  void ExpireIfNecessary() {
-    base::TimeDelta time_to_expire;
-    time_to_expire_callback_.Run(&time_to_expire);
-
-    // When the owner of |time_to_expire_callback_| is deleted, or it returns a
-    // TimeDelta of 0, the InfoBar should be deleted. Otherwise, re-evaluate
-    // after |time_to_expire|.
-    if (time_to_expire > base::TimeDelta()) {
-      RunDelayedCheck(time_to_expire);
-      return;
-    }
-
-    RecordInteractionUMA(InfoBarInteraction::kDismissedByNetworkStopped);
-
-    // |this| will be gone after this call.
-    infobar()->RemoveSelf();
-  }
-
-  // |pause_callback| will either pause subresource loading or resume it based
-  // on the passed in bool.
-  const PauseCallback pause_callback_;
-
-  // Used to get the earliest time at which the page is considered to have
-  // stopped using data.
-  const TimeToExpireCallback time_to_expire_callback_;
-
-  base::WeakPtrFactory<PauseDelegate> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(PauseDelegate);
-};
-
-}  // namespace
-
-// static
-bool PageLoadCappingInfoBarDelegate::Create(
-    content::WebContents* web_contents,
-    const PauseCallback& pause_callback,
-    const TimeToExpireCallback& time_to_expire_callback) {
-  auto* infobar_service = InfoBarService::FromWebContents(web_contents);
-  RecordInteractionUMA(InfoBarInteraction::kShowedInfoBar);
-  // WrapUnique is used to allow for a private constructor.
-  return infobar_service->AddInfoBar(
-      infobar_service->CreateConfirmInfoBar(std::make_unique<PauseDelegate>(
-          pause_callback, time_to_expire_callback)));
-}
-
-PageLoadCappingInfoBarDelegate::~PageLoadCappingInfoBarDelegate() = default;
-
-PageLoadCappingInfoBarDelegate::PageLoadCappingInfoBarDelegate() = default;
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-PageLoadCappingInfoBarDelegate::GetIdentifier() const {
-  return PAGE_LOAD_CAPPING_INFOBAR_DELEGATE;
-}
-
-int PageLoadCappingInfoBarDelegate::GetIconId() const {
-// TODO(ryansturm): Make data saver resources available on other platforms.
-// https://crbug.com/820594
-#if defined(OS_ANDROID)
-  return IDR_ANDROID_INFOBAR_PREVIEWS;
-#else
-  return kNoIconID;
-#endif
-}
-
-bool PageLoadCappingInfoBarDelegate::ShouldExpire(
-    const NavigationDetails& details) const {
-  return details.is_navigation_to_different_page;
-}
-
-int PageLoadCappingInfoBarDelegate::GetButtons() const {
-  return BUTTON_NONE;
-}
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h
deleted file mode 100644
index d5a6394..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_INFOBAR_DELEGATE_H_
-
-#include <stdint.h>
-
-#include "base/strings/string16.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-
-namespace content {
-class WebContents;
-}  // namespace content
-
-// An InfoBar delegate for page load capping. This sets up the correct
-// strings for both the InfoBar that allows the user to pause the resource
-// loading and the InfoBar that allows the user to resume resource loading. When
-// the button in the pause InfoBar is clicked, the Resume InfoBar is shown and
-// the resource loading is paused. When the button in the resume InfoBar is
-// clicked, the resume InfoBar is dismissed, and resources continue to load.
-//
-// Page load capping is a feature that informs users when a page goes beyond a
-// certain amount of network bytes and presents the user an option to pause
-// resource loading on the page until the user chooses to resume resource
-// loading.
-//
-// This class cannot be created directly, but an instance can be created using
-// Create().
-class PageLoadCappingInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // A callback that triggers the page to have its subresource loading paused or
-  // resumed based on |pause|.
-  using PauseCallback = base::RepeatingCallback<void(bool pause)>;
-
-  // A callback used to get the earliest possible time (offset from now) that
-  // the InfoBar could be dismissed based on lack of network usage.
-  // |time_to_expire| must be passed in as TimeDelta initialized to 0 to handle
-  // the case of the underlying weak pointer being destroyed.
-  using TimeToExpireCallback =
-      base::RepeatingCallback<void(base::TimeDelta* time_to_expire)>;
-
-  // Creates an InfoBar for page load capping. Returns whether the InfoBar was
-  // created. |web_contents| is the WebContents that caused the data usage.
-  // |pause_callback| is used to pause and unpause the resource loading of the
-  // page. |time_to_expire_callback| is used to get the earliest time at which
-  // the page is considered to have stopped using data.
-  static bool Create(content::WebContents* web_contents,
-                     const PauseCallback& pause_callback,
-                     const TimeToExpireCallback& time_to_expire_callback);
-
-  ~PageLoadCappingInfoBarDelegate() override;
-
-  // Used to record UMA on user interaction with the capping heavy pages
-  // InfoBar.
-  enum class InfoBarInteraction {
-    kShowedInfoBar = 0,
-    kPausedPage = 1,
-    kResumedPage = 2,
-    kDismissedByNetworkStopped = 3,
-    kMaxValue = kDismissedByNetworkStopped,
-  };
-
- protected:
-  PageLoadCappingInfoBarDelegate();
-
- private:
-  // ConfirmInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  int GetButtons() const override;
-  bool ShouldExpire(const NavigationDetails& details) const override;
-  base::string16 GetMessageText() const override = 0;
-  bool LinkClicked(WindowOpenDisposition disposition) override = 0;
-  base::string16 GetLinkText() const override = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(PageLoadCappingInfoBarDelegate);
-};
-
-#endif  // CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc
deleted file mode 100644
index f10059c..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc
+++ /dev/null
@@ -1,113 +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 "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/infobars/mock_infobar_service.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar.h"
-#include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace {
-// A test URL used for simulated navigations that do not trigger real URL
-// requests.
-const char kTestURL[] = "http://www.test.com";
-}  // namespace
-
-class PageLoadCappingInfoBarDelegateTest
-    : public ChromeRenderViewHostTestHarness {
- public:
-  PageLoadCappingInfoBarDelegateTest() = default;
-  ~PageLoadCappingInfoBarDelegateTest() override = default;
-
-  void SetUpTest() {
-    MockInfoBarService::CreateForWebContents(web_contents());
-    NavigateAndCommit(GURL(kTestURL));
-  }
-
-  size_t InfoBarCount() { return infobar_service()->infobar_count(); }
-
-  void RemoveAllInfoBars() { infobar_service()->RemoveAllInfoBars(false); }
-
-  infobars::InfoBar* infobar_at(size_t index) {
-    return infobar_service()->infobar_at(index);
-  }
-
-  InfoBarService* infobar_service() {
-    return InfoBarService::FromWebContents(web_contents());
-  }
-
-  void PauseSubresourceLoading(bool pause) {
-    pause_subresource_loading_count_++;
-  }
-
- protected:
-  size_t pause_subresource_loading_count_ = 0;
-};
-
-TEST_F(PageLoadCappingInfoBarDelegateTest, ClickingCreatesNewInfobar) {
-  SetUpTest();
-
-  base::HistogramTester histogram_tester;
-
-  histogram_tester.ExpectTotalCount("HeavyPageCapping.InfoBarInteraction", 0);
-  EXPECT_TRUE(PageLoadCappingInfoBarDelegate::Create(
-      web_contents(),
-      base::BindRepeating(
-          &PageLoadCappingInfoBarDelegateTest::PauseSubresourceLoading,
-          base::Unretained(this)),
-      base::DoNothing()));
-  histogram_tester.ExpectUniqueSample(
-      "HeavyPageCapping.InfoBarInteraction",
-      PageLoadCappingInfoBarDelegate::InfoBarInteraction::kShowedInfoBar, 1);
-
-  EXPECT_EQ(1u, InfoBarCount());
-  infobars::InfoBar* infobar = infobar_at(0);
-  EXPECT_TRUE(infobar);
-  ConfirmInfoBarDelegate* delegate = nullptr;
-  if (infobar)
-    delegate = infobar->delegate()->AsConfirmInfoBarDelegate();
-  EXPECT_TRUE(delegate);
-  // Make sure this is pause delegate.
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_CAPPING_STOP_MESSAGE),
-            delegate->GetLinkText());
-  // |delegate| and |infobar| will be deleted by this call.
-  EXPECT_FALSE(delegate->LinkClicked(WindowOpenDisposition::CURRENT_TAB));
-  EXPECT_EQ(1u, InfoBarCount());
-  EXPECT_EQ(1u, pause_subresource_loading_count_);
-
-  histogram_tester.ExpectBucketCount(
-      "HeavyPageCapping.InfoBarInteraction",
-      PageLoadCappingInfoBarDelegate::InfoBarInteraction::kPausedPage, 1);
-  histogram_tester.ExpectTotalCount("HeavyPageCapping.InfoBarInteraction", 2);
-
-  infobar = infobar_at(0);
-  ConfirmInfoBarDelegate* stopped_delegate = nullptr;
-  if (infobar)
-    stopped_delegate = infobar->delegate()->AsConfirmInfoBarDelegate();
-
-  // Make sure this is the resume delegate.
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_CAPPING_CONTINUE_MESSAGE),
-            stopped_delegate->GetLinkText());
-  EXPECT_TRUE(stopped_delegate);
-  // Make sure that they are different infobar instances.
-  EXPECT_NE(delegate, stopped_delegate);
-
-  // If this is true, the infobar will be closed by the infobar manager.
-  EXPECT_TRUE(
-      stopped_delegate->LinkClicked(WindowOpenDisposition::CURRENT_TAB));
-  EXPECT_EQ(2u, pause_subresource_loading_count_);
-
-  histogram_tester.ExpectBucketCount(
-      "HeavyPageCapping.InfoBarInteraction",
-      PageLoadCappingInfoBarDelegate::InfoBarInteraction::kResumedPage, 1);
-  histogram_tester.ExpectTotalCount("HeavyPageCapping.InfoBarInteraction", 3);
-}
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.cc
deleted file mode 100644
index cb9c41ed..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.cc
+++ /dev/null
@@ -1,55 +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 "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h"
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/sequenced_task_runner.h"
-#include "base/task/post_task.h"
-#include "base/time/default_clock.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h"
-#include "chrome/common/chrome_constants.h"
-#include "components/blacklist/opt_out_blacklist/sql/opt_out_store_sql.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-
-// Whether an opt out store should be used or not.
-bool PageCappingOptOutStoreDisabled() {
-  return base::GetFieldTrialParamByFeatureAsBool(
-      data_use_measurement::page_load_capping::features::kDetectingHeavyPages,
-      "OptOutStoreDisabled", false);
-}
-
-PageLoadCappingService::PageLoadCappingService() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-}
-
-PageLoadCappingService::~PageLoadCappingService() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-}
-
-void PageLoadCappingService::Initialize(const base::FilePath& profile_path) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  std::unique_ptr<blacklist::OptOutStoreSQL> opt_out_store;
-
-  if (!PageCappingOptOutStoreDisabled()) {
-    // Get the background thread to run SQLite on.
-    scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-        base::CreateSequencedTaskRunnerWithTraits(
-            {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
-
-    opt_out_store = std::make_unique<blacklist::OptOutStoreSQL>(
-        base::CreateSingleThreadTaskRunnerWithTraits(
-            {content::BrowserThread::UI}),
-        background_task_runner,
-        profile_path.Append(chrome::kPageLoadCappingOptOutDBFilename));
-  }
-
-  page_load_capping_blacklist_ = std::make_unique<PageLoadCappingBlacklist>(
-      std::move(opt_out_store), base::DefaultClock::GetInstance(), this);
-}
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h
deleted file mode 100644
index be4dd73..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_SERVICE_H_
-#define CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_SERVICE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_blacklist_delegate.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-namespace base {
-class FilePath;
-}
-
-class PageLoadCappingBlacklist;
-
-// Keyed service that owns the page load capping blacklist.
-class PageLoadCappingService : public KeyedService,
-                               public blacklist::OptOutBlacklistDelegate {
- public:
-  PageLoadCappingService();
-  ~PageLoadCappingService() override;
-
-  // Initializes the UI Service. |profile_path| is the path to user data on
-  // disk.
-  void Initialize(const base::FilePath& profile_path);
-
-  PageLoadCappingBlacklist* page_load_capping_blacklist() const {
-    return page_load_capping_blacklist_.get();
-  }
-
- private:
-  // blacklist::OptOutBlacklistDelegate:
-  // TODO(ryansturm): Report page capping information to
-  // interventions-internals. https://crbug.com/797988
-  void OnNewBlacklistedHost(const std::string& host, base::Time time) override {
-  }
-  void OnUserBlacklistedStatusChange(bool blacklisted) override {}
-  void OnBlacklistCleared(base::Time time) override {}
-
-  // The blacklist used to control triggering of the page load capping feature.
-  // Created during Initialize().
-  std::unique_ptr<PageLoadCappingBlacklist> page_load_capping_blacklist_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageLoadCappingService);
-};
-
-#endif  // CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_SERVICE_H_
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.cc
deleted file mode 100644
index fab5a80..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.cc
+++ /dev/null
@@ -1,41 +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 "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.h"
-
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_context.h"
-
-namespace {
-
-base::LazyInstance<PageLoadCappingServiceFactory>::DestructorAtExit
-    g_previews_factory = LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-// static
-PageLoadCappingService* PageLoadCappingServiceFactory::GetForBrowserContext(
-    content::BrowserContext* context) {
-  return static_cast<PageLoadCappingService*>(
-      GetInstance()->GetServiceForBrowserContext(context, true));
-}
-
-// static
-PageLoadCappingServiceFactory* PageLoadCappingServiceFactory::GetInstance() {
-  return g_previews_factory.Pointer();
-}
-
-PageLoadCappingServiceFactory::PageLoadCappingServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "PageLoadCappingService",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-PageLoadCappingServiceFactory::~PageLoadCappingServiceFactory() {}
-
-KeyedService* PageLoadCappingServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new PageLoadCappingService();
-}
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.h b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.h
deleted file mode 100644
index 3e92392..0000000
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.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 CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_SERVICE_FACTORY_H_
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace content {
-class BrowserContext;
-}
-
-class PageLoadCappingService;
-
-// LazyInstance that owns all PageLoadCappingServices and associates them with
-// Profiles.
-class PageLoadCappingServiceFactory : public BrowserContextKeyedServiceFactory {
- public:
-  // Gets the PageLoadCappingService instance for |context|.
-  static PageLoadCappingService* GetForBrowserContext(
-      content::BrowserContext* context);
-
-  // Gets the LazyInstance that owns all PreviewsServices.
-  static PageLoadCappingServiceFactory* GetInstance();
-
- private:
-  friend struct base::LazyInstanceTraitsBase<PageLoadCappingServiceFactory>;
-
-  PageLoadCappingServiceFactory();
-  ~PageLoadCappingServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(PageLoadCappingServiceFactory);
-};
-
-#endif  // CHROME_BROWSER_DATA_USE_MEASUREMENT_PAGE_LOAD_CAPPING_PAGE_LOAD_CAPPING_SERVICE_FACTORY_H_
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
index 9aa0c4c..d87b11b 100644
--- a/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
+++ b/chrome/browser/extensions/api/browsing_data/browsing_data_test.cc
@@ -69,8 +69,10 @@
   network::mojom::CookieManager* cookie_manager =
       content::BrowserContext::GetDefaultStoragePartition(profile)
           ->GetCookieManagerForBrowserProcess();
+  net::CookieOptions options;
+  options.set_include_httponly();
   cookie_manager->SetCanonicalCookie(
-      cookie, google_url.scheme(), true,
+      cookie, google_url.scheme(), options,
       mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), false));
   loop.Run();
   return success;
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index 564eb04..75e1e015 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -368,8 +368,12 @@
   // Dispatch the setter, immediately followed by the getter.  This
   // plus FIFO ordering on the cookie_manager_ pipe means that no
   // other extension function will affect the get result.
+  net::CookieOptions options;
+  options.set_include_httponly();
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   cookie_manager->SetCanonicalCookie(
-      *cc, url_.scheme(), true /*modify_http_only*/,
+      *cc, url_.scheme(), options,
       base::BindOnce(&CookiesSetFunction::SetCanonicalCookieCallback, this));
   cookies_helpers::GetCookieListFromManager(
       cookie_manager, url_,
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
index 54c97d9..84bc8e2 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "chromeos/system/statistics_provider.h"
 #include "components/account_id/account_id.h"
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
index 1ade97a..958d221 100644
--- a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
@@ -15,8 +15,8 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/policy_constants.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 6bf3366..6a24dd4 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -4992,7 +4992,7 @@
     bool set_result = false;
     base::RunLoop run_loop;
     cookie_manager_ptr->SetCanonicalCookie(
-        *cc.get(), origin1.scheme(), true /* modify_http_only */,
+        *cc.get(), origin1.scheme(), net::CookieOptions(),
         base::BindOnce(&SetCookieSaveData, &set_result,
                        run_loop.QuitClosure()));
     run_loop.Run();
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 67c1253..bb3bc53 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3017,7 +3017,7 @@
   },
   {
     "name": "upcoming-ui-features",
-    // "owners": [ "your-team" ],
+    "owners": [ "robliao" ],
     "expiry_milestone": 76
   },
   {
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index 3b5980b..cf4e5b42 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -12,7 +12,6 @@
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "chrome/browser/banners/app_banner_infobar_delegate_desktop.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h"
 #include "chrome/browser/devtools/devtools_infobar_delegate.h"
 #include "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar.h"
 #include "chrome/browser/extensions/api/messaging/incognito_connectability_infobar_delegate.h"
@@ -229,7 +228,6 @@
       {"data_reduction_proxy_preview",
        IBD::DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE},
       {"automation", IBD::AUTOMATION_INFOBAR_DELEGATE},
-      {"page_load_capping", IBD::PAGE_LOAD_CAPPING_INFOBAR_DELEGATE},
       {"bloated_renderer", IBD::BLOATED_RENDERER_INFOBAR_DELEGATE},
       {"previews_lite_page", IBD::LITE_PAGE_PREVIEWS_INFOBAR},
   };
@@ -410,11 +408,6 @@
       AutomationInfoBarDelegate::Create();
       break;
 
-    case IBD::PAGE_LOAD_CAPPING_INFOBAR_DELEGATE:
-      PageLoadCappingInfoBarDelegate::Create(
-          GetWebContents(), base::DoNothing(), base::DoNothing());
-      break;
-
     case IBD::BLOATED_RENDERER_INFOBAR_DELEGATE:
       BloatedRendererTabHelper::ShowInfoBar(GetInfoBarService());
       break;
@@ -583,10 +576,6 @@
   ShowAndVerifyUi();
 }
 
-IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_page_load_capping) {
-  ShowAndVerifyUi();
-}
-
 IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_bloated_renderer) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/lifetime/termination_notification.cc b/chrome/browser/lifetime/termination_notification.cc
index 4ffc9f1b..d050efc9b 100644
--- a/chrome/browser/lifetime/termination_notification.cc
+++ b/chrome/browser/lifetime/termination_notification.cc
@@ -15,7 +15,7 @@
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_policy_controller.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/update_engine_client.h"
 #endif
 
diff --git a/chrome/browser/net/chrome_network_service_browsertest.cc b/chrome/browser/net/chrome_network_service_browsertest.cc
index 0941d01..a58ae066 100644
--- a/chrome/browser/net/chrome_network_service_browsertest.cc
+++ b/chrome/browser/net/chrome_network_service_browsertest.cc
@@ -48,7 +48,7 @@
                               net::COOKIE_PRIORITY_DEFAULT);
   base::RunLoop run_loop;
   cookie_manager->SetCanonicalCookie(
-      cookie, "http", false,
+      cookie, "http", net::CookieOptions(),
       base::BindLambdaForTesting([&](bool success) { run_loop.Quit(); }));
   run_loop.Run();
 }
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 68cd93f..f30dfb6 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -282,9 +282,6 @@
   UrlLanguageHistogram* language_histogram =
       UrlLanguageHistogramFactory::GetForBrowserContext(profile);
 
-  scoped_refptr<net::URLRequestContextGetter> request_context =
-      content::BrowserContext::GetDefaultStoragePartition(profile)
-          ->GetURLRequestContext();
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory =
       content::BrowserContext::GetDefaultStoragePartition(profile)
           ->GetURLLoaderFactoryForBrowserProcess();
diff --git a/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py b/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py
index 39e03980..d17b4547 100755
--- a/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py
+++ b/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py
@@ -112,7 +112,7 @@
   def get_adb_command(args):
     adb_path = os.path.join(
         build_dir_path,
-        '../../third_party/android_tools/sdk/platform-tools/adb')
+        '../../third_party/android_sdk/public/platform-tools/adb')
     if options.device_id != None:
       return [adb_path, '-s', options.device_id] + args
     return [adb_path] + args
diff --git a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc
deleted file mode 100644
index 97d28af..0000000
--- a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.cc
+++ /dev/null
@@ -1,374 +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 "chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/optional.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/time/default_tick_clock.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.h"
-#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-
-namespace {
-
-const char kMediaPageCap[] = "MediaPageCapMiB";
-const char kPageCap[] = "PageCapMiB";
-
-const char kMediaPageTypical[] = "MediaPageTypicalLargePageMiB";
-const char kPageTypical[] = "PageTypicalLargePageMiB";
-
-const char kPageFuzzing[] = "PageFuzzingKiB";
-
-const char kInfoBarTimeoutInMilliseconds[] = "InfoBarTimeoutInMilliseconds";
-
-// The page load capping bytes threshold for the page. There are seperate
-// thresholds for media and non-media pages. Returns empty optional if the
-// page should not be capped.
-base::Optional<int64_t> GetPageLoadCappingBytesThreshold(bool media_page_load) {
-  if (!base::FeatureList::IsEnabled(data_use_measurement::page_load_capping::
-                                        features::kDetectingHeavyPages)) {
-    return base::nullopt;
-  }
-  // Defaults are 15 MiB for media and 5 MiB for non-media.
-  int64_t default_cap_mib = media_page_load ? 15 : 5;
-  return base::GetFieldTrialParamByFeatureAsInt(
-             data_use_measurement::page_load_capping::features::
-                 kDetectingHeavyPages,
-             (media_page_load ? kMediaPageCap : kPageCap), default_cap_mib) *
-         1024 * 1024;
-}
-
-// Provides an estimate of savings based on the typical size of page loads above
-// the capping thresholds.
-int64_t GetEstimatedSavings(int64_t network_bytes,
-                            int64_t threshold,
-                            bool media_page_load) {
-  // These are estimated by the median size page above the capping threshold
-  int64_t typical_size =
-      base::GetFieldTrialParamByFeatureAsInt(
-          data_use_measurement::page_load_capping::features::
-              kDetectingHeavyPages,
-          (media_page_load ? kMediaPageTypical : kPageTypical), 0) *
-      1024 * 1024;
-  if (typical_size == 0) {
-    // Defaults are capping thresholds inflated 50 percent.
-    typical_size = threshold * 1.5;
-  }
-  // If this page load already exceeded the typical page load size, report 0
-  // savings.
-  return std::max<int64_t>((typical_size - network_bytes), 0);
-}
-
-base::TimeDelta GetPageLoadCappingTimeout() {
-  return base::TimeDelta::FromMilliseconds(
-      base::GetFieldTrialParamByFeatureAsInt(
-          data_use_measurement::page_load_capping::features::
-              kDetectingHeavyPages,
-          kInfoBarTimeoutInMilliseconds, 8000));
-}
-
-}  // namespace
-
-PageCappingPageLoadMetricsObserver::PageCappingPageLoadMetricsObserver()
-    : clock_(base::DefaultTickClock::GetInstance()), weak_factory_(this) {}
-PageCappingPageLoadMetricsObserver::~PageCappingPageLoadMetricsObserver() {}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-PageCappingPageLoadMetricsObserver::OnCommit(
-    content::NavigationHandle* navigation_handle,
-    ukm::SourceId source_id) {
-  last_data_use_time_ = clock_->NowTicks();
-  page_cap_ = GetPageLoadCappingBytesThreshold(false /* media_page_load */);
-  url_host_ = navigation_handle->GetURL().host();
-  fuzzing_offset_ = GetFuzzingOffset();
-
-  MaybeCreate();
-  // TODO(ryansturm) Check a blacklist of eligible pages.
-  // https://crbug.com/797981
-  return page_load_metrics::PageLoadMetricsObserver::CONTINUE_OBSERVING;
-}
-
-void PageCappingPageLoadMetricsObserver::OnResourceDataUseObserved(
-    FrameTreeNodeId frame_tree_node_id,
-    const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
-        resources) {
-  last_data_use_time_ = clock_->NowTicks();
-  for (auto const& resource : resources)
-    network_bytes_ += resource->delta_bytes;
-
-  DCHECK_LE(0u, network_bytes_);
-  MaybeCreate();
-}
-
-void PageCappingPageLoadMetricsObserver::MaybeCreate() {
-  // If the InfoBar has already been shown for the page, don't show an InfoBar.
-  if (page_capping_state_ != PageCappingState::kInfoBarNotShown)
-    return;
-
-  // If the page has not committed, don't show an InfoBar.
-  if (!GetDelegate()->DidCommit())
-    return;
-
-  // If there is no capping threshold or the threshold is not met, do not show
-  // an InfoBar. Use the fuzzing offset to increase the number of bytes needed.
-  if (!page_cap_ || (network_bytes_ - fuzzing_offset_) < page_cap_.value())
-    return;
-
-  if (IsBlacklisted())
-    return;
-
-  // Set the state preemptively in case one of the callbacks is called
-  // synchronously, if the InfoBar is not created, set it back.
-  page_capping_state_ = PageCappingState::kInfoBarShown;
-  if (!PageLoadCappingInfoBarDelegate::Create(
-          GetDelegate()->GetWebContents(),
-          base::BindRepeating(
-              &PageCappingPageLoadMetricsObserver::PauseSubresourceLoading,
-              weak_factory_.GetWeakPtr()),
-          base::BindRepeating(&PageCappingPageLoadMetricsObserver::TimeToExpire,
-                              weak_factory_.GetWeakPtr()))) {
-    page_capping_state_ = PageCappingState::kInfoBarNotShown;
-  }
-}
-
-void PageCappingPageLoadMetricsObserver::MediaStartedPlaying(
-    const content::WebContentsObserver::MediaPlayerInfo& video_type,
-    content::RenderFrameHost* render_frame_host) {
-  media_page_load_ = true;
-  page_cap_ = GetPageLoadCappingBytesThreshold(true /* media_page_load */);
-}
-
-void PageCappingPageLoadMetricsObserver::OnDidFinishSubFrameNavigation(
-    content::NavigationHandle* navigation_handle,
-    const page_load_metrics::PageLoadExtraInfo& extra_info) {
-  // If the page is not paused, there is no need to pause new frames.
-  if (page_capping_state_ != PageCappingState::kPagePaused)
-    return;
-  // If the navigation is to the same page, is to an error page, the load hasn't
-  // committed or render frame host is null, no need to pause the page.
-  if (navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage() ||
-      !navigation_handle->HasCommitted() ||
-      !navigation_handle->GetRenderFrameHost()) {
-    return;
-  }
-  // Pause the new frame.
-  handles_.push_back(
-      navigation_handle->GetRenderFrameHost()->PauseSubresourceLoading());
-}
-
-void PageCappingPageLoadMetricsObserver::PauseSubresourceLoading(bool pause) {
-  DCHECK((pause && page_capping_state_ == PageCappingState::kInfoBarShown) ||
-         (!pause && page_capping_state_ == PageCappingState::kPagePaused));
-  page_capping_state_ =
-      pause ? PageCappingState::kPagePaused : PageCappingState::kPageResumed;
-  if (pause)
-    handles_ = GetDelegate()->GetWebContents()->PauseSubresourceLoading();
-  else
-    handles_.clear();
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-PageCappingPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
-    const page_load_metrics::mojom::PageLoadTiming& timing,
-    const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordDataSavingsAndUKM(info);
-  return CONTINUE_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-PageCappingPageLoadMetricsObserver::OnHidden(
-    const page_load_metrics::mojom::PageLoadTiming& timing,
-    const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordDataSavingsAndUKM(info);
-  return CONTINUE_OBSERVING;
-}
-
-void PageCappingPageLoadMetricsObserver::OnComplete(
-    const page_load_metrics::mojom::PageLoadTiming& timing,
-    const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordDataSavingsAndUKM(info);
-  ReportOptOut();
-  if (page_capping_state_ == PageCappingState::kPagePaused) {
-    PAGE_BYTES_HISTOGRAM("HeavyPageCapping.RecordedDataSavings",
-                         recorded_savings_);
-  }
-}
-
-void PageCappingPageLoadMetricsObserver::RecordDataSavingsAndUKM(
-    const page_load_metrics::PageLoadExtraInfo& info) {
-  // If the InfoBar was never shown, don't report savings or UKM.
-  if (page_capping_state_ == PageCappingState::kInfoBarNotShown) {
-    DCHECK_EQ(0, recorded_savings_);
-    return;
-  }
-
-  if (!ukm_recorded_) {
-    ukm::builders::PageLoadCapping builder(info.source_id);
-    builder.SetFinalState(static_cast<int64_t>(page_capping_state_));
-    builder.Record(ukm::UkmRecorder::Get());
-    ukm_recorded_ = true;
-  }
-  // If the InfoBar was shown, but not acted upon, don't update savings.
-  if (page_capping_state_ == PageCappingState::kInfoBarShown) {
-    DCHECK_EQ(0, recorded_savings_);
-    return;
-  }
-
-  // If the user resumed, we may need to update the savings.
-  if (page_capping_state_ == PageCappingState::kPageResumed) {
-    // No need to undo savings if no savings were previously recorded.
-    if (recorded_savings_ == 0)
-      return;
-    // Undo previous savings since the page was resumed.
-    WriteToSavings(-1 * recorded_savings_);
-    recorded_savings_ = 0;
-    return;
-  }
-
-  DCHECK_EQ(PageCappingState::kPagePaused, page_capping_state_);
-
-  int64_t estimated_savings =
-      GetEstimatedSavings(network_bytes_, page_cap_.value(), media_page_load_);
-  // Record an update to the savings. |recorded_savings_| is generally larger
-  // than |estimated_savings| when called a second time.
-  WriteToSavings(estimated_savings - recorded_savings_);
-
-  recorded_savings_ = estimated_savings;
-}
-
-void PageCappingPageLoadMetricsObserver::WriteToSavings(int64_t bytes_saved) {
-  data_reduction_proxy::DataReductionProxySettings*
-      data_reduction_proxy_settings =
-          DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-              GetDelegate()->GetWebContents()->GetBrowserContext());
-
-  bool data_saver_enabled =
-      data_reduction_proxy_settings->IsDataReductionProxyEnabled();
-
-  data_reduction_proxy_settings->data_reduction_proxy_service()
-      ->UpdateDataUseForHost(0, bytes_saved, url_host_);
-
-  data_reduction_proxy_settings->data_reduction_proxy_service()
-      ->UpdateContentLengths(0, bytes_saved, data_saver_enabled,
-                             data_reduction_proxy::HTTPS, "text/html", true,
-                             data_use_measurement::DataUseUserData::OTHER, 0);
-}
-
-int64_t PageCappingPageLoadMetricsObserver::GetFuzzingOffset() const {
-  if (!base::FeatureList::IsEnabled(data_use_measurement::page_load_capping::
-                                        features::kDetectingHeavyPages)) {
-    return 0;
-  }
-  // Default is is 75 KiB.
-  int cap_kib = 75;
-
-  cap_kib = base::GetFieldTrialParamByFeatureAsInt(
-      data_use_measurement::page_load_capping::features::kDetectingHeavyPages,
-      kPageFuzzing, cap_kib);
-
-  int cap_bytes = cap_kib * 1024;
-
-  return base::RandInt(0, cap_bytes);
-}
-
-bool PageCappingPageLoadMetricsObserver::IsPausedForTesting() const {
-  return page_capping_state_ == PageCappingState::kPagePaused;
-}
-
-void PageCappingPageLoadMetricsObserver::ReportOptOut() {
-  if (page_capping_state_ == PageCappingState::kInfoBarNotShown)
-    return;
-  auto* blacklist = GetPageLoadCappingBlacklist();
-  if (!blacklist)
-    return;
-  // Opt outs are when the InfoBar is shown and either ignored or clicked
-  // through twice to resume the page. Currently, reloads are not treated as opt
-  // outs.
-  blacklist->AddEntry(
-      url_host_, page_capping_state_ != PageCappingState::kPagePaused,
-      static_cast<int>(PageCappingBlacklistType::kPageCappingOnlyType));
-}
-
-bool PageCappingPageLoadMetricsObserver::IsBlacklisted() {
-  if (blacklisted_)
-    return blacklisted_.value();
-
-  DCHECK_EQ(PageCappingState::kInfoBarNotShown, page_capping_state_);
-  auto* blacklist = GetPageLoadCappingBlacklist();
-  // Treat incognito profiles as blacklisted.
-  if (!blacklist) {
-    blacklisted_ = true;
-    return true;
-  }
-  std::vector<blacklist::BlacklistReason> passed_reasons;
-  auto blacklist_reason = blacklist->IsLoadedAndAllowed(
-      url_host_,
-      static_cast<int>(PageCappingBlacklistType::kPageCappingOnlyType), false,
-      &passed_reasons);
-  UMA_HISTOGRAM_ENUMERATION("HeavyPageCapping.BlacklistReason",
-                            blacklist_reason);
-  blacklisted_ = (blacklist_reason != blacklist::BlacklistReason::kAllowed);
-
-  return blacklisted_.value();
-}
-
-PageLoadCappingBlacklist*
-PageCappingPageLoadMetricsObserver::GetPageLoadCappingBlacklist() const {
-  auto* data_reduction_proxy_settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-          GetDelegate()->GetWebContents()->GetBrowserContext());
-
-  if (!data_reduction_proxy_settings ||
-      !data_reduction_proxy_settings->IsDataReductionProxyEnabled()) {
-    return nullptr;
-  }
-
-  auto* page_capping_service =
-      PageLoadCappingServiceFactory::GetForBrowserContext(
-          GetDelegate()->GetWebContents()->GetBrowserContext());
-  if (!page_capping_service)
-    return nullptr;
-
-  return page_capping_service->page_load_capping_blacklist();
-}
-
-void PageCappingPageLoadMetricsObserver::TimeToExpire(
-    base::TimeDelta* time_to_expire) const {
-  DCHECK(time_to_expire);
-  DCHECK_EQ(*time_to_expire, base::TimeDelta());
-  DCHECK_EQ(PageCappingState::kInfoBarShown, page_capping_state_);
-  DCHECK(last_data_use_time_);
-  auto expiration_time =
-      (last_data_use_time_.value() + GetPageLoadCappingTimeout());
-  if (expiration_time < clock_->NowTicks())
-    return;
-
-  *time_to_expire = expiration_time - clock_->NowTicks();
-}
-
-void PageCappingPageLoadMetricsObserver::SetTickClockForTesting(
-    base::TickClock* clock) {
-  clock_ = clock;
-}
diff --git a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h
deleted file mode 100644
index 2509853..0000000
--- a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_PAGE_CAPPING_PAGE_LOAD_METRICS_OBSERVER_H_
-#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_PAGE_CAPPING_PAGE_LOAD_METRICS_OBSERVER_H_
-
-#include <memory>
-#include <vector>
-
-#include <stdint.h>
-
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
-#include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h"
-
-class PageLoadCappingBlacklist;
-
-// A class that tracks the data usage of a page load and triggers an infobar
-// when the page load is above a certain threshold. The thresholds are field
-// trial controlled and vary based on whether media has played on the page.
-// TODO(ryansturm): This class can change the functionality of the page itself
-// through pausing subresource loading (by owning a collection of
-// PauseSubResourceLoadingHandlePtr's). This type of behavior is typically not
-// seen in page load metrics observers, but the PageLoadTracker functionality
-// (request data usage) is necessary for determining triggering conditions.
-// Consider moving to a WebContentsObserver/TabHelper and source byte updates
-// from this class to that observer. https://crbug.com/840399
-class PageCappingPageLoadMetricsObserver
-    : public page_load_metrics::PageLoadMetricsObserver {
- public:
-  PageCappingPageLoadMetricsObserver();
-  ~PageCappingPageLoadMetricsObserver() override;
-
-  // Returns whether the page's subresource loading is currently paused.
-  bool IsPausedForTesting() const;
-
-  // Tests can change the behavior of clock for testing time between resource
-  // loads.
-  void SetTickClockForTesting(base::TickClock* clock);
-
-  // The current state of the page.
-  // This class operates as a state machine going from each of the below states
-  // in order. This is recorded to UKM, so the enum should not be changed.
-  enum class PageCappingState {
-    // The initial state of the page. No InfoBar has been shown.
-    kInfoBarNotShown = 0,
-    // When the cap is met, an InfoBar will be shown.
-    kInfoBarShown = 1,
-    // If the user clicks pause on the InfoBar, the page will be paused.
-    kPagePaused = 2,
-    // If the user then clicks resume on the InfoBar the page is resumed. This
-    // is the final state.
-    kPageResumed = 3,
-  };
-
- protected:
-  // Virtual for testing.
-  // Gets the random offset for the capping threshold.
-  virtual int64_t GetFuzzingOffset() const;
-
-  // Virtual for testing.
-  // Gets the page load capping blacklist from the page load capping service.
-  // Returns null for incognito profiles or profiles that have Data Saver
-  // disabled.
-  virtual PageLoadCappingBlacklist* GetPageLoadCappingBlacklist() const;
-
- private:
-  // page_load_metrics::PageLoadMetricsObserver:
-  void OnResourceDataUseObserved(
-      FrameTreeNodeId frame_tree_node_id,
-      const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
-          resources) override;
-  ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
-                         ukm::SourceId source_id) override;
-  void OnDidFinishSubFrameNavigation(
-      content::NavigationHandle* navigation_handle,
-      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
-  void MediaStartedPlaying(
-      const content::WebContentsObserver::MediaPlayerInfo& video_type,
-      content::RenderFrameHost* render_frame_host) override;
-  ObservePolicy FlushMetricsOnAppEnterBackground(
-      const page_load_metrics::mojom::PageLoadTiming& timing,
-      const page_load_metrics::PageLoadExtraInfo& info) override;
-  ObservePolicy OnHidden(
-      const page_load_metrics::mojom::PageLoadTiming& timing,
-      const page_load_metrics::PageLoadExtraInfo& info) override;
-  void OnComplete(const page_load_metrics::mojom::PageLoadTiming& timing,
-                  const page_load_metrics::PageLoadExtraInfo& info) override;
-
-  // If this is the first time this is called, queries the page load capping
-  // blacklist for whether the InfoBar should be allowed and records UMA.
-  // Otherwise, this returns the cached value.
-  // Records nothing for incognito Profiles and returns false.
-  bool IsBlacklisted();
-
-  // Reports whether the page was an opt out or not to the blacklist.
-  void ReportOptOut();
-
-  // Records a new estimate of data savings based on data used and field trial
-  // params. Also records the PageCappingState to UKM.
-  void RecordDataSavingsAndUKM(
-      const page_load_metrics::PageLoadExtraInfo& info);
-
-  // Writes the amount of savings to the data saver feature. Virtual for
-  // testing.
-  virtual void WriteToSavings(int64_t bytes_saved);
-
-  // Show the page capping infobar if it has not been shown before and the data
-  // use is above the threshold.
-  void MaybeCreate();
-
-  // Pauses or unpauses the subresource loading of the page based on |paused|.
-  // TODO(ryansturm): New Subframes will not be paused automatically and may
-  // load resources. https://crbug.com/835895
-  void PauseSubresourceLoading(bool paused);
-
-  // Sets |time_to_expire| to the earliest time duration that the page load is
-  // considered not to be using data anymore. |time_to_expire| must be passed in
-  // as TimeDelta initialized to 0 to handle the case of the underlying weak
-  // pointer being destroyed.
-  // If |time_to_expire| is returned as 0, the consumer should treat the page as
-  // not using data anymore, and does not need to wait any longer to consider
-  // the page stopped with respect to data use..
-  void TimeToExpire(base::TimeDelta* time_to_expire) const;
-
-  // The current bytes threshold of the capping page triggering.
-  base::Optional<int64_t> page_cap_;
-
-  // The host to attribute savings to.
-  std::string url_host_;
-
-  // Whether a media element has been played on the page.
-  bool media_page_load_ = false;
-
-  // The cumulative network body bytes used so far.
-  int64_t network_bytes_ = 0;
-
-  // The amount of bytes when the data savings was last recorded.
-  int64_t recorded_savings_ = 0;
-
-  PageCappingState page_capping_state_ = PageCappingState::kInfoBarNotShown;
-
-  // True once UKM has been recorded. This is recorded at the same time as
-  // PageLoad UKM (during hidden, complete, or app background).
-  bool ukm_recorded_ = false;
-
-  // The randomly generated offset from the capping threshold.
-  int64_t fuzzing_offset_ = 0;
-
-  // Empty until the blacklist is queried and UMA is recorded about blacklist
-  // reason. Once populated, whether the feature is blacklisted or not for the
-  // user on the URL of this page. Incognito Profiles or Profiles with Data
-  // Saver disabled will cause this to be false once populated.
-  base::Optional<bool> blacklisted_;
-
-  // If non-empty, a group of handles that are pausing subresource loads in the
-  // render frames of this page.
-  std::vector<blink::mojom::PauseSubresourceLoadingHandlePtr> handles_;
-
-  base::Optional<base::TimeTicks> last_data_use_time_;
-
-  // Default clock unless SetClockForTesting is called.
-  const base::TickClock* clock_;
-
-  base::WeakPtrFactory<PageCappingPageLoadMetricsObserver> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageCappingPageLoadMetricsObserver);
-};
-
-#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_PAGE_CAPPING_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc
deleted file mode 100644
index ccef215..0000000
--- a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc
+++ /dev/null
@@ -1,726 +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 "chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h"
-
-#include <memory>
-#include <string>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "base/time/default_clock.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/chrome_page_load_capping_features.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_blacklist.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/infobars/mock_infobar_service.h"
-#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
-#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
-#include "chrome/browser/page_load_metrics/page_load_tracker.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_blacklist_data.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_blacklist_delegate.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_store.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar.h"
-#include "content/public/test/web_contents_tester.h"
-#include "services/metrics/public/cpp/ukm_builders.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "url/gurl.h"
-
-namespace {
-
-const char kTestURL[] = "http://www.test.com";
-
-// Test class that has default blacklisting behavior with no backing store.
-class TestPageLoadCappingBlacklist : public PageLoadCappingBlacklist {
- public:
-  explicit TestPageLoadCappingBlacklist(
-      blacklist::OptOutBlacklistDelegate* delegate)
-      : PageLoadCappingBlacklist(nullptr,
-                                 base::DefaultClock::GetInstance(),
-                                 delegate) {}
-  ~TestPageLoadCappingBlacklist() override {}
-};
-
-}  // namespace
-
-// Class that overrides WriteToSavings.
-class TestPageCappingPageLoadMetricsObserver
-    : public PageCappingPageLoadMetricsObserver {
- public:
-  using SizeUpdateCallback = base::RepeatingCallback<void(int64_t)>;
-  TestPageCappingPageLoadMetricsObserver(
-      int64_t fuzzing_offset,
-      PageLoadCappingBlacklist* blacklist,
-      std::unique_ptr<base::SimpleTestTickClock> simple_test_tick_clock,
-      const SizeUpdateCallback& callback)
-      : fuzzing_offset_(fuzzing_offset),
-        blacklist_(blacklist),
-        simple_test_tick_clock_(std::move(simple_test_tick_clock)),
-        size_callback_(callback) {
-    SetTickClockForTesting(simple_test_tick_clock_.get());
-  }
-  ~TestPageCappingPageLoadMetricsObserver() override {}
-
-  void WriteToSavings(int64_t bytes_saved) override {
-    size_callback_.Run(bytes_saved);
-  }
-
-  int64_t GetFuzzingOffset() const override { return fuzzing_offset_; }
-
-  PageLoadCappingBlacklist* GetPageLoadCappingBlacklist() const override {
-    return blacklist_;
-  }
-
- private:
-  int64_t fuzzing_offset_;
-  PageLoadCappingBlacklist* blacklist_;
-  std::unique_ptr<base::SimpleTestTickClock> simple_test_tick_clock_;
-  SizeUpdateCallback size_callback_;
-};
-
-class PageCappingObserverTest
-    : public page_load_metrics::PageLoadMetricsObserverTestHarness,
-      public blacklist::OptOutBlacklistDelegate {
- public:
-  PageCappingObserverTest()
-      : test_blacklist_(std::make_unique<TestPageLoadCappingBlacklist>(this)) {}
-  ~PageCappingObserverTest() override = default;
-
-  void SetUpTest(bool enabled, std::map<std::string, std::string> params) {
-    if (enabled) {
-      scoped_feature_list_.InitAndEnableFeatureWithParameters(
-          data_use_measurement::page_load_capping::features::
-              kDetectingHeavyPages,
-          params);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          data_use_measurement::page_load_capping::features::
-              kDetectingHeavyPages);
-    }
-
-    MockInfoBarService::CreateForWebContents(web_contents());
-    NavigateAndCommit(GURL(kTestURL));
-  }
-
-  size_t InfoBarCount() { return infobar_service()->infobar_count(); }
-
-  void RemoveAllInfoBars() { infobar_service()->RemoveAllInfoBars(false); }
-
-  InfoBarService* infobar_service() {
-    return InfoBarService::FromWebContents(web_contents());
-  }
-
-  // Called from the observer when |WriteToSavings| is called.
-  void UpdateSavings(int64_t savings) { savings_ += savings; }
-
-  // Load a resource of size |bytes|.
-  void SimulateBytes(int bytes) {
-    std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources;
-    auto resource_data_update =
-        page_load_metrics::mojom::ResourceDataUpdate::New();
-    resource_data_update->delta_bytes = bytes;
-    resources.push_back(std::move(resource_data_update));
-    SimulateResourceDataUseUpdate(resources);
-  }
-
- protected:
-  void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
-    auto observer = std::make_unique<TestPageCappingPageLoadMetricsObserver>(
-        fuzzing_offset_, test_blacklist_.get(),
-        std::make_unique<base::SimpleTestTickClock>(),
-        base::BindRepeating(&PageCappingObserverTest::UpdateSavings,
-                            base::Unretained(this)));
-    observer_ = observer.get();
-    // Keep the clock frozen.
-    tracker->AddObserver(std::move(observer));
-  }
-
-  // blacklist::OptOutBlacklistDelegate:
-  void OnNewBlacklistedHost(const std::string& host, base::Time time) override {
-  }
-  void OnUserBlacklistedStatusChange(bool blacklisted) override {}
-  void OnBlacklistCleared(base::Time time) override {}
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-  int64_t savings_ = 0;
-  int64_t fuzzing_offset_ = 0;
-  TestPageCappingPageLoadMetricsObserver* observer_;
-  std::unique_ptr<TestPageLoadCappingBlacklist> test_blacklist_;
-};
-
-TEST_F(PageCappingObserverTest, ExperimentDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitAndDisableFeature(
-      data_use_measurement::page_load_capping::features::kDetectingHeavyPages);
-  SetUpTest(false, {});
-
-  // Load a resource slightly over 1 MB.
-  // The InfoBar should not show even though the cap would be met because the
-  // feature is disabled.
-  SimulateBytes(1 * 1024 * 1024 + 10);
-
-  EXPECT_EQ(0u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, DefaultThresholdNotMetNonMedia) {
-  SetUpTest(true, {});
-
-  // Load a resource slightly under 5 MB, the default page capping threshold.
-  // The cap is not met, so the InfoBar should not show.
-  SimulateBytes(5 * 1024 * 1024 - 10);
-
-  EXPECT_EQ(0u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, DefaultThresholdMetNonMedia) {
-  SetUpTest(true, {});
-
-  // Load a resource slightly over 5 MB, the default page capping threshold.
-  // The cap is not met, so the InfoBar should not show.
-  SimulateBytes(5 * 1024 * 1024 + 10);
-
-  EXPECT_EQ(1u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, DefaultThresholdNotMetMedia) {
-  SetUpTest(true, {});
-
-  SimulateMediaPlayed();
-
-  // Load a resource slightly under 15 MB, the default media page capping
-  // threshold. The cap is not met, so the InfoBar should not show.
-  SimulateBytes(15 * 1024 * 1024 - 10);
-
-  EXPECT_EQ(0u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, DefaultThresholdMetMedia) {
-  SetUpTest(true, {});
-
-  SimulateMediaPlayed();
-
-  // Load a resource slightly over 15 MB, the default media page capping
-  // threshold. The cap is not met, so the InfoBar should not show.
-  SimulateBytes(15 * 1024 * 1024 + 10);
-
-  EXPECT_EQ(1u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, NotEnoughForThreshold) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"}, {"PageCapMiB", "1"}});
-
-  // Load a resource slightly under 1 MB.
-  // The cap is not met, so the InfoBar should not show.
-  SimulateBytes(1 * 1024 * 1024 - 10);
-
-  EXPECT_EQ(0u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, InfobarOnlyShownOnce) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"}, {"PageCapMiB", "1"}});
-
-  // Load a resource slightly over 1 MB.
-  // This should trigger the InfoBar.
-  SimulateBytes(1 * 1024 * 1024 + 10);
-  EXPECT_EQ(1u, InfoBarCount());
-  // The InfoBar is already being shown, so this should not trigger an InfoBar.
-  SimulateBytes(10);
-  EXPECT_EQ(1u, InfoBarCount());
-
-  // Clear all InfoBars.
-  RemoveAllInfoBars();
-  // Verify the InfoBars are clear.
-  EXPECT_EQ(0u, InfoBarCount());
-  // This would trigger an InfoBar if one was not already shown from this
-  // observer.
-  SimulateBytes(10);
-  EXPECT_EQ(0u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, MediaCap) {
-  SetUpTest(true, {{"MediaPageCapMiB", "10"}, {"PageCapMiB", "1"}});
-
-  // Show that media has played.
-  SimulateMediaPlayed();
-
-  // Load a resource slightly under 10 MB.
-  // This should not trigger an InfoBar as the media cap is not met.
-  SimulateBytes(10 * 1024 * 1024 - 10);
-  EXPECT_EQ(0u, InfoBarCount());
-
-  // Adding more data should now trigger the InfoBar.
-  SimulateBytes(10);
-  EXPECT_EQ(1u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, PageCap) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"}, {"PageCapMiB", "10"}});
-
-  // Load a resource slightly under 10 MB.
-  // This should not trigger an InfoBar as the non-media cap is not met.
-  SimulateBytes(10 * 1024 * 1024 - 10);
-  EXPECT_EQ(0u, InfoBarCount());
-
-  // Adding more data should now trigger the InfoBar.
-  SimulateBytes(10);
-  EXPECT_EQ(1u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, PageCappingTriggered) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"}, {"PageCapMiB", "1"}});
-
-  // Load a resource slightly over 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1 * 1024 * 1024 + 10);
-  EXPECT_EQ(1u, InfoBarCount());
-
-  // Verify the callback is called twice with appropriate bool values.
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_TRUE(content::WebContentsTester::For(web_contents())
-                  ->GetPauseSubresourceLoadingCalled());
-  EXPECT_EQ(1u, InfoBarCount());
-  EXPECT_TRUE(observer_->IsPausedForTesting());
-
-  content::WebContentsTester::For(web_contents())
-      ->ResetPauseSubresourceLoadingCalled();
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-  EXPECT_FALSE(observer_->IsPausedForTesting());
-}
-
-// Check that data savings works without a specific param. The estimated page
-// size should be 1.5 the threshold.
-TEST_F(PageCappingObserverTest, DataSavingsDefault) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"}, {"PageCapMiB", "1"}});
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-  EXPECT_EQ(1u, InfoBarCount());
-
-  // Verify the callback is called twice with appropriate bool values.
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_TRUE(content::WebContentsTester::For(web_contents())
-                  ->GetPauseSubresourceLoadingCalled());
-  EXPECT_EQ(1u, InfoBarCount());
-  EXPECT_TRUE(observer_->IsPausedForTesting());
-
-  // This should cause savings to be written.
-  SimulateAppEnterBackground();
-  EXPECT_EQ(1024 * 1024 / 2, savings_);
-
-  // Load a resource of size 1/4 MB.
-  SimulateBytes(1024 * 1024 / 4);
-
-  // Adding another resource and forcing savings to be written should reduce
-  // total savings.
-  SimulateAppEnterBackground();
-  EXPECT_EQ(1024 * 1024 / 4, savings_);
-
-  content::WebContentsTester::For(web_contents())
-      ->ResetPauseSubresourceLoadingCalled();
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-  EXPECT_FALSE(observer_->IsPausedForTesting());
-
-  // Resuming the page should force savings to 0.
-  NavigateToUntrackedUrl();
-  EXPECT_EQ(0l, savings_);
-}
-
-// Check that data savings works with a specific param. The estimated page size
-// should be |PageTypicalLargePageMB|.
-TEST_F(PageCappingObserverTest, DataSavingsParam) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-  EXPECT_EQ(1u, InfoBarCount());
-
-  // Verify the callback is called twice with appropriate bool values.
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_TRUE(content::WebContentsTester::For(web_contents())
-                  ->GetPauseSubresourceLoadingCalled());
-  EXPECT_EQ(1u, InfoBarCount());
-  EXPECT_TRUE(observer_->IsPausedForTesting());
-
-  // This should cause savings to be written.
-  SimulateAppEnterBackground();
-  EXPECT_EQ(1024 * 1024, savings_);
-
-  // Load a resource of size 1/4 MB.
-  SimulateBytes(1024 * 1024 / 4);
-
-  // Adding another resource and forcing savings to be written should reduce
-  // total savings.
-  SimulateAppEnterBackground();
-  EXPECT_EQ(1024 * 1024 * 3 / 4, savings_);
-
-  content::WebContentsTester::For(web_contents())
-      ->ResetPauseSubresourceLoadingCalled();
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-  EXPECT_FALSE(content::WebContentsTester::For(web_contents())
-                   ->GetPauseSubresourceLoadingCalled());
-  EXPECT_FALSE(observer_->IsPausedForTesting());
-
-  // Resuming should make the savings 0.
-  SimulateAppEnterBackground();
-  EXPECT_EQ(0l, savings_);
-
-  // Forcing savings to be written again should not change savings.
-  NavigateToUntrackedUrl();
-  EXPECT_EQ(0l, savings_);
-}
-
-TEST_F(PageCappingObserverTest, DataSavingsHistogram) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-  base::HistogramTester histogram_tester;
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  // Savings is only recorded in OnComplete
-  SimulateAppEnterBackground();
-  histogram_tester.ExpectTotalCount("HeavyPageCapping.RecordedDataSavings", 0);
-
-  NavigateToUntrackedUrl();
-  histogram_tester.ExpectUniqueSample("HeavyPageCapping.RecordedDataSavings",
-                                      1024, 1);
-}
-
-TEST_F(PageCappingObserverTest, DataSavingsHistogramWhenResumed) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-  base::HistogramTester histogram_tester;
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  NavigateToUntrackedUrl();
-  histogram_tester.ExpectTotalCount("HeavyPageCapping.RecordedDataSavings", 0);
-}
-
-TEST_F(PageCappingObserverTest, UKMNotRecordedWhenNotTriggered) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-  base::HistogramTester histogram_tester;
-  NavigateToUntrackedUrl();
-
-  using UkmEntry = ukm::builders::PageLoadCapping;
-  auto entries = test_ukm_recorder().GetEntriesByName(UkmEntry::kEntryName);
-
-  EXPECT_EQ(0u, entries.size());
-}
-
-TEST_F(PageCappingObserverTest, UKMRecordedInfoBarShown) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  NavigateToUntrackedUrl();
-
-  using UkmEntry = ukm::builders::PageLoadCapping;
-  auto entries = test_ukm_recorder().GetEntriesByName(UkmEntry::kEntryName);
-
-  EXPECT_EQ(1u, entries.size());
-  test_ukm_recorder().ExpectEntrySourceHasUrl(entries[0], GURL(kTestURL));
-  EXPECT_TRUE(test_ukm_recorder().EntryHasMetric(entries[0],
-                                                 UkmEntry::kFinalStateName));
-  EXPECT_EQ(static_cast<int64_t>(1),
-            *(test_ukm_recorder().GetEntryMetric(entries[0],
-                                                 UkmEntry::kFinalStateName)));
-  EXPECT_EQ(
-      static_cast<int64_t>(
-          PageCappingPageLoadMetricsObserver::PageCappingState::kInfoBarShown),
-      *(test_ukm_recorder().GetEntryMetric(entries[0],
-                                           UkmEntry::kFinalStateName)));
-}
-
-TEST_F(PageCappingObserverTest, UKMRecordedPaused) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  // Pause the page.
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  NavigateToUntrackedUrl();
-  using UkmEntry = ukm::builders::PageLoadCapping;
-  auto entries = test_ukm_recorder().GetEntriesByName(UkmEntry::kEntryName);
-
-  EXPECT_EQ(1u, entries.size());
-  test_ukm_recorder().ExpectEntrySourceHasUrl(entries[0], GURL(kTestURL));
-  EXPECT_TRUE(test_ukm_recorder().EntryHasMetric(entries[0],
-                                                 UkmEntry::kFinalStateName));
-  EXPECT_EQ(static_cast<int64_t>(2),
-            *(test_ukm_recorder().GetEntryMetric(entries[0],
-                                                 UkmEntry::kFinalStateName)));
-  EXPECT_EQ(
-      static_cast<int64_t>(
-          PageCappingPageLoadMetricsObserver::PageCappingState::kPagePaused),
-      *(test_ukm_recorder().GetEntryMetric(entries[0],
-                                           UkmEntry::kFinalStateName)));
-}
-
-TEST_F(PageCappingObserverTest, UKMRecordedResumed) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  // Pause then resume.
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  NavigateToUntrackedUrl();
-  using UkmEntry = ukm::builders::PageLoadCapping;
-  auto entries = test_ukm_recorder().GetEntriesByName(UkmEntry::kEntryName);
-
-  EXPECT_EQ(1u, entries.size());
-  test_ukm_recorder().ExpectEntrySourceHasUrl(entries[0], GURL(kTestURL));
-  EXPECT_TRUE(test_ukm_recorder().EntryHasMetric(entries[0],
-                                                 UkmEntry::kFinalStateName));
-  EXPECT_EQ(static_cast<int64_t>(3),
-            *(test_ukm_recorder().GetEntryMetric(entries[0],
-                                                 UkmEntry::kFinalStateName)));
-  EXPECT_EQ(
-      static_cast<int64_t>(
-          PageCappingPageLoadMetricsObserver::PageCappingState::kPageResumed),
-      *(test_ukm_recorder().GetEntryMetric(entries[0],
-                                           UkmEntry::kFinalStateName)));
-}
-
-TEST_F(PageCappingObserverTest, FuzzingOffset) {
-  fuzzing_offset_ = 1;
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  // Load a resource of 1 MB.
-  // This should not trigger an InfoBar as the non-media cap is not met.
-  SimulateBytes(1024 * 1024);
-
-  EXPECT_EQ(0u, InfoBarCount());
-
-  // Load a resource of 1 byte.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1);
-
-  EXPECT_EQ(1u, InfoBarCount());
-}
-
-TEST_F(PageCappingObserverTest, NullBlacklistBlocksInfoBar) {
-  test_blacklist_ = nullptr;
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-  base::HistogramTester histogram_tester;
-
-  // Load a resource of 1 MB.
-  // This should be enough to trigger an InfoBar (when ignoring the blacklist).
-  SimulateBytes(1024 * 1024);
-
-  // Because the blacklist is null (as in the case of incognito profiles), the
-  // InfoBar should not be shown.
-  EXPECT_EQ(0u, InfoBarCount());
-
-  histogram_tester.ExpectTotalCount("HeavyPageCapping.BlacklistReason", 0);
-}
-
-TEST_F(PageCappingObserverTest, BlacklistOnTwoOptOuts) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-  base::HistogramTester histogram_tester;
-
-  test_blacklist_->AddEntry(GURL(kTestURL).host(), true, 0);
-  test_blacklist_->AddEntry(GURL(kTestURL).host(), true, 0);
-
-  // Verify the blacklist is reporting not allowed.
-  std::vector<blacklist::BlacklistReason> passed_reasons;
-  auto blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_NE(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  // Because the blacklist is in an opted out state, the InfoBar should not be
-  // shown.
-  EXPECT_EQ(0u, InfoBarCount());
-
-  histogram_tester.ExpectUniqueSample("HeavyPageCapping.BlacklistReason",
-                                      static_cast<int>(blacklist_reason), 1);
-}
-
-TEST_F(PageCappingObserverTest, IgnoringInfoBarTriggersOptOut) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  test_blacklist_->AddEntry(GURL(kTestURL).host(), true, 0);
-
-  std::vector<blacklist::BlacklistReason> passed_reasons;
-  auto blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_EQ(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  // Blacklist is in allowed state, so an InfoBar is allowed to be shown.
-  EXPECT_EQ(1u, InfoBarCount());
-
-  // Trigger an opt out reporting event.
-  NavigateToUntrackedUrl();
-
-  // Check that the opt out caused a blacklisted state.
-  blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_NE(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-}
-
-TEST_F(PageCappingObserverTest, PausedInfoBarTriggersNonOptOut) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  test_blacklist_->AddEntry(GURL(kTestURL).host(), true, 0);
-
-  std::vector<blacklist::BlacklistReason> passed_reasons;
-  auto blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_EQ(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-
-  // Load a resource of 1 MB.
-  // This should trigger an InfoBar as the non-media cap is met.
-  SimulateBytes(1024 * 1024);
-
-  // Blacklist is in allowed state, so an InfoBar is allowed to be shown.
-  EXPECT_EQ(1u, InfoBarCount());
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  // Trigger a non-opt out reporting event.
-  NavigateToUntrackedUrl();
-
-  // Check that the non-opt out did not cause a blacklisted state.
-  blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_EQ(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-}
-
-TEST_F(PageCappingObserverTest, ResumedInfoBarTriggersOptOut) {
-  SetUpTest(true, {{"MediaPageCapMiB", "1"},
-                   {"PageCapMiB", "1"},
-                   {"PageTypicalLargePageMiB", "2"}});
-
-  test_blacklist_->AddEntry(GURL(kTestURL).host(), true, 0);
-
-  std::vector<blacklist::BlacklistReason> passed_reasons;
-  auto blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_EQ(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-
-  // Load a resource of 1 MB.
-  // This should not trigger an InfoBar as the blacklist rules should prevent
-  // it.
-  SimulateBytes(1024 * 1024);
-
-  // Blacklist is in allowed state, so an InfoBar is allowed to be shown.
-  EXPECT_EQ(1u, InfoBarCount());
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  static_cast<ConfirmInfoBarDelegate*>(
-      infobar_service()->infobar_at(0u)->delegate())
-      ->LinkClicked(WindowOpenDisposition::CURRENT_TAB);
-
-  // Trigger an opt out reporting event.
-  NavigateToUntrackedUrl();
-
-  // Check that the opt out caused a blacklisted state.
-  blacklist_reason = test_blacklist_->IsLoadedAndAllowed(
-      GURL(kTestURL).host(), 0, false, &passed_reasons);
-  EXPECT_NE(blacklist::BlacklistReason::kAllowed, blacklist_reason);
-}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 4f2b84b..aa4b30e 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.h"
-#include "chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/previews_lite_page_redirect_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/previews_ukm_observer.h"
@@ -115,8 +114,6 @@
         std::make_unique<
             previews::OfflinePagePreviewsPageLoadMetricsObserver>());
     tracker->AddObserver(
-        std::make_unique<PageCappingPageLoadMetricsObserver>());
-    tracker->AddObserver(
         std::make_unique<PreviewsLitePageRedirectMetricsObserver>());
     tracker->AddObserver(
         std::make_unique<previews::PreviewsPageLoadMetricsObserver>());
diff --git a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
index 43123c31..b1d805e 100644
--- a/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_browsertest.cc
@@ -88,12 +88,14 @@
                                    const std::string& value) {
   DCHECK(!waiting_callback_);
   waiting_callback_ = true;
+  net::CookieOptions options;
+  options.set_include_httponly();
   cookie_manager_->SetCanonicalCookie(
       net::CanonicalCookie(name, value, host, "/", base::Time(), base::Time(),
                            base::Time(), false, false,
                            net::CookieSameSite::NO_RESTRICTION,
                            net::COOKIE_PRIORITY_MEDIUM),
-      "http", true /* modify_http_only */,
+      "http", options,
       base::BindOnce(&RemoveCookieTester::SetCanonicalCookieCallback,
                      base::Unretained(this)));
   BlockUntilNotified();
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index e1eb6dc..343eadc6 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -48,8 +48,6 @@
 #include "chrome/browser/client_hints/client_hints_factory.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service.h"
-#include "chrome/browser/data_use_measurement/page_load_capping/page_load_capping_service_factory.h"
 #include "chrome/browser/dom_distiller/profile_utils.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/download/download_core_service.h"
@@ -718,8 +716,14 @@
   model->AddObserver(new BookmarkModelLoadedObserver(this));
 #endif
 
-  PageLoadCappingServiceFactory::GetForBrowserContext(this)->Initialize(
-      GetPath());
+  // Page Load Capping was remove in M74, so the database file should be removed
+  // when users upgrade Chrome.
+  // TODO(ryansturm): Remove this after M-79. https://crbug.com/937489
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::TaskPriority::LOWEST, base::MayBlock()},
+      base::BindOnce(base::IgnoreResult(&base::DeleteFile),
+                     GetPath().Append(chrome::kPageLoadCappingOptOutDBFilename),
+                     false));
 
   PushMessagingServiceImpl::InitializeForProfile(this);
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_update.js b/chrome/browser/resources/chromeos/login/oobe_screen_update.js
index f400fb62..6d0caa8 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_update.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_update.js
@@ -8,66 +8,28 @@
 
 login.createScreen('UpdateScreen', 'update', function() {
   var USER_ACTION_CANCEL_UPDATE_SHORTCUT = 'cancel-update';
-  var CONTEXT_KEY_TIME_LEFT_SEC = 'time-left-sec';
-  var CONTEXT_KEY_SHOW_TIME_LEFT = 'show-time-left';
-  var CONTEXT_KEY_UPDATE_COMPLETED = 'update-completed';
-  var CONTEXT_KEY_SHOW_CURTAIN = 'show-curtain';
-  var CONTEXT_KEY_SHOW_PROGRESS_MESSAGE = 'show-progress-msg';
-  var CONTEXT_KEY_PROGRESS = 'progress';
-  var CONTEXT_KEY_PROGRESS_MESSAGE = 'progress-msg';
-  var CONTEXT_KEY_CANCEL_UPDATE_SHORTCUT_ENABLED = 'cancel-update-enabled';
-  var CONTEXT_KEY_REQUIRES_PERMISSION_FOR_CELLULAR =
-      'requires-permission-for-cellular';
 
   return {
-    EXTERNAL_API: [],
+    EXTERNAL_API: [
+      'setEstimatedTimeLeft',
+      'showEstimatedTimeLeft',
+      'setUpdateCompleted',
+      'showUpdateCurtain',
+      'setProgressMessage',
+      'setUpdateProgress',
+      'setRequiresPermissionForCellular',
+      'setCancelUpdateShortcutEnabled',
+    ],
 
-    /** @override */
-    decorate: function() {
-      var self = this;
-
-      this.context.addObserver(
-          CONTEXT_KEY_TIME_LEFT_SEC, function(time_left_sec) {
-            self.setEstimatedTimeLeft(time_left_sec);
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_SHOW_TIME_LEFT, function(show_time_left) {
-            self.showEstimatedTimeLeft(show_time_left);
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_UPDATE_COMPLETED, function(is_completed) {
-            self.setUpdateCompleted(is_completed);
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_SHOW_CURTAIN, function(show_curtain) {
-            self.showUpdateCurtain(show_curtain);
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_SHOW_PROGRESS_MESSAGE, function(show_progress_msg) {
-            self.showProgressMessage(show_progress_msg);
-          });
-      this.context.addObserver(CONTEXT_KEY_PROGRESS, function(progress) {
-        self.setUpdateProgress(progress);
-      });
-      this.context.addObserver(
-          CONTEXT_KEY_PROGRESS_MESSAGE, function(progress_msg) {
-            self.setProgressMessage(progress_msg);
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_REQUIRES_PERMISSION_FOR_CELLULAR,
-          function(requires_permission) {
-            self.setRequiresPermissionForCellular(requires_permission);
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_CANCEL_UPDATE_SHORTCUT_ENABLED, function(enabled) {
-            $('oobe-update-md').cancelAllowed = enabled;
-            var configuration = Oobe.getInstance().getOobeConfiguration();
-            if (!configuration)
-              return;
-            if (configuration.updateSkipNonCritical && enabled) {
-              self.cancel();
-            }
-          });
+    /** @param {boolean} enabled */
+    setCancelUpdateShortcutEnabled: function(enabled) {
+      $('oobe-update-md').cancelAllowed = enabled;
+      var configuration = Oobe.getInstance().getOobeConfiguration();
+      if (!configuration)
+        return;
+      if (configuration.updateSkipNonCritical && enabled) {
+        this.cancel();
+      }
     },
 
     /**
@@ -142,20 +104,15 @@
     },
 
     /**
-     * Shows or hides info message below progress bar.
-     * @param {boolean} visible Are message visible?
-     */
-    showProgressMessage: function(visible) {
-      $('oobe-update-md').estimatedTimeLeftShown = !visible;
-      $('oobe-update-md').progressMessageShown = visible;
-    },
-
-    /**
-     * Sets message below progress bar.
+     * Sets message below progress bar. Hide the message by setting an empty
+     * string.
      * @param {string} message Message that should be shown.
      */
     setProgressMessage: function(message) {
+      var visible = !!message;
       $('oobe-update-md').progressMessage = message;
+      $('oobe-update-md').estimatedTimeLeftShown = !visible;
+      $('oobe-update-md').progressMessageShown = visible;
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/slow.html b/chrome/browser/resources/chromeos/slow.html
index d3736c9e..5392c89 100644
--- a/chrome/browser/resources/chromeos/slow.html
+++ b/chrome/browser/resources/chromeos/slow.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
 <head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0,
@@ -7,23 +7,19 @@
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
 <link rel="stylesheet" href="chrome://resources/css/widgets.css">
 <link rel="stylesheet" href="slow.css">
-<script src="chrome://resources/js/load_time_data.js"></script>
 <script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/cr/event_target.js"></script>
 <script src="chrome://resources/js/util.js"></script>
-<script src="chrome://slow/slow.js"></script>
-<script src="chrome://slow/strings.js"></script>
+<script src="slow.js"></script>
 </head>
 <body>
-  <div id="container" class="container">
-    <div i18n-content="slowDescription"></div>
+  <div id="container">
+    <div>$i18n{slowDescription}</div>
     <br>
-    <div i18n-values=".innerHTML:slowWarning"></div>
-    <div id="container-inner" width=100% class="container-inner">
-      <button id="slow-disable" i18n-content="slowDisable" hidden></button>
-      <button id="slow-enable" i18n-content="slowEnable" hidden></button>
+    <div>$i18nRaw{slowWarning}</div>
+    <div id="container-inner">
+      <button id="slow-disable" hidden>$i18n{slowDisable}</button>
+      <button id="slow-enable" hidden>$i18n{slowEnable}</button>
     </div>
   </div>
-<script src="chrome://resources/js/i18n_template.js"></script>
 </body>
 </html>
diff --git a/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
index c606e82..12e1aaa2 100644
--- a/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
+++ b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
@@ -228,9 +228,9 @@
     this.ink_.setPDF(data);
     this.state_ = State.ACTIVE;
     this.viewportChanged();
-    // TODO(dstockwell): we shouldn't need this extra flush.
-    await this.ink_.flush();
-    await this.ink_.flush();
+    // Wait for the next task to avoid a race where Ink drops the background
+    // color.
+    await new Promise(resolve => setTimeout(resolve));
     this.ink_.setOutOfBoundsColor(BACKGROUND_COLOR);
     const spacing = Viewport.PAGE_SHADOW.top + Viewport.PAGE_SHADOW.bottom;
     this.ink_.setPageSpacing(spacing);
diff --git a/chrome/browser/resources/pdf/ink/ink_api.js b/chrome/browser/resources/pdf/ink/ink_api.js
index b5efa32..78c1172 100644
--- a/chrome/browser/resources/pdf/ink/ink_api.js
+++ b/chrome/browser/resources/pdf/ink/ink_api.js
@@ -20,6 +20,7 @@
   constructor(embed) {
     this.embed_ = embed;
     this.brush_ = ink.BrushModel.getInstance(embed);
+    this.camera_ = null;
   }
 
   /**
@@ -49,8 +50,12 @@
     return this.embed_.getPDFDestructive();
   }
 
-  setCamera(camera) {
+  async setCamera(camera) {
+    this.camera_ = camera;
     this.embed_.setCamera(camera);
+    // Wait for the next task to avoid a race where Ink drops the camera value
+    // when the canvas is rotated in low-latency mode.
+    setTimeout(() => this.embed_.setCamera(this.camera_), 0);
   }
 
   /** @param {AnnotationTool} tool */
diff --git a/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
index 1bc9016..1f05f90 100644
--- a/chrome/browser/resources/safe_browsing/download_file_types.asciipb
+++ b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
@@ -8,7 +8,7 @@
 ##
 ## Top level settings
 ##
-version_id: 33
+version_id: 34
 sampled_ping_probability: 0.01
 max_archived_binaries_to_report: 10
 default_file_type {
@@ -2807,6 +2807,16 @@
   inspection_type: DMG
 }
 file_types {
+  extension: "dylib"
+  uma_value: 357
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
   extension: "img"
   uma_value: 247
   ping_setting: FULL_PING
@@ -2829,16 +2839,6 @@
   inspection_type: DMG
 }
 file_types {
-  extension: "mobileconfig"
-  uma_value: 356
-  ping_setting: FULL_PING
-  platform_settings {
-    platform: PLATFORM_MAC
-    danger_level: ALLOW_ON_USER_GESTURE
-    auto_open_hint: DISALLOW_AUTO_OPEN
-  }
-}
-file_types {
   extension: "ndif"
   uma_value: 258
   ping_setting: FULL_PING
@@ -2850,6 +2850,16 @@
   inspection_type: DMG
 }
 file_types {
+  extension: "service"
+  uma_value: 358
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
   extension: "smi"
   uma_value: 248
   ping_setting: FULL_PING
@@ -2910,7 +2920,40 @@
   # Automator action
   extension: "action"
   uma_value: 158
-  ping_setting: SAMPLED_PING
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  # Automator action
+  extension: "definition"
+  uma_value: 359
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  # Automator action
+  extension: "wflow"
+  uma_value: 360
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  # Automator action
+  extension: "caction"
+  uma_value: 361
+  ping_setting: FULL_PING
   platform_settings {
     platform: PLATFORM_MAC
     danger_level: ALLOW_ON_USER_GESTURE
@@ -3040,7 +3083,7 @@
   # Automator workflow
   extension: "workflow"
   uma_value: 170
-  ping_setting: SAMPLED_PING
+  ping_setting: FULL_PING
   platform_settings {
     platform: PLATFORM_MAC
     danger_level: ALLOW_ON_USER_GESTURE
@@ -3059,6 +3102,46 @@
   }
   inspection_type: ZIP
 }
+file_types {
+  extension: "mobileconfig"
+  uma_value: 356
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  extension: "configprofile"
+  uma_value: 362
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  extension: "internetconnect"
+  uma_value: 363
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
+file_types {
+  extension: "networkconnect"
+  uma_value: 364
+  ping_setting: FULL_PING
+  platform_settings {
+    platform: PLATFORM_MAC
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
 
 
 ##
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn
index 23ba36d..bfb43ba 100644
--- a/chrome/browser/resources/settings/privacy_page/BUILD.gn
+++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -9,6 +9,9 @@
     ":personalization_options",
     ":privacy_page",
     ":privacy_page_browser_proxy",
+    ":security_keys_reset_dialog",
+    ":security_keys_set_pin_dialog",
+    ":security_keys_subpage",
   ]
 }
 
@@ -50,3 +53,36 @@
   ]
   externs_list = [ "$externs_path/settings_private.js" ]
 }
+
+js_library("security_keys_browser_proxy") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/chrome_send.js" ]
+}
+
+js_library("security_keys_subpage") {
+  deps = [
+    ":security_keys_browser_proxy",
+    "..:route",
+    "../settings_page:settings_animated_pages",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+  externs_list = [ "$externs_path/settings_private.js" ]
+}
+
+js_library("security_keys_set_pin_dialog") {
+  deps = [
+    ":security_keys_browser_proxy",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+  externs_list = [ "$externs_path/settings_private.js" ]
+}
+
+js_library("security_keys_reset_dialog") {
+  deps = [
+    ":security_keys_browser_proxy",
+    "//ui/webui/resources/js:i18n_behavior",
+  ]
+  externs_list = [ "$externs_path/settings_private.js" ]
+}
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 5bb8a5f2..caf03bc5 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -8,6 +8,7 @@
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="security_keys_subpage.html">
 <link rel="import" href="../clear_browsing_data_dialog/clear_browsing_data_dialog.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
 <link rel="import" href="../lifetime_browser_proxy.html">
@@ -155,7 +156,15 @@
             label="$i18n{clearBrowsingData}"
             sub-label="$i18n{clearBrowsingDataDescription}"
             on-click="onClearBrowsingDataTap_"></cr-link-row>
+        <template is="dom-if" if="[[enableSecurityKeysSubpage_]]">
+          <cr-link-row id="security-keys-subpage-trigger"
+            class="hr"
+            label="$i18n{securityKeysTitle}"
+            sub-label="$i18n{securityKeysDesc}"
+            on-click="onSecurityKeysTap_"></cr-link-row>
+        </template>
       </div>
+
 <if expr="use_nss_certs">
       <template is="dom-if" route-path="/certificates">
         <settings-subpage
@@ -165,6 +174,17 @@
         </settings-subpage>
       </template>
 </if>
+
+      <template is="dom-if" if="[[enableSecurityKeysSubpage_]]">
+        <template is="dom-if" route-path="/securityKeys">
+          <settings-subpage
+              associated-control="[[$$('#security-keys-subpage-trigger')]]"
+              page-title="Security Keys">
+            <security-keys-subpage></security-keys-subpage>
+          </settings-subpage>
+        </template>
+      </template>
+
       <template is="dom-if" route-path="/content">
         <settings-subpage
             associated-control="[[$$('#site-settings-subpage-trigger')]]"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index 41d6511..4aa64569 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -135,6 +135,15 @@
       }
     },
 
+    /** @private */
+    enableSecurityKeysSubpage_: {
+      type: Boolean,
+      readOnly: true,
+      value: function() {
+        return loadTimeData.getBoolean('enableSecurityKeysSubpage');
+      }
+    },
+
     /** @private {!Map<string, string>} */
     focusConfig_: {
       type: Object,
@@ -361,6 +370,11 @@
     cr.ui.focusWithoutInk(assert(this.$.clearBrowsingData));
   },
 
+  /** @private */
+  onSecurityKeysTap_: function() {
+    settings.navigateTo(settings.routes.SECURITY_KEYS);
+  },
+
   /**
    * The sub-page title for the site or content settings.
    * @return {string}
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html
new file mode 100644
index 0000000..a4a3f987
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.html
@@ -0,0 +1 @@
+<script src="security_keys_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js
new file mode 100644
index 0000000..1be440a
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_browser_proxy.js
@@ -0,0 +1,89 @@
+// 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.
+
+cr.exportPath('settings');
+
+cr.define('settings', function() {
+  /** @interface */
+  class SecurityKeysBrowserProxy {
+    /**
+     * Starts a PIN set/change operation by flashing all security keys. Resolves
+     * with a pair of numbers. The first is one if the process has immediately
+     * completed (i.e. failed). In this case the second is a CTAP error code.
+     * Otherwise the process is ongoing and must be completed by calling
+     * |setPIN|. In this case the second number is either the number of tries
+     * remaining to correctly specify the current PIN, or else null to indicate
+     * that no PIN is currently set.
+     * @return {!Promise<Array<number>>}
+     */
+    startSetPIN() {}
+
+    /**
+     * Attempts a PIN set/change operation. Resolves with a pair of numbers
+     * whose meaning is the same as with |startSetPIN|. The first number will
+     * always be 1 to indicate that the process has completed and thus the
+     * second will be the CTAP error code.
+     * @return {!Promise<Array<number>>}
+     */
+    setPIN(oldPIN, newPIN) {}
+
+    /**
+     * Starts a reset operation by flashing all security keys and sending a
+     * reset command to the one that the user activates. Resolves with a CTAP
+     * error code.
+     * @return {!Promise<number>}
+     */
+    reset() {}
+
+    /**
+     * Waits for a reset operation to complete. Resolves with a CTAP error code.
+     * @return {!Promise<number>}
+     */
+    completeReset() {}
+
+    /**
+     * Cancel all outstanding operations.
+     */
+    close() {}
+  }
+
+  /**
+   * @implements {settings.SecurityKeysBrowserProxy}
+   */
+  class SecurityKeysBrowserProxyImpl {
+    /** @override */
+    startSetPIN() {
+      return cr.sendWithPromise('securityKeyStartSetPIN');
+    }
+
+    /** @override */
+    setPIN(oldPIN, newPIN) {
+      return cr.sendWithPromise('securityKeySetPIN', oldPIN, newPIN);
+    }
+
+    /** @override */
+    reset() {
+      return cr.sendWithPromise('securityKeyReset');
+    }
+
+    /** @override */
+    completeReset() {
+      return cr.sendWithPromise('securityKeyCompleteReset');
+    }
+
+    /** @override */
+    close() {
+      return chrome.send('securityKeyClose');
+    }
+  }
+
+  // The singleton instance_ is replaced with a test version of this wrapper
+  // during testing.
+  cr.addSingletonGetter(SecurityKeysBrowserProxyImpl);
+
+  return {
+    SecurityKeysBrowserProxy: SecurityKeysBrowserProxy,
+    SecurityKeysBrowserProxyImpl: SecurityKeysBrowserProxyImpl,
+  };
+});
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.html b/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.html
new file mode 100644
index 0000000..5029b77
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.html
@@ -0,0 +1,60 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+<link rel="import" href="../i18n_setup.html">
+<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="security_keys_browser_proxy.html">
+
+<dom-module id="settings-security-keys-reset-dialog">
+  <template>
+    <style include="settings-shared">
+      paper-spinner-lite {
+        padding-bottom: 12px;
+      }
+    </style>
+    <cr-dialog id="dialog" close-text="$i18n{close}" ignore-popstate
+         on-close="closeDialog_">
+      <div slot="title">$i18n{securityKeysResetTitle}</div>
+      <div slot="body">
+        <iron-pages attr-for-selected="id" selected="[[shown_]]">
+          <div id="initial">
+            <p>$i18n{securityKeysResetIntro}</p>
+            <p>$i18n{securityKeysResetStep1}</p>
+            <paper-spinner-lite active></paper-spinner-lite>
+          </div>
+
+          <div id="noReset">
+            <p>$i18n{securityKeysNoReset}</p>
+          </div>
+
+          <div id="resetFailed">
+            <p>[[resetFailed_(errorCode_)]]</p>
+          </div>
+
+          <div id="reset2">
+            <p>$i18n{securityKeysResetStep2}</p>
+          </div>
+
+          <div id="resetSuccess">
+            <p>$i18n{securityKeysResetSuccess}</p>
+          </div>
+
+          <div id="resetNotAllowed">
+            <p>$i18n{securityKeysResetNotAllowed}</p>
+          </div>
+        </iron-pages>
+      </div>
+      <div slot="button-container">
+        <paper-button id="button" class$="[[maybeActionButton_(complete_)]]"
+             on-click="closeDialog_">
+          [[closeText_(complete_)]]
+        </paper-button>
+      </div>
+    </cr-dialog>
+  </template>
+  <script src="security_keys_reset_dialog.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js
new file mode 100644
index 0000000..e8f4478b
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_reset_dialog.js
@@ -0,0 +1,122 @@
+// 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.
+
+/**
+ * @fileoverview 'settings-security-keys-reset-dialog' is a dialog for
+ * triggering factory resets of security keys.
+ */
+Polymer({
+  is: 'settings-security-keys-reset-dialog',
+
+  behaviors: [I18nBehavior],
+
+  properties: {
+    /**
+     * A CTAP error code for when the specific error was not recognised.
+     * @private
+     */
+    errorCode_: Number,
+
+    /**
+     * True iff the process has completed, successfully or otherwise.
+     * @private
+     */
+    complete_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
+     * The id of an element on the page that is currently shown.
+     * @private
+     */
+    shown_: {
+      type: String,
+      value: 'initial',
+    },
+  },
+
+  /** @private {?settings.SecurityKeysBrowserProxy} */
+  browserProxy_: null,
+
+  /** @override */
+  attached: function() {
+    this.browserProxy_ = settings.SecurityKeysBrowserProxyImpl.getInstance();
+    this.$.dialog.showModal();
+
+    this.browserProxy_.reset().then(code => {
+      // code is a CTAP error code. See
+      // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#error-responses
+      if (code == 1 /* INVALID_COMMAND */) {
+        this.shown_ = 'noReset';
+        this.finish_();
+      } else if (code != 0 /* unknown error */) {
+        this.errorCode_ = code;
+        this.shown_ = 'resetFailed';
+        this.finish_();
+      } else {
+        this.shown_ = 'reset2';
+        this.browserProxy_.completeReset().then(code => {
+          if (code == 0 /* SUCCESS */) {
+            this.shown_ = 'resetSuccess';
+          } else if (code == 48 /* NOT_ALLOWED */) {
+            this.shown_ = 'resetNotAllowed';
+          } else /* unknown error */ {
+            this.errorCode_ = code;
+            this.shown_ = 'resetFailed';
+          }
+          this.finish_();
+        });
+      }
+    });
+  },
+
+  /** @private */
+  closeDialog_: function() {
+    this.$.dialog.close();
+    this.finish_();
+  },
+
+  /** @private */
+  finish_: function() {
+    if (this.complete_) {
+      return;
+    }
+    this.complete_ = true;
+    this.browserProxy_.close();
+  },
+
+  /**
+     @param {number} code CTAP error code.
+     @return {string} Contents of the error string that may be displayed
+          to the user. Used automatically by Polymer.
+     @private
+   */
+  resetFailed_: function(code) {
+    if (code === null) {
+      return '';
+    }
+    return this.i18n('securityKeysResetError', code.toString());
+  },
+
+  /**
+   * @param {boolean} complete Whether the dialog process is complete.
+   * @return {string} The label of the dialog button. Used automatically by
+   *     Polymer.
+   * @private
+   */
+  closeText_: function(complete) {
+    return this.i18n(complete ? 'ok' : 'cancel');
+  },
+
+  /**
+   * @param {boolean} complete Whether the dialog process is complete.
+   * @return {string} The class of the dialog button. Used automatically by
+   *     Polymer.
+   * @private
+   */
+  maybeActionButton_: function(complete) {
+    return complete ? 'action-button' : 'cancel-button';
+  },
+});
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html
new file mode 100644
index 0000000..7ee8ee1
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html
@@ -0,0 +1,108 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+<link rel="import" href="../i18n_setup.html">
+<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="security_keys_browser_proxy.html">
+
+<dom-module id="settings-security-keys-set-pin-dialog">
+  <template>
+    <style include="settings-shared">
+      cr-input {
+        display: inline-block;
+        padding-inline-end: 2em;
+        width: 8em;
+      }
+
+      #newPINRow {
+        display: flex;
+        flex-direction: row;
+      }
+
+      paper-spinner-lite {
+        padding-bottom: 12px;
+      }
+    </style>
+
+    <cr-dialog id="dialog" close-text="$i18n{close}" ignore-popstate
+        on-close="closeDialog_">
+      <div slot="title">$i18n{securityKeysSetPIN}</div>
+      <div slot="body">
+        <iron-pages attr-for-selected="id" selected="[[shown_]]">
+          <div id="initial">
+            <p>$i18n{securityKeysPINDesc}</p>
+            <p>$i18n{securityKeysPINTouch}</p>
+            <paper-spinner-lite active></paper-spinner-lite>
+          </div>
+
+          <div id="noPINSupport">
+            <p>$i18n{securityKeysNoPIN}</p>
+          </div>
+
+          <div id="pinPrompt">
+            <div id="currentPINEntry">
+              <p>$i18nRaw{securityKeysCurrentPINIntro}</p>
+
+              <cr-input id="currentPIN" value="{{currentPIN_}}" minLength="4"
+                  maxLength="255" spellcheck="false"
+                  on-input="validateCurrentPIN_" invalid="[[!currentPINValid_]]"
+                  label="$i18n{securityKeysCurrentPIN}" tabindex="0"
+                  type="password"
+                  error-message="[[mismatchErrorText_(mismatchErrorVisible_, retries_)]]">
+              </cr-input>
+            </div>
+
+            <p>$i18n{securityKeysNewPIN}</p>
+
+            <div id="newPINRow">
+              <cr-input id="newPIN" value="{{newPIN_}}" minLength="4"
+                  maxLength="255" spellcheck="false" on-input="validateNewPIN_"
+                  invalid="[[!newPINValid_]]" label="$i18n{securityKeysPIN}"
+                  tabindex="0" type="password"></cr-input>
+              <cr-input id="confirmPIN" value="{{confirmPIN_}}" minLength="4"
+                  maxLength="255" spellcheck="false"
+                  on-input="validateConfirmPIN_" invalid="[[!confirmPINValid_]]"
+                  label="$i18n{securityKeysConfirmPIN}" tabindex="0"
+                  type="password"></cr-input>
+            </div>
+          </div>
+
+          <div id="success">
+            <p>$i18n{securityKeysPINSuccess}</p>
+          </div>
+
+          <div id="error">
+            <p>[[pinFailed_(errorCode_)]]</p>
+          </div>
+
+          <div id="locked">
+            <p>$i18n{securityKeysPINHardLock}</p>
+          </div>
+
+          <div id="reinsert">
+            <p>$i18n{securityKeysPINSoftLock}</p>
+          </div>
+        </iron-pages>
+      </div>
+
+      <div slot="button-container">
+        <paper-button id="closeButton"
+            class$="[[maybeActionButton_(complete_)]]"
+            on-click="closeDialog_">
+          [[closeText_(complete_)]]
+        </paper-button>
+        <paper-button id="pinSubmit" class="action-button"
+            on-click="pinSubmitNew_" disabled="[[!setPINButtonValid_]]"
+            hidden="[[complete_]]">
+          $i18n{securityKeysSetPIN}
+        </paper-button>
+      </div>
+    </cr-dialog>
+  </template>
+  <script src="security_keys_set_pin_dialog.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
new file mode 100644
index 0000000..734dddd
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
@@ -0,0 +1,332 @@
+// 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.
+
+(function() {
+'use strict';
+
+/**
+   @param {string} pin A candidate PIN.
+   @return {boolean} Whether the parameter was a valid PIN.
+   @private
+ */
+function isValidPIN(pin) {
+  // The UTF-8 encoding of the PIN must be between 4 and 63 bytes, and the
+  // final byte cannot be zero.
+  const utf8Encoded = new TextEncoder().encode(pin);
+  if (utf8Encoded.length < 4 || utf8Encoded.length > 63 ||
+      utf8Encoded[utf8Encoded.length - 1] == 0) {
+    return false;
+  }
+
+  // A PIN must contain at least four code-points. Javascript strings are UCS-2
+  // and the |length| property counts UCS-2 elements, not code-points. (For
+  // example, '\u{1f6b4}'.length == 2, but it's a single code-point.) Therefore,
+  // iterate over the string (which does yield codepoints) and check that four
+  // or more were seen.
+  let length = 0;
+  for (const codepoint of pin) {
+    length++;
+  }
+
+  return length >= 4;
+}
+
+/**
+ * @fileoverview 'settings-security-keys-set-pin-dialog' is a dialog for
+ * setting and changing security key PINs.
+ */
+Polymer({
+  is: 'settings-security-keys-set-pin-dialog',
+
+  behaviors: [I18nBehavior],
+
+  properties: {
+    /**
+     * Whether the value of the current PIN textbox is a valid PIN or not.
+     * @private
+     */
+    currentPINValid_: Boolean,
+
+    /** @private */
+    newPINValid_: Boolean,
+
+    /** @private */
+    confirmPINValid_: Boolean,
+
+    /**
+     * Whether the dialog is in a state where the Set PIN button should be
+     * enabled. Read by Polymer.
+     * @private
+     */
+    setPINButtonValid_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
+     * The value of the new PIN textbox. Read/write by Polymer.
+     * @private
+     */
+    newPIN_: {
+      type: String,
+      value: '',
+    },
+
+    /** @private */
+    confirmPIN_: {
+      type: String,
+      value: '',
+    },
+
+    /** @private */
+    currentPIN_: {
+      type: String,
+      value: '',
+    },
+
+    /**
+     * The number of PIN attempts remaining.
+     * @private
+     */
+    retries_: Number,
+
+    /**
+     * A CTAP error code when we don't recognise the specific error. Read by
+     * Polymer.
+     * @private
+     */
+    errorCode_: Number,
+
+    /**
+     * Whether the error message indicating an incorrect PIN should be visible.
+     * @private
+     */
+    mismatchErrorVisible_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
+     * Whether the dialog process has completed, successfully or otherwise.
+     * @private
+     */
+    complete_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
+     * The id of an element on the page that is currently shown.
+     * @private
+     */
+    shown_: {
+      type: String,
+      value: 'initial',
+    },
+  },
+
+  /** @private {?settings.SecurityKeysBrowserProxy} */
+  browserProxy_: null,
+
+  /** @override */
+  attached: function() {
+    this.browserProxy_ = settings.SecurityKeysBrowserProxyImpl.getInstance();
+    this.$.dialog.showModal();
+
+    this.browserProxy_.startSetPIN().then(result => {
+      if (result[0]) {
+        // Operation is complete. result[1] is a CTAP error code. See
+        // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#error-responses
+        if (result[1] == 1 /* INVALID_COMMAND */) {
+          this.shown_ = 'noPINSupport';
+          this.finish_();
+        } else if (result[1] == 52 /* temporarily locked */) {
+          this.shown_ = 'reinsert';
+          this.finish_();
+        } else if (result[1] == 50 /* locked */) {
+          this.shown_ = 'locked';
+          this.finish_();
+        } else {
+          this.errorCode_ = result[1];
+          this.shown_ = 'error';
+          this.finish_();
+        }
+      } else if (result[1] == 0) {
+        // A device can also signal that it is locked by returning zero retries.
+        this.shown_ = 'locked';
+        this.finish_();
+      } else {
+        // Need to prompt for a pin. Initially set the text boxes to valid so
+        // that they don't all appear red without the user typing anything.
+        this.currentPINValid_ = true;
+        this.newPINValid_ = true;
+        this.confirmPINValid_ = true;
+
+        this.retries_ = result[1];
+        // retries_ may be null to indicate that there is currently no PIN set.
+        let focusTarget;
+        if (this.retries_ === null) {
+          this.$.currentPINEntry.hidden = true;
+          focusTarget = this.$.newPIN;
+        } else {
+          this.$.currentPINEntry.hidden = false;
+          focusTarget = this.$.currentPIN;
+        }
+
+        this.shown_ = 'pinPrompt';
+        // Focus cannot be set directly from within a backend callback.
+        window.setTimeout(function() {
+          focusTarget.focus();
+        }, 0);
+        this.fire('ui-ready');  // for test synchronization.
+      }
+    });
+  },
+
+  /** @private */
+  closeDialog_: function() {
+    this.$.dialog.close();
+    this.finish_();
+  },
+
+  /** @private */
+  finish_: function() {
+    if (this.complete_) {
+      return;
+    }
+    this.complete_ = true;
+    this.browserProxy_.close();
+  },
+
+  /** @private */
+  updatePINButtonValid_: function() {
+    this.setPINButtonValid_ =
+        (this.$.currentPINEntry.hidden ||
+         (this.currentPINValid_ && this.currentPIN_.length > 0)) &&
+        this.newPINValid_ && this.newPIN_.length > 0 && this.confirmPINValid_ &&
+        this.confirmPIN_.length > 0;
+  },
+
+  /** @private */
+  validateCurrentPIN_: function() {
+    this.currentPINValid_ = isValidPIN(this.currentPIN_);
+    this.updatePINButtonValid_();
+    // Typing in the current PIN box after an error makes the error message
+    // disappear.
+    this.mismatchErrorVisible_ = false;
+  },
+
+  /** @private */
+  validateNewPIN_: function() {
+    this.newPINValid_ = isValidPIN(this.newPIN_);
+    this.updatePINButtonValid_();
+  },
+
+  /** @private */
+  validateConfirmPIN_: function() {
+    this.confirmPINValid_ = this.confirmPIN_ == this.newPIN_;
+    this.updatePINButtonValid_();
+  },
+
+  /**
+   * Called by Polymer when the Set PIN button is activated.
+   * @private
+   */
+  pinSubmitNew_: function() {
+    this.setPINButtonValid_ = false;
+    this.browserProxy_.setPIN(this.currentPIN_, this.newPIN_).then(result => {
+      // This call always completes the process so result[0] is always 1.
+      // result[1] is a CTAP2 error code. See
+      // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#error-responses
+      if (result[1] == 0 /* SUCCESS */) {
+        this.shown_ = 'success';
+        this.finish_();
+      } else if (result[1] == 52 /* temporarily locked */) {
+        this.shown_ = 'reinsert';
+        this.finish_();
+      } else if (result[1] == 50 /* locked */) {
+        this.shown_ = 'locked';
+        this.finish_();
+      } else if (result[1] == 49 /* PIN_INVALID */) {
+        this.currentPIN_ = '';
+        this.currentPINValid_ = false;
+        this.retries_--;
+        this.mismatchErrorVisible_ = true;
+
+        // Focus cannot be set directly from within a backend callback. Also,
+        // directly focusing |currentPIN| doesn't always seem to work(!). Thus
+        // focus something else first, which is a hack that seems to solve the
+        // problem.
+        const preFocusTarget = this.$.newPIN;
+        const focusTarget = this.$.currentPIN;
+        window.setTimeout(function() {
+          preFocusTarget.focus();
+          focusTarget.focus();
+        }, 0);
+        this.fire('ui-ready');  // for test synchronization.
+      } else {
+        // Unknown error.
+        this.errorCode_ = result[1];
+        this.shown_ = 'error';
+        this.finish_();
+      }
+    });
+  },
+
+  /**
+   * Called by Polymer when |errorCode_| changes to set the error string.
+   * @param {number} code A CTAP error code.
+   * @private
+   */
+  pinFailed_: function(code) {
+    if (code === null) {
+      return '';
+    }
+    return this.i18n('securityKeysPINError', code.toString());
+  },
+
+  /**
+   * Called by Polymer to set the error text displayed when the user enters an
+   * incorrect PIN.
+   * @param {boolean} show Whether or not an error message should be shown.
+   * @param {number} retries The number of PIN attempts remaining.
+   * @return {string} The message to show under the text box.
+   * @private
+   */
+  mismatchErrorText_: function(show, retries) {
+    if (!show) {
+      return '';
+    }
+
+    let msg = this.i18n('securityKeysPINIncorrect');
+    // Warn the user if the number of retries is getting low.
+    if (1 < retries && retries <= 3) {
+      msg += ' ' +
+          this.i18n(
+              'securityKeysCurrentPINRetriesPl', this.retries_.toString());
+    } else if (retries == 1) {
+      msg += ' ' + this.i18n('securityKeysCurrentPINRetriesSin');
+    }
+    return msg;
+  },
+
+  /**
+   * @param {boolean} complete Whether the dialog process is complete.
+   * @return {string} The class of the Ok / Cancel button.
+   * @private
+   */
+  maybeActionButton_: function(complete) {
+    return complete ? 'action-button' : 'cancel-button';
+  },
+
+  /**
+   * @param {boolean} complete Whether the dialog process is complete.
+   * @return {string} The label of the Ok / Cancel button.
+   * @private
+   */
+  closeText_: function(complete) {
+    return this.i18n(complete ? 'ok' : 'cancel');
+  },
+});
+})();
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
new file mode 100644
index 0000000..fceb965
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
@@ -0,0 +1,38 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
+<link rel="import" href="../settings_shared_css.html">
+
+<link rel="import" href="security_keys_set_pin_dialog.html">
+<link rel="import" href="security_keys_reset_dialog.html">
+
+<dom-module id="security-keys-subpage">
+  <template>
+    <style include="settings-shared"></style>
+
+    <cr-link-row
+      class="hr"
+      label="$i18n{securityKeysSetPIN}"
+      sub-label="$i18n{securityKeysSetPINDesc}"
+      on-click="onSetPIN_"></cr-link-row>
+    <cr-link-row
+      class="hr"
+      label="$i18n{securityKeysReset}"
+      sub-label="$i18n{securityKeysResetDesc}"
+      on-click="onReset_"></cr-link-row>
+
+    <template is="dom-if" if="[[showSetPINDialog_]]" restamp>
+      <settings-security-keys-set-pin-dialog on-close="onSetPINDialogClosed_">
+      </settings-security-keys-set-pin-dialog>
+    </template>
+
+    <template is="dom-if" if="[[showResetDialog_]]" restamp>
+      <settings-security-keys-reset-dialog on-close="onResetDialogClosed_">
+      </settings-security-keys-reset-dialog>
+    </template>
+
+  </template>
+  <script src="security_keys_subpage.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_subpage.js b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.js
new file mode 100644
index 0000000..a27010d
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_subpage.js
@@ -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.
+
+/**
+ * @fileoverview 'security-keys-subpage' is a settings subpage
+ * containing operations on security keys.
+ */
+Polymer({
+  is: 'security-keys-subpage',
+
+  properties: {
+    /** @private */
+    showSetPINDialog_: {
+      type: Boolean,
+      value: false,
+    },
+    /** @private */
+    showResetDialog_: {
+      type: Boolean,
+      value: false,
+    },
+  },
+
+  /** @private */
+  onSetPIN_: function() {
+    this.showSetPINDialog_ = true;
+  },
+
+  /** @private */
+  onSetPINDialogClosed_: function() {
+    this.showSetPINDialog_ = false;
+    cr.ui.focusWithoutInk(this.$.setPINButton);
+  },
+
+  /** @private */
+  onReset_: function() {
+    this.showResetDialog_ = true;
+  },
+
+  /** @private */
+  onResetDialogClosed_: function() {
+    this.showResetDialog_ = false;
+    cr.ui.focusWithoutInk(this.$.resetButton);
+  },
+});
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 337b8c1..82d15f5 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -68,6 +68,7 @@
  *   RESET_DIALOG: (undefined|!settings.Route),
  *   SEARCH: (undefined|!settings.Route),
  *   SEARCH_ENGINES: (undefined|!settings.Route),
+ *   SECURITY_KEYS: (undefined|!settings.Route),
  *   SIGN_OUT: (undefined|!settings.Route),
  *   SITE_SETTINGS: (undefined|!settings.Route),
  *   SITE_SETTINGS_ADS: (undefined|!settings.Route),
@@ -324,6 +325,9 @@
         r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy');
         r.CERTIFICATES = r.PRIVACY.createChild('/certificates');
         r.SITE_SETTINGS = r.PRIVACY.createChild('/content');
+        if (loadTimeData.getBoolean('enableSecurityKeysSubpage')) {
+          r.SECURITY_KEYS = r.PRIVACY.createChild('/securityKeys');
+        }
       }
 
       if (loadTimeData.getBoolean('enableSiteSettings')) {
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index dbff3ba..029c2ee 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -368,6 +368,30 @@
       <structure name="IDR_SETTINGS_HISTORY_DELETION_DIALOG_JS"
                  file="clear_browsing_data_dialog/history_deletion_dialog.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_PAGE_HTML"
+                 file="privacy_page/security_keys_subpage.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_PAGE_JS"
+                 file="privacy_page/security_keys_subpage.js"
+                 type="chrome_html"/>
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_SET_PIN_DIALOG_HTML"
+                 file="privacy_page/security_keys_set_pin_dialog.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_SET_PIN_DIALOG_JS"
+                 file="privacy_page/security_keys_set_pin_dialog.js"
+                 type="chrome_html"/>
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_RESET_DIALOG_HTML"
+                 file="privacy_page/security_keys_reset_dialog.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_RESET_DIALOG_JS"
+                 file="privacy_page/security_keys_reset_dialog.js"
+                 type="chrome_html"/>
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_DIALOG_BROWSER_PROXY_HTML"
+                 file="privacy_page/security_keys_browser_proxy.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SECURITY_KEYS_DIALOG_BROWSER_PROXY_JS"
+                 file="privacy_page/security_keys_browser_proxy.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_HTML"
                  file="controls/settings_boolean_control_behavior.html"
                  type="chrome_html" />
diff --git a/chrome/browser/send_tab_to_self/desktop_notification_handler.cc b/chrome/browser/send_tab_to_self/desktop_notification_handler.cc
index 01131039..f9142ff 100644
--- a/chrome/browser/send_tab_to_self/desktop_notification_handler.cc
+++ b/chrome/browser/send_tab_to_self/desktop_notification_handler.cc
@@ -45,7 +45,7 @@
       message_center::NOTIFICATION_TYPE_SIMPLE, entry->GetGUID(),
       base::UTF8ToUTF16(entry->GetTitle()), device_info, gfx::Image(),
       base::UTF8ToUTF16(url.host()), url, message_center::NotifierId(url),
-      optional_fields, nullptr);
+      optional_fields, /*delegate=*/nullptr);
   NotificationDisplayServiceFactory::GetForProfile(profile_)->Display(
       NotificationHandler::Type::SEND_TAB_TO_SELF, notification);
 }
@@ -84,12 +84,31 @@
   Navigate(&params);
   NotificationDisplayServiceFactory::GetForProfile(profile)->Close(
       NotificationHandler::Type::SEND_TAB_TO_SELF, notification_id);
-
+  // Delete the entry in SendTabToSelfModel
   SendTabToSelfSyncServiceFactory::GetForProfile(profile)
       ->GetSendTabToSelfModel()
       ->DeleteEntry(notification_id);
-
   std::move(completed_closure).Run();
 }
 
+void DesktopNotificationHandler::DisplaySendingConfirmation(
+    const SendTabToSelfEntry* entry) {
+  const GURL& url = entry->GetURL();
+  // Declare a notification
+  message_center::Notification notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE, entry->GetGUID(),
+      l10n_util::GetStringUTF16(
+          IDS_MESSAGE_NOTIFICATION_SEND_TAB_TO_SELF_CONFIRMATION_SUCCESS),
+      base::UTF8ToUTF16(entry->GetTitle()), gfx::Image(),
+      base::UTF8ToUTF16(url.host()), url, message_center::NotifierId(url),
+      message_center::RichNotificationData(), /*delegate=*/nullptr);
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->Display(
+      NotificationHandler::Type::SEND_TAB_TO_SELF, notification);
+}
+
+void DesktopNotificationHandler::DisplayFailureMessage() {
+  // TODO(crbug/942206): implement after the design has been finalized
+  NOTIMPLEMENTED();
+}
+
 }  // namespace send_tab_to_self
diff --git a/chrome/browser/send_tab_to_self/desktop_notification_handler.h b/chrome/browser/send_tab_to_self/desktop_notification_handler.h
index 62524ca2..110d23f 100644
--- a/chrome/browser/send_tab_to_self/desktop_notification_handler.h
+++ b/chrome/browser/send_tab_to_self/desktop_notification_handler.h
@@ -43,6 +43,13 @@
                const base::Optional<base::string16>& reply,
                base::OnceClosure completed_closure) override;
 
+  // When the user share a tab, a confirmation notification will be shown.
+  // Displays a notification telling the user that the tab was successfully
+  // sent.
+  void DisplaySendingConfirmation(const SendTabToSelfEntry* entry);
+  // Displays a notification telling the user that the tab could not be sent.
+  void DisplayFailureMessage();
+
  protected:
   Profile* const profile_;
   DISALLOW_COPY_AND_ASSIGN(DesktopNotificationHandler);
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
index 71a5a50..7926de2 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
@@ -8,6 +8,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/send_tab_to_self/desktop_notification_handler.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
@@ -72,9 +73,15 @@
 void CreateNewEntry(content::WebContents* tab, Profile* profile) {
   GURL url = tab->GetURL();
   std::string title = base::UTF16ToUTF8(tab->GetTitle());
-  SendTabToSelfSyncServiceFactory::GetForProfile(profile)
-      ->GetSendTabToSelfModel()
-      ->AddEntry(url, title);
+  const send_tab_to_self::SendTabToSelfEntry* entry =
+      SendTabToSelfSyncServiceFactory::GetForProfile(profile)
+          ->GetSendTabToSelfModel()
+          ->AddEntry(url, title);
+  if (entry) {
+    DesktopNotificationHandler(profile).DisplaySendingConfirmation(entry);
+  } else {
+    DesktopNotificationHandler(profile).DisplayFailureMessage();
+  }
 }
 
 }  // namespace send_tab_to_self
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc
index 3de5f90..79d3b5be 100644
--- a/chrome/browser/ui/ash/session_controller_client.cc
+++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -37,7 +37,7 @@
 #include "chromeos/assistant/buildflags.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index 995ce794..a4431a1 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -33,7 +33,7 @@
 #include "chrome/common/url_constants.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 2afa294..8973956a 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -1994,11 +1994,10 @@
 
 void BookmarkBarView::InsertBookmarkButtonAtIndex(views::View* button,
                                                   int index) {
-  int offset = GetIndexOf(managed_bookmarks_button_) + 1;
 // All of the secondary buttons are always in the view hierarchy, even if
 // they're not visible. The order should be: [Apps shortcut] [Managed bookmark
 // button] ..bookmark buttons.. [Overflow chevron] [Other bookmarks]
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
   int view_index = 0;
   DCHECK_EQ(child_at(view_index++), apps_page_shortcut_);
   DCHECK_EQ(child_at(view_index++), managed_bookmarks_button_);
@@ -2012,7 +2011,7 @@
   DCHECK_EQ(child, overflow_button_);
   DCHECK_EQ(child_at(view_index++), other_bookmarks_button_);
 #endif
-  AddChildViewAt(button, offset + index);
+  AddChildViewAt(button, GetIndexOf(managed_bookmarks_button_) + 1 + index);
 }
 
 int BookmarkBarView::GetIndexForButton(views::View* button) {
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index f2d3921..47f62608 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -166,6 +166,12 @@
   find_text_->SetTextInputFlags(ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF);
   AddChildView(find_text_);
 
+  match_count_text_->SetEventTargeter(
+      std::make_unique<views::ViewTargeter>(this));
+  AddChildView(match_count_text_);
+
+  AddChildView(separator_);
+
   find_previous_button_->set_id(VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON);
   find_previous_button_->SetFocusForPlatform();
   find_previous_button_->SetTooltipText(
@@ -195,14 +201,6 @@
 
   EnableCanvasFlippingForRTLUI(true);
 
-  match_count_text_->SetEventTargeter(
-      std::make_unique<views::ViewTargeter>(this));
-  AddChildViewAt(match_count_text_, 1);
-
-  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
-
-  AddChildViewAt(separator_, 2);
-
   // Normally we could space objects horizontally by simply passing a constant
   // value to BoxLayout for between-child spacing.  But for the vector image
   // buttons, we want the spacing to apply between the inner "glyph" portions
@@ -211,6 +209,7 @@
   // we place views directly adjacent, with horizontal margins on each view
   // that will add up to the right spacing amounts.
 
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
   const gfx::Insets horizontal_margin(
       0,
       provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL) / 2);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 3e03982..bc2722a7 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -672,15 +672,14 @@
   // https://crbug.com/840242. To fix this, we'll make the caption buttons
   // temporarily children of the TopContainerView while they're all painting to
   // their layers.
-  browser_view()->top_container()->AddChildViewAt(caption_button_container_, 0);
-  if (hosted_app_button_container()) {
-    browser_view()->top_container()->AddChildViewAt(
-        hosted_app_button_container(), 0);
-  }
+  auto* container = browser_view()->top_container();
+  container->AddChildViewAt(caption_button_container_, 0);
+  if (hosted_app_button_container())
+    container->AddChildViewAt(hosted_app_button_container(), 0);
   if (back_button_)
-    browser_view()->top_container()->AddChildViewAt(back_button_, 0);
+    container->AddChildViewAt(back_button_, 0);
 
-  browser_view()->top_container()->Layout();
+  container->Layout();
 }
 
 void BrowserNonClientFrameViewAsh::OnImmersiveRevealEnded() {
diff --git a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
index 4855669..80da07471 100644
--- a/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_menu_button.cc
@@ -76,7 +76,9 @@
                                               const ui::Event* event) {
   Browser* browser = browser_view_->browser();
   RunMenu(std::make_unique<HostedAppMenuModel>(browser_view_, browser), browser,
-          AppMenu::NO_FLAGS, false);
+          event && event->IsKeyEvent() ? AppMenu::SHOW_MNEMONICS
+                                       : AppMenu::NO_FLAGS,
+          false);
 
   // Add UMA for how many times the hosted app menu button are clicked.
   base::RecordAction(
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index dc3333b..ac8a9e3 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -360,7 +360,7 @@
   // There will be no parent when this infobar is not in a container, e.g. if
   // it's in a background tab.  It's still possible to reach here in that case,
   // e.g. if ElevationIconSetter triggers a Layout().
-  return parent() && parent()->GetIndexOf(this) != 0;
+  return parent() && parent()->child_at(0) != this;
 }
 
 int InfoBarView::GetSeparatorHeightDip() const {
diff --git a/chrome/browser/ui/views/media_router/app_menu_test_api_views.cc b/chrome/browser/ui/views/media_router/app_menu_test_api_views.cc
index 04018e5..815e081 100644
--- a/chrome/browser/ui/views/media_router/app_menu_test_api_views.cc
+++ b/chrome/browser/ui/views/media_router/app_menu_test_api_views.cc
@@ -42,7 +42,7 @@
 }
 
 void AppMenuTestApiViews::ShowMenu() {
-  GetAppMenuButton()->ShowMenu(false);
+  GetAppMenuButton()->ShowMenu(AppMenu::NO_FLAGS);
 }
 
 void AppMenuTestApiViews::ExecuteCommand(int command) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 53df986..e6b0431 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -157,7 +157,7 @@
   for (size_t i = 0; i < AutocompleteResult::GetMaxMatches(); ++i) {
     OmniboxResultView* result_view = new OmniboxResultView(this, i);
     result_view->SetVisible(false);
-    AddChildViewAt(result_view, static_cast<int>(i));
+    AddChildView(result_view);
   }
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index b269f06..1c878366 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <memory>
 
+#include "base/metrics/field_trial_params.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
@@ -25,11 +26,6 @@
 
 namespace {
 
-constexpr base::TimeDelta kMinimumTriggerDelay =
-    base::TimeDelta::FromMilliseconds(50);
-constexpr base::TimeDelta kMaximumTriggerDelay =
-    base::TimeDelta::FromMilliseconds(1000);
-
 // Hover card and preview image dimensions.
 int GetPreferredTabHoverCardWidth() {
   return TabStyle::GetStandardWidth();
@@ -45,6 +41,39 @@
   return base::FeatureList::IsEnabled(features::kTabHoverCardImages);
 }
 
+// Get delay threshold based on flag settings option selected. This is for
+// user testing.
+// TODO(corising): remove this after user study is completed.
+base::TimeDelta GetMinimumTriggerDelay() {
+  int delay_group = base::GetFieldTrialParamByFeatureAsInt(
+      features::kTabHoverCards, features::kTabHoverCardsFeatureParameterName,
+      0);
+  switch (delay_group) {
+    case 2:
+      return base::TimeDelta::FromMilliseconds(500);
+    case 1:
+      return base::TimeDelta::FromMilliseconds(200);
+    case 0:
+    default:
+      return base::TimeDelta::FromMilliseconds(0);
+  }
+}
+
+base::TimeDelta GetMaximumTriggerDelay() {
+  int delay_group = base::GetFieldTrialParamByFeatureAsInt(
+      features::kTabHoverCards, features::kTabHoverCardsFeatureParameterName,
+      0);
+  switch (delay_group) {
+    case 2:
+      return base::TimeDelta::FromMilliseconds(1000);
+    case 1:
+      return base::TimeDelta::FromMilliseconds(700);
+    case 0:
+    default:
+      return base::TimeDelta::FromMilliseconds(0);
+  }
+}
+
 }  // namespace
 
 TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab)
@@ -142,14 +171,17 @@
   //           |___________________________________________ tab width
   //               |                                |
   //       pinned tab width               standard tab width
+  base::TimeDelta minimum_trigger_delay = GetMinimumTriggerDelay();
   if (tab_width < TabStyle::GetPinnedWidth())
-    return kMinimumTriggerDelay;
+    return minimum_trigger_delay;
+  base::TimeDelta maximum_trigger_delay = GetMaximumTriggerDelay();
   double logarithmic_fraction =
       std::log(tab_width - TabStyle::GetPinnedWidth() + 1) /
       std::log(TabStyle::GetStandardWidth() - TabStyle::GetPinnedWidth() + 1);
-  base::TimeDelta scaling_factor = kMaximumTriggerDelay - kMinimumTriggerDelay;
+  base::TimeDelta scaling_factor =
+      maximum_trigger_delay - minimum_trigger_delay;
   base::TimeDelta delay =
-      logarithmic_fraction * scaling_factor + kMinimumTriggerDelay;
+      logarithmic_fraction * scaling_factor + minimum_trigger_delay;
   return delay;
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index 46d77a4..44d6f38 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -36,13 +36,6 @@
  private:
   friend class TabHoverCardBubbleViewBrowserTest;
 
-  base::OneShotTimer delayed_show_timer_;
-
-  views::Widget* widget_ = nullptr;
-  views::Label* title_label_;
-  views::Label* domain_label_;
-  views::ImageView* preview_image_ = nullptr;
-
   // Get delay in milliseconds based on tab width.
   base::TimeDelta GetDelay(int tab_width) const;
 
@@ -52,6 +45,15 @@
   void UpdateCardContent(TabRendererData data);
 
   gfx::Size CalculatePreferredSize() const override;
+
+  base::OneShotTimer delayed_show_timer_;
+
+  views::Widget* widget_ = nullptr;
+  views::Label* title_label_ = nullptr;
+  views::Label* domain_label_ = nullptr;
+  views::ImageView* preview_image_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(TabHoverCardBubbleView);
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index bd1a606..978bf8a 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -413,11 +413,9 @@
 }
 
 void TabStrip::AddTabAt(int model_index, TabRendererData data, bool is_active) {
-  // Get view child index of where we want to insert
-  int view_index = 0;
-  if (model_index > 0) {
-    view_index = GetIndexOf(tab_at(model_index - 1)) + 1;
-  }
+  // Get view child index of where we want to insert.
+  const int view_index =
+      (model_index > 0) ? (GetIndexOf(tab_at(model_index - 1)) + 1) : 0;
 
   Tab* tab = new Tab(this);
   AddChildViewAt(tab, view_index);
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 1455acc..956a9db 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -804,6 +804,9 @@
     // BrowserActionsContainer view.
     types |= views::MenuRunner::FOR_DROP | views::MenuRunner::NESTED_DRAG;
   }
+  if (run_flags_ & AppMenu::SHOW_MNEMONICS)
+    types |= views::MenuRunner::SHOULD_SHOW_MNEMONICS;
+
   menu_runner_.reset(new views::MenuRunner(root_, types));
 }
 
diff --git a/chrome/browser/ui/views/toolbar/app_menu.h b/chrome/browser/ui/views/toolbar/app_menu.h
index 91c883c..7975fee 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.h
+++ b/chrome/browser/ui/views/toolbar/app_menu.h
@@ -35,10 +35,15 @@
                 public content::NotificationObserver,
                 public base::SupportsWeakPtr<AppMenu> {
  public:
+  // TODO(cyan): Remove this enum and use MenuRunner::RunTypes instead.
   enum RunFlags {
     NO_FLAGS = 0,
+
     // Indicates that the menu was opened for a drag-and-drop operation.
     FOR_DROP = 1 << 0,
+
+    // Indicates that the menu should show mnemonics.
+    SHOW_MNEMONICS = 1 << 1,
   };
 
   AppMenu(Browser* browser, int run_flags, bool alert_reopen_tab_items);
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index 22ac7e15..b63d874 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -218,7 +218,7 @@
 }
 #endif
 
-void BrowserAppMenuButton::ShowMenu(bool for_drop) {
+void BrowserAppMenuButton::ShowMenu(int run_types) {
   if (IsMenuShowing())
     return;
 
@@ -234,13 +234,13 @@
   alert_reopen_tab_items = promo_feature_ == InProductHelpFeature::kReopenTab;
 #endif
   base::TimeTicks menu_open_time = base::TimeTicks::Now();
+
   RunMenu(
       std::make_unique<AppMenuModel>(toolbar_view_, browser,
                                      toolbar_view_->app_menu_icon_controller()),
-      browser, for_drop ? AppMenu::FOR_DROP : AppMenu::NO_FLAGS,
-      alert_reopen_tab_items);
+      browser, run_types, alert_reopen_tab_items);
 
-  if (!for_drop) {
+  if (!(run_types & AppMenu::FOR_DROP)) {
     // Record the time-to-action for the menu. We don't record in the case of a
     // drag-and-drop command because menus opened for drag-and-drop don't block
     // the message loop.
@@ -370,14 +370,18 @@
 
 void BrowserAppMenuButton::OnDragEntered(const ui::DropTargetEvent& event) {
   DCHECK(!weak_factory_.HasWeakPtrs());
+  int run_types = AppMenu::FOR_DROP;
+  if (event.IsKeyEvent())
+    run_types |= AppMenu::SHOW_MNEMONICS;
+
   if (!g_open_app_immediately_for_testing) {
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&BrowserAppMenuButton::ShowMenu,
-                       weak_factory_.GetWeakPtr(), true),
+                       weak_factory_.GetWeakPtr(), run_types),
         base::TimeDelta::FromMilliseconds(views::GetMenuShowDelay()));
   } else {
-    ShowMenu(true);
+    ShowMenu(run_types);
   }
 }
 
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
index 74775f4..280f650 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
@@ -37,9 +37,9 @@
     return type_and_severity_.severity;
   }
 
-  // Shows the app menu. |for_drop| indicates whether the menu is opened for a
-  // drag-and-drop operation.
-  void ShowMenu(bool for_drop);
+  // Shows the app menu. |run_types| denotes the MenuRunner::RunTypes associated
+  // with the menu.
+  void ShowMenu(int run_types);
 
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
   // Called to inform the button that it's being used as an anchor for a promo
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 1d225eb..cc9ed0a 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/views/location_bar/star_view.h"
 #include "chrome/browser/ui/views/media_router/cast_toolbar_button.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/browser/ui/views/toolbar/app_menu.h"
 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
 #include "chrome/browser/ui/views/toolbar/browser_app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/home_button.h"
@@ -403,7 +404,7 @@
                                       const ui::Event* event) {
   TRACE_EVENT0("views", "ToolbarView::OnMenuButtonClicked");
   DCHECK_EQ(VIEW_ID_APP_MENU, source->id());
-  app_menu_button_->ShowMenu(false);  // Not for drop.
+  app_menu_button_->ShowMenu(AppMenu::NO_FLAGS);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 3f90052..87ca41c 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -365,12 +365,17 @@
 
   std::string gaps_cookie_value(kGAPSCookie);
   gaps_cookie_value += "=" + context.gaps_cookie;
+  net::CookieOptions options;
+  options.set_include_httponly();
+  // Permit it to set a SameSite cookie if it wants to.
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   std::unique_ptr<net::CanonicalCookie> cc(net::CanonicalCookie::Create(
       GaiaUrls::GetInstance()->gaia_url(), gaps_cookie_value, base::Time::Now(),
-      net::CookieOptions()));
+      options));
 
   partition->GetCookieManagerForBrowserProcess()->SetCanonicalCookie(
-      *cc.get(), "https", true /* modify_http_only */, std::move(callback));
+      *cc.get(), "https", options, std::move(callback));
 }
 
 void GaiaScreenHandler::OnSetCookieForLoadGaiaWithPartition(
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc
index ba35003..7d67e6b 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc
@@ -16,7 +16,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/login/localized_values_builder.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
index 4015441..50e3747 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/chromeos/login/screens/reset_screen.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/login/localized_values_builder.h"
 #include "components/strings/grit/components_strings.h"
 
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
index 97bae0b..d2b4388e 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
@@ -31,6 +31,58 @@
     screen_->OnViewDestroyed(this);
 }
 
+void UpdateScreenHandler::Show() {
+  if (!page_is_ready()) {
+    show_on_init_ = true;
+    return;
+  }
+  ShowScreen(kScreenId);
+}
+
+void UpdateScreenHandler::Hide() {}
+
+void UpdateScreenHandler::Bind(UpdateScreen* screen) {
+  screen_ = screen;
+  BaseScreenHandler::SetBaseScreen(screen_);
+}
+
+void UpdateScreenHandler::Unbind() {
+  screen_ = nullptr;
+  BaseScreenHandler::SetBaseScreen(nullptr);
+}
+
+void UpdateScreenHandler::SetEstimatedTimeLeft(int value) {
+  CallJS("login.UpdateScreen.setEstimatedTimeLeft", value);
+}
+
+void UpdateScreenHandler::SetShowEstimatedTimeLeft(bool value) {
+  CallJS("login.UpdateScreen.showEstimatedTimeLeft", value);
+}
+
+void UpdateScreenHandler::SetUpdateCompleted(bool value) {
+  CallJS("login.UpdateScreen.setUpdateCompleted", value);
+}
+
+void UpdateScreenHandler::SetShowCurtain(bool value) {
+  CallJS("login.UpdateScreen.showUpdateCurtain", value);
+}
+
+void UpdateScreenHandler::SetProgressMessage(const base::string16& value) {
+  CallJS("login.UpdateScreen.setProgressMessage", value);
+}
+
+void UpdateScreenHandler::SetProgress(int value) {
+  CallJS("login.UpdateScreen.setUpdateProgress", value);
+}
+
+void UpdateScreenHandler::SetRequiresPermissionForCellular(bool value) {
+  CallJS("login.UpdateScreen.setRequiresPermissionForCellular", value);
+}
+
+void UpdateScreenHandler::SetCancelUpdateShortcutEnabled(bool value) {
+  CallJS("login.UpdateScreen.setCancelUpdateShortcutEnabled", value);
+}
+
 void UpdateScreenHandler::DeclareLocalizedValues(
     ::login::LocalizedValuesBuilder* builder) {
   builder->Add("checkingForUpdatesMsg", IDS_CHECKING_FOR_UPDATE_MSG);
@@ -72,25 +124,4 @@
   }
 }
 
-void UpdateScreenHandler::Show() {
-  if (!page_is_ready()) {
-    show_on_init_ = true;
-    return;
-  }
-  ShowScreen(kScreenId);
-}
-
-void UpdateScreenHandler::Hide() {
-}
-
-void UpdateScreenHandler::Bind(UpdateScreen* screen) {
-  screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
-}
-
-void UpdateScreenHandler::Unbind() {
-  screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
index 5f864834..fbca33da 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
@@ -25,6 +25,14 @@
   void Hide() override;
   void Bind(UpdateScreen* screen) override;
   void Unbind() override;
+  void SetEstimatedTimeLeft(int value) override;
+  void SetShowEstimatedTimeLeft(bool value) override;
+  void SetUpdateCompleted(bool value) override;
+  void SetShowCurtain(bool value) override;
+  void SetProgressMessage(const base::string16& value) override;
+  void SetProgress(int value) override;
+  void SetRequiresPermissionForCellular(bool value) override;
+  void SetCancelUpdateShortcutEnabled(bool value) override;
 
   // BaseScreenHandler:
   void DeclareLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/set_time_ui_browsertest.js b/chrome/browser/ui/webui/chromeos/set_time_ui_browsertest.js
index ea19765..ead759c 100644
--- a/chrome/browser/ui/webui/chromeos/set_time_ui_browsertest.js
+++ b/chrome/browser/ui/webui/chromeos/set_time_ui_browsertest.js
@@ -2,11 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-GEN('#if defined(OS_CHROMEOS)');
-
 /**
  * SetTimeWebUITest tests loading and interacting with the SetTimeUI web UI,
- * which is normally shown as a dialog.
+ * which is normally shown as a dialog. Chrome OS only.
  * @constructor
  * @extends {testing.Test}
  */
@@ -48,5 +46,3 @@
   TimeSetter.setTimezone('Europe/Moscow');
   expectEquals('Europe/Moscow', $('timezone-select').value);
 });
-
-GEN('#endif');
diff --git a/chrome/browser/ui/webui/chromeos/slow_ui.cc b/chrome/browser/ui/webui/chromeos/slow_ui.cc
index 2e5b4c35..614813d 100644
--- a/chrome/browser/ui/webui/chromeos/slow_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/slow_ui.cc
@@ -49,9 +49,10 @@
   source->AddLocalizedString("slowDescription", IDS_SLOW_DESCRIPTION);
   source->AddLocalizedString("slowWarning", IDS_SLOW_WARNING);
 
-  source->SetJsonPath("strings.js");
   source->AddResourcePath("slow.js", IDR_SLOW_JS);
+  source->AddResourcePath("slow.css", IDR_SLOW_CSS);
   source->SetDefaultResource(IDR_SLOW_HTML);
+  source->UseGzip();
   return source;
 }
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 049f08da..4c5eb14 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -50,6 +50,7 @@
 #include "components/unified_consent/feature.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/content_features.h"
+#include "device/fido/features.h"
 #include "media/base/media_switches.h"
 #include "services/device/public/cpp/device_features.h"
 #include "ui/accessibility/accessibility_switches.h"
@@ -2816,6 +2817,50 @@
                                   IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL);
 }
 
+void AddSecurityKeysStrings(content::WebUIDataSource* html_source) {
+  static constexpr LocalizedString kSecurityKeysStrings[] = {
+      {"securityKeysTitle", IDS_SETTINGS_SECURITY_KEYS_TITLE},
+      {"securityKeysDesc", IDS_SETTINGS_SECURITY_KEYS_DESC},
+      {"securityKeysSetPIN", IDS_SETTINGS_SECURITY_KEYS_SET_PIN},
+      {"securityKeysSetPINDesc", IDS_SETTINGS_SECURITY_KEYS_SET_PIN_DESC},
+      {"securityKeysReset", IDS_SETTINGS_SECURITY_KEYS_RESET},
+      {"securityKeysResetDesc", IDS_SETTINGS_SECURITY_KEYS_RESET_DESC},
+      {"securityKeysResetTitle", IDS_SETTINGS_SECURITY_KEYS_RESET_TITLE},
+      {"securityKeysResetIntro", IDS_SETTINGS_SECURITY_KEYS_RESET_INTRO},
+      {"securityKeysResetStep1", IDS_SETTINGS_SECURITY_KEYS_RESET_STEP1},
+      {"securityKeysResetStep2", IDS_SETTINGS_SECURITY_KEYS_RESET_STEP2},
+      {"securityKeysNoReset", IDS_SETTINGS_SECURITY_KEYS_NO_RESET},
+      {"securityKeysResetError", IDS_SETTINGS_SECURITY_KEYS_RESET_ERROR},
+      {"securityKeysResetSuccess", IDS_SETTINGS_SECURITY_KEYS_RESET_SUCCESS},
+      {"securityKeysResetNotAllowed",
+       IDS_SETTINGS_SECURITY_KEYS_RESET_NOTALLOWED},
+      {"securityKeysPINDesc", IDS_SETTINGS_SECURITY_KEYS_PINS_DESC},
+      {"securityKeysPINTouch", IDS_SETTINGS_SECURITY_KEYS_PIN_TOUCH},
+      {"securityKeysNoPIN", IDS_SETTINGS_SECURITY_KEYS_NO_PIN},
+      {"securityKeysCurrentPINIntro",
+       IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_INTRO},
+      {"securityKeysPINIncorrect", IDS_SETTINGS_SECURITY_KEYS_PIN_INCORRECT},
+      {"securityKeysCurrentPINRetriesPl",
+       IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_RETRIES_PL},
+      {"securityKeysCurrentPINRetriesSin",
+       IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN_RETRIES_SIN},
+      {"securityKeysNewPIN", IDS_SETTINGS_SECURITY_KEYS_NEW_PIN},
+      {"securityKeysCurrentPIN", IDS_SETTINGS_SECURITY_KEYS_CURRENT_PIN},
+      {"securityKeysPIN", IDS_SETTINGS_SECURITY_KEYS_PIN},
+      {"securityKeysConfirmPIN", IDS_SETTINGS_SECURITY_KEYS_CONFIRM_PIN},
+      {"securityKeysPINSuccess", IDS_SETTINGS_SECURITY_KEYS_PIN_SUCCESS},
+      {"securityKeysPINError", IDS_SETTINGS_SECURITY_KEYS_PIN_ERROR},
+      {"securityKeysPINHardLock", IDS_SETTINGS_SECURITY_KEYS_PIN_HARD_LOCK},
+      {"securityKeysPINSoftLock", IDS_SETTINGS_SECURITY_KEYS_PIN_SOFT_LOCK},
+  };
+  AddLocalizedStringsBulk(html_source, kSecurityKeysStrings,
+                          base::size(kSecurityKeysStrings));
+
+  html_source->AddBoolean(
+      "enableSecurityKeysSubpage",
+      base::FeatureList::IsEnabled(device::kWebAuthPINSupport));
+}
+
 }  // namespace
 
 void AddLocalizedStrings(content::WebUIDataSource* html_source,
@@ -2880,6 +2925,7 @@
   chromeos::network_element::AddErrorLocalizedStrings(html_source);
 #endif
   policy_indicator::AddLocalizedStrings(html_source);
+  AddSecurityKeysStrings(html_source);
 
   html_source->SetJsonPath(kLocalizedStringsFile);
 }
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 153a0e1..6ded0f88 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
 application: chrome-apps-doc
-version: 3-64-0
+version: 3-65-0
 runtime: python27
 api_version: 1
 threadsafe: false
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index be08d74..56566f9 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -35,7 +35,6 @@
 #include "extensions/renderer/bindings/api_bindings_system.h"
 #include "extensions/renderer/css_native_handler.h"
 #include "extensions/renderer/dispatcher.h"
-#include "extensions/renderer/i18n_custom_bindings.h"
 #include "extensions/renderer/lazy_background_page_native_handler.h"
 #include "extensions/renderer/native_extension_bindings_system.h"
 #include "extensions/renderer/native_handler.h"
@@ -112,9 +111,6 @@
   // there's no reason to have its native handlers residing and being compiled
   // in //extensions.
   module_system->RegisterNativeHandler(
-      "i18n", std::unique_ptr<NativeHandler>(
-                  new extensions::I18NCustomBindings(context)));
-  module_system->RegisterNativeHandler(
       "lazy_background_page",
       std::unique_ptr<NativeHandler>(
           new extensions::LazyBackgroundPageNativeHandler(context)));
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 57303fb2..155c562 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -651,7 +651,6 @@
       "../browser/data_saver/data_saver_holdback_browsertest.cc",
       "../browser/data_saver/data_saver_webapis_browsertest.cc",
       "../browser/data_use_measurement/data_use_measurement_browsertest.cc",
-      "../browser/data_use_measurement/page_load_capping/page_load_capping_browsertest.cc",
       "../browser/devtools/device/adb/adb_client_socket_browsertest.cc",
       "../browser/devtools/device/adb/mock_adb_server.cc",
       "../browser/devtools/device/adb/mock_adb_server.h",
@@ -2613,8 +2612,6 @@
     "../browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_unittest.cc",
     "../browser/data_reduction_proxy/data_reduction_proxy_settings_unittest_android.cc",
     "../browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc",
-    "../browser/data_use_measurement/page_load_capping/page_load_capping_blacklist_unittest.cc",
-    "../browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc",
     "../browser/download/chrome_download_manager_delegate_unittest.cc",
     "../browser/download/download_history_unittest.cc",
     "../browser/download/download_item_model_unittest.cc",
@@ -2737,7 +2734,6 @@
     "../browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer_unittest.cc",
-    "../browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc",
     "../browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h",
     "../browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc",
diff --git a/chrome/test/data/data_use_measurement/page_capping.html b/chrome/test/data/data_use_measurement/page_capping.html
deleted file mode 100644
index f065fc3..0000000
--- a/chrome/test/data/data_use_measurement/page_capping.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<head>
-<title> Display an image </title>
-</head>
-<body>
-</body>
-</html>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 32faf5c..babfa5c 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -38,12 +38,8 @@
   # and are handled by a rule, but in the GN build they're in a separate
   # action so need to be separated out.
   sources = [
-    "../../../browser/ui/webui/chromeos/bluetooth_pairing_dialog_browsertest.js",
-    "../../../browser/ui/webui/chromeos/certificate_manager_dialog_browsertest.js",
-    "../../../browser/ui/webui/chromeos/set_time_ui_browsertest.js",
     "../../../browser/ui/webui/identity_internals_ui_browsertest.js",
     "../../../browser/ui/webui/sync_internals_browsertest.js",
-    "../chromeos/oobe_webui_browsertest.js",
     "//third_party/axe-core/axe.js",
     "a11y/accessibility_audit_rules.js",
     "a11y/accessibility_test.js",
@@ -73,14 +69,8 @@
     "settings/a11y/accessibility_a11y_test.js",
     "settings/a11y/basic_a11y_test.js",
     "settings/a11y/edit_dictionary_a11y_test.js",
-    "settings/a11y/manage_accessibility_a11y_test.js",
-    "settings/a11y/manage_profile_a11y_test.js",
-    "settings/a11y/multidevice_a11y_test.js",
-    "settings/a11y/multidevice_features_a11y_test.js",
     "settings/a11y/passwords_a11y_test.js",
     "settings/a11y/settings_accessibility_test.js",
-    "settings/a11y/sign_out_a11y_test.js",
-    "settings/a11y/tts_subpage_a11y_test.js",
     "settings/advanced_page_browsertest.js",
     "settings/basic_page_browsertest.js",
     "settings/cr_settings_browsertest.js",
@@ -101,13 +91,23 @@
 
   if (is_chromeos) {
     sources += [
+      "../../../browser/ui/webui/chromeos/bluetooth_pairing_dialog_browsertest.js",
+      "../../../browser/ui/webui/chromeos/certificate_manager_dialog_browsertest.js",
+      "../../../browser/ui/webui/chromeos/set_time_ui_browsertest.js",
+      "../chromeos/oobe_webui_browsertest.js",
       "certificate_viewer_dialog_test.js",
       "md_set_time_browsertest.js",
+      "settings/a11y/manage_accessibility_a11y_test.js",
+      "settings/a11y/multidevice_a11y_test.js",
+      "settings/a11y/multidevice_features_a11y_test.js",
+      "settings/a11y/tts_subpage_a11y_test.js",
       "sys_internals/sys_internals_browsertest.js",
     ]
   } else {
     sources += [
       "md_user_manager/user_manager_browsertest.js",
+      "settings/a11y/manage_profile_a11y_test.js",
+      "settings/a11y/sign_out_a11y_test.js",
       "signin/signin_browsertest.js",
       "welcome/onboarding_welcome_browsertest.js",
     ]
diff --git a/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js b/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js
index 9c1897fe..87e14d0 100644
--- a/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js
+++ b/chrome/test/data/webui/multidevice_setup/multidevice_setup_browsertest.js
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @fileoverview Tests for MultiDevice unified setup WebUI. */
-
-GEN('#if defined(OS_CHROMEOS)');
+/** @fileoverview Tests for MultiDevice unified setup WebUI. Chrome OS only. */
 
 /** @const {string} Path to source root. */
 var ROOT_PATH = '../../../../../';
@@ -50,5 +48,3 @@
   multidevice_setup.registerStartSetupPageTests();
   mocha.run();
 });
-
-GEN('#endif');
diff --git a/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js b/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js
index 66454f2..04c7faa4 100644
--- a/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js
@@ -4,11 +4,9 @@
 
 /**
  * @fileoverview Define accessibility tests for the MANAGE_ACCESSIBILITY route.
+ * Chrome OS only.
  */
 
-// This is only for Chrome OS.
-GEN('#if defined(OS_CHROMEOS)');
-
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
   'settings_accessibility_test.js',
@@ -29,5 +27,3 @@
   /** @override */
   violationFilter: SettingsAccessibilityTest.violationFilter,
 });
-
-GEN('#endif  // defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/a11y/manage_profile_a11y_test.js b/chrome/test/data/webui/settings/a11y/manage_profile_a11y_test.js
index 1e85f5a4..16db9d8 100644
--- a/chrome/test/data/webui/settings/a11y/manage_profile_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/manage_profile_a11y_test.js
@@ -4,11 +4,9 @@
 
 /**
  * @fileoverview Define accessibility tests for the MANAGE_PROFILE route.
+ * Non-Chrome OS only.
  */
 
-// The MANAGE_PROFILE route is non-Chrome OS only.
-GEN('#if !defined(OS_CHROMEOS)');
-
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
   'settings_accessibility_test.js',
@@ -41,5 +39,3 @@
         },
       }),
 });
-
-GEN('#endif  // !defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/a11y/multidevice_a11y_test.js b/chrome/test/data/webui/settings/a11y/multidevice_a11y_test.js
index a0892c9a..91688c8 100644
--- a/chrome/test/data/webui/settings/a11y/multidevice_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/multidevice_a11y_test.js
@@ -4,11 +4,9 @@
 
 /**
  * @fileoverview Define accessibility tests for the MULTIDEVICE route.
+ * Chrome OS only.
  */
 
-// This is only for Chrome OS.
-GEN('#if defined(OS_CHROMEOS)');
-
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
   'settings_accessibility_test.js',
@@ -29,5 +27,3 @@
   /** @override */
   violationFilter: SettingsAccessibilityTest.violationFilter,
 });
-
-GEN('#endif  // defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/a11y/multidevice_features_a11y_test.js b/chrome/test/data/webui/settings/a11y/multidevice_features_a11y_test.js
index 8aef3763..351cca2 100644
--- a/chrome/test/data/webui/settings/a11y/multidevice_features_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/multidevice_features_a11y_test.js
@@ -4,11 +4,9 @@
 
 /**
  * @fileoverview Define accessibility tests for the MULTIDEVICE_FEATURES route.
+ * Chrome OS only.
  */
 
-// This is only for Chrome OS.
-GEN('#if defined(OS_CHROMEOS)');
-
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
   'settings_accessibility_test.js',
@@ -37,5 +35,3 @@
         },
       }),
 });
-
-GEN('#endif  // defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js b/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js
index 05be4d5..e94cc90 100644
--- a/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/sign_out_a11y_test.js
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @fileoverview Suite of accessibility tests for the SIGN_OUT route. */
-
-// Do not test the SIGN_OUT route on Chrome OS since signing out is done at the
-// OS level, not within the Chrome Browser.
-GEN('#if !defined(OS_CHROMEOS)');
+/**
+ * @fileoverview Suite of accessibility tests for the SIGN_OUT route.
+ * Not used on Chrome OS since signing out is done at the OS level, not within
+ * the Chrome Browser.
+ */
 
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
@@ -114,5 +114,3 @@
   /** @override */
   violationFilter: SettingsAccessibilityTest.violationFilter,
 });
-
-GEN('#endif  // !defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js b/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js
index 2beb0f4e..84e3a31 100644
--- a/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js
+++ b/chrome/test/data/webui/settings/a11y/tts_subpage_a11y_test.js
@@ -4,11 +4,9 @@
 
 /**
  * @fileoverview Define accessibility tests for the MANAGE_TTS_SETTINGS route.
+ * Chrome OS only.
  */
 
-// This is only for Chrome OS.
-GEN('#if defined(OS_CHROMEOS)');
-
 // SettingsAccessibilityTest fixture.
 GEN_INCLUDE([
   'settings_accessibility_test.js',
@@ -36,5 +34,3 @@
   /** @override */
   violationFilter: SettingsAccessibilityTest.violationFilter,
 });
-
-GEN('#endif  // defined(OS_CHROMEOS)');
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 9e316b4..a63af80b 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1440,6 +1440,32 @@
 });
 
 /**
+ * Test fixture for
+ * chrome/browser/resources/settings/privacy_page/security_keys_subpage.html
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsSecurityKeysSubpageTest() {}
+
+CrSettingsSecurityKeysSubpageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings/privacy_page/security_keys_subpage.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'test_util.js',
+    '../test_browser_proxy.js',
+    'security_keys_subpage_test.js',
+  ]),
+};
+
+TEST_F('CrSettingsSecurityKeysSubpageTest', 'All', function() {
+  mocha.run();
+});
+
+/**
  * @constructor
  * @extends {CrSettingsBrowserTest}
  */
diff --git a/chrome/test/data/webui/settings/security_keys_subpage_test.js b/chrome/test/data/webui/settings/security_keys_subpage_test.js
new file mode 100644
index 0000000..fc2a392
--- /dev/null
+++ b/chrome/test/data/webui/settings/security_keys_subpage_test.js
@@ -0,0 +1,436 @@
+// 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.
+
+/** @implements {settings.SecurityKeysBrowserProxy} */
+class TestSecurityKeysBrowserProxy extends TestBrowserProxy {
+  constructor() {
+    super([
+      'startSetPIN',
+      'setPIN',
+      'reset',
+      'completeReset',
+      'close',
+    ]);
+
+    /**
+     * A map from method names to a promise to return when that method is
+     * called. (If no promise is installed, a never-resolved promise is
+     * returned.)
+     * @private {!Map<string, !Promise>}
+     */
+    this.promiseMap_ = new Map();
+  }
+
+  /**
+   * @param {string} methodName
+   * @param {!Promise} promise
+   */
+  setResponseFor(methodName, promise) {
+    this.promiseMap_.set(methodName, promise);
+  }
+
+  /**
+   * @param {string} methodName
+   * @param {*} opt_arg
+   * @return {!Promise}
+   * @private
+   */
+  handleMethod_(methodName, opt_arg) {
+    this.methodCalled(methodName, opt_arg);
+    const promise = this.promiseMap_.get(methodName);
+    if (promise != undefined) {
+      this.promiseMap_.delete(methodName);
+      return promise;
+    }
+
+    // Return a Promise that never resolves.
+    return new Promise(() => {});
+  }
+
+  /** @override */
+  startSetPIN() {
+    return this.handleMethod_('startSetPIN');
+  }
+
+  /** @override */
+  setPIN(oldPIN, newPIN) {
+    return this.handleMethod_('setPIN', {oldPIN, newPIN});
+  }
+
+  /** @override */
+  reset() {
+    return this.handleMethod_('reset');
+  }
+
+  /** @override */
+  completeReset() {
+    return this.handleMethod_('completeReset');
+  }
+
+  /** @override */
+  close() {
+    this.methodCalled('close');
+  }
+}
+
+suite('SecurityKeysResetDialog', function() {
+  let dialog = null;
+
+  setup(function() {
+    browserProxy = new TestSecurityKeysBrowserProxy();
+    settings.SecurityKeysBrowserProxyImpl.instance_ = browserProxy;
+    PolymerTest.clearBody();
+    dialog = document.createElement('settings-security-keys-reset-dialog');
+  });
+
+  function assertShown(expectedID) {
+    const allDivs = [
+      'initial', 'noReset', 'resetFailed', 'reset2', 'resetSuccess',
+      'resetNotAllowed'
+    ];
+    assertTrue(allDivs.includes(expectedID));
+
+    const allShown =
+        allDivs.filter(id => dialog.$[id].className == 'iron-selected');
+    assertEquals(allShown.length, 1);
+    assertEquals(allShown[0], expectedID);
+  }
+
+  function assertComplete() {
+    assertEquals(dialog.$.button.textContent.trim(), 'OK');
+    assertEquals(dialog.$.button.className, 'action-button');
+  }
+
+  function assertNotComplete() {
+    assertEquals(dialog.$.button.textContent.trim(), 'Cancel');
+    assertEquals(dialog.$.button.className, 'cancel-button');
+  }
+
+  test('Initialization', async function() {
+    document.body.appendChild(dialog);
+    await browserProxy.whenCalled('reset');
+    assertShown('initial');
+    assertNotComplete();
+  });
+
+  test('Cancel', async function() {
+    document.body.appendChild(dialog);
+    await browserProxy.whenCalled('reset');
+    assertShown('initial');
+    assertNotComplete();
+    dialog.$.button.click();
+    await browserProxy.whenCalled('close');
+    assertFalse(dialog.$.dialog.open);
+  });
+
+  test('NotSupported', async function() {
+    browserProxy.setResponseFor(
+        'reset', Promise.resolve(1 /* INVALID_COMMAND */));
+    document.body.appendChild(dialog);
+
+    await browserProxy.whenCalled('reset');
+    await browserProxy.whenCalled('close');
+    assertComplete();
+    assertShown('noReset');
+  });
+
+  test('ImmediateUnknownError', async function() {
+    const error = 1000 /* undefined error code */;
+    browserProxy.setResponseFor('reset', Promise.resolve(error));
+    document.body.appendChild(dialog);
+
+    await browserProxy.whenCalled('reset');
+    await browserProxy.whenCalled('close');
+    assertComplete();
+    assertShown('resetFailed');
+    assertTrue(
+        dialog.$.resetFailed.textContent.trim().includes(error.toString()));
+  });
+
+  test('ImmediateUnknownError', async function() {
+    browserProxy.setResponseFor('reset', Promise.resolve(0 /* success */));
+    const promiseResolver = new PromiseResolver();
+    browserProxy.setResponseFor('completeReset', promiseResolver.promise);
+    document.body.appendChild(dialog);
+
+    await browserProxy.whenCalled('reset');
+    await browserProxy.whenCalled('completeReset');
+    assertNotComplete();
+    assertShown('reset2');
+    promiseResolver.resolve(0 /* success */);
+    await browserProxy.whenCalled('close');
+    assertComplete();
+    assertShown('resetSuccess');
+  });
+
+  test('UnknownError', async function() {
+    const error = 1000 /* undefined error code */;
+    browserProxy.setResponseFor('reset', Promise.resolve(0 /* success */));
+    browserProxy.setResponseFor('completeReset', Promise.resolve(error));
+    document.body.appendChild(dialog);
+
+    await browserProxy.whenCalled('reset');
+    await browserProxy.whenCalled('completeReset');
+    await browserProxy.whenCalled('close');
+    assertComplete();
+    assertShown('resetFailed');
+    assertTrue(
+        dialog.$.resetFailed.textContent.trim().includes(error.toString()));
+  });
+
+  test('ResetRejected', async function() {
+    browserProxy.setResponseFor('reset', Promise.resolve(0 /* success */));
+    browserProxy.setResponseFor(
+        'completeReset', Promise.resolve(48 /* NOT_ALLOWED */));
+    document.body.appendChild(dialog);
+
+    await browserProxy.whenCalled('reset');
+    await browserProxy.whenCalled('completeReset');
+    await browserProxy.whenCalled('close');
+    assertComplete();
+    assertShown('resetNotAllowed');
+  });
+});
+
+suite('SecurityKeysSetPINDialog', function() {
+  let dialog = null;
+
+  setup(function() {
+    browserProxy = new TestSecurityKeysBrowserProxy();
+    settings.SecurityKeysBrowserProxyImpl.instance_ = browserProxy;
+    PolymerTest.clearBody();
+    dialog = document.createElement('settings-security-keys-set-pin-dialog');
+  });
+
+  function assertShown(expectedID) {
+    const allDivs = [
+      'initial',
+      'noPINSupport',
+      'pinPrompt',
+      'success',
+      'error',
+      'locked',
+      'reinsert',
+    ];
+    assertTrue(allDivs.includes(expectedID));
+
+    const allShown =
+        allDivs.filter(id => dialog.$[id].className == 'iron-selected');
+    assertEquals(allShown.length, 1);
+    assertEquals(allShown[0], expectedID);
+  }
+
+  function assertComplete() {
+    assertEquals(dialog.$.closeButton.textContent.trim(), 'OK');
+    assertEquals(dialog.$.closeButton.className, 'action-button');
+    assertEquals(dialog.$.pinSubmit.hidden, true);
+  }
+
+  function assertNotComplete() {
+    assertEquals(dialog.$.closeButton.textContent.trim(), 'Cancel');
+    assertEquals(dialog.$.closeButton.className, 'cancel-button');
+    assertEquals(dialog.$.pinSubmit.hidden, false);
+  }
+
+  test('Initialization', async function() {
+    document.body.appendChild(dialog);
+    await browserProxy.whenCalled('startSetPIN');
+    assertShown('initial');
+    assertNotComplete();
+  });
+
+  // Test error codes that are returned immediately.
+  for (let testCase of [
+           [1 /* INVALID_COMMAND */, 'noPINSupport'],
+           [52 /* temporary lock */, 'reinsert'], [50 /* locked */, 'locked'],
+           [1000 /* invalid error */, 'error']]) {
+    test('ImmediateError' + testCase[0].toString(), async function() {
+      browserProxy.setResponseFor(
+          'startSetPIN',
+          Promise.resolve([1 /* operation complete */, testCase[0]]));
+      document.body.appendChild(dialog);
+
+      await browserProxy.whenCalled('startSetPIN');
+      await browserProxy.whenCalled('close');
+      assertComplete();
+      assertShown(testCase[1]);
+      if (testCase[1] == 'error') {
+        // Unhandled error codes display the numeric code.
+        assertTrue(
+            dialog.$.error.textContent.trim().includes(testCase[0].toString()));
+      }
+    });
+  }
+
+  test('ZeroRetries', async function() {
+    // Authenticators can also signal that they are locked by indicating zero
+    // attempts remaining.
+    browserProxy.setResponseFor(
+        'startSetPIN',
+        Promise.resolve([0 /* not yet complete */, 0 /* no retries */]));
+    document.body.appendChild(dialog);
+
+    await browserProxy.whenCalled('startSetPIN');
+    await browserProxy.whenCalled('close');
+    assertComplete();
+    assertShown('locked');
+  });
+
+  function setNewPINEntries(pinValue, confirmPINValue) {
+    const newPIN = dialog.$.newPIN;
+    const confirmPIN = dialog.$.confirmPIN;
+    newPIN.value = pinValue;
+    // Dispatch input events to trigger validation and UI updates.
+    newPIN.dispatchEvent(
+        new CustomEvent('input', {bubbles: true, cancelable: true}));
+    confirmPIN.value = confirmPINValue;
+    confirmPIN.dispatchEvent(
+        new CustomEvent('input', {bubbles: true, cancelable: true}));
+  }
+
+  function setChangePINEntries(currentPINValue, pinValue, confirmPINValue) {
+    setNewPINEntries(pinValue, confirmPINValue);
+    const currentPIN = dialog.$.currentPIN;
+    currentPIN.value = currentPINValue;
+    // Dispatch input events to trigger validation and UI updates.
+    currentPIN.dispatchEvent(
+        new CustomEvent('input', {bubbles: true, cancelable: true}));
+  }
+
+  test('SetPIN', async function() {
+    const startSetPINResolver = new PromiseResolver();
+    browserProxy.setResponseFor('startSetPIN', startSetPINResolver.promise);
+    document.body.appendChild(dialog);
+    const uiReady = test_util.eventToPromise('ui-ready', dialog);
+
+    await browserProxy.whenCalled('startSetPIN');
+    startSetPINResolver.resolve(
+        [0 /* not yet complete */, null /* no current PIN */]);
+    await uiReady;
+    assertNotComplete();
+    assertShown('pinPrompt');
+    assertTrue(dialog.$.currentPINEntry.hidden);
+
+    setNewPINEntries('123', '');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setNewPINEntries('123', '123');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setNewPINEntries('1234', '123');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setNewPINEntries('1234', '1234');
+    assertFalse(dialog.$.pinSubmit.disabled);  // Note True -> False
+
+    const setPINResolver = new PromiseResolver();
+    browserProxy.setResponseFor('setPIN', setPINResolver.promise);
+    dialog.$.pinSubmit.click();
+    ({oldPIN, newPIN} = await browserProxy.whenCalled('setPIN'));
+    assertTrue(dialog.$.pinSubmit.disabled);
+    assertEquals(oldPIN, '');
+    assertEquals(newPIN, '1234');
+
+    setPINResolver.resolve([1 /* complete */, 0 /* success */]);
+    await browserProxy.whenCalled('close');
+    assertShown('success');
+    assertComplete();
+  });
+
+  // Test error codes that are only returned after attempting to set a PIN.
+  for (let testCase of [
+           [52 /* temporary lock */, 'reinsert'], [50 /* locked */, 'locked'],
+           [1000 /* invalid error */, 'error']]) {
+    test('Error' + testCase[0].toString(), async function() {
+      const startSetPINResolver = new PromiseResolver();
+      browserProxy.setResponseFor('startSetPIN', startSetPINResolver.promise);
+      document.body.appendChild(dialog);
+      const uiReady = test_util.eventToPromise('ui-ready', dialog);
+
+      await browserProxy.whenCalled('startSetPIN');
+      startSetPINResolver.resolve(
+          [0 /* not yet complete */, null /* no current PIN */]);
+      await uiReady;
+      setNewPINEntries('1234', '1234');
+
+      browserProxy.setResponseFor(
+          'setPIN', Promise.resolve([1 /* complete */, testCase[0]]));
+      dialog.$.pinSubmit.click();
+      await browserProxy.whenCalled('setPIN');
+      await browserProxy.whenCalled('close');
+      assertComplete();
+      assertShown(testCase[1]);
+      if (testCase[1] == 'error') {
+        // Unhandled error codes display the numeric code.
+        assertTrue(
+            dialog.$.error.textContent.trim().includes(testCase[0].toString()));
+      }
+    });
+  }
+
+  test('ChangePIN', async function() {
+    const startSetPINResolver = new PromiseResolver();
+    browserProxy.setResponseFor('startSetPIN', startSetPINResolver.promise);
+    document.body.appendChild(dialog);
+    let uiReady = test_util.eventToPromise('ui-ready', dialog);
+
+    await browserProxy.whenCalled('startSetPIN');
+    startSetPINResolver.resolve(
+        [0 /* not yet complete */, 2 /* two attempts */]);
+    await uiReady;
+    assertNotComplete();
+    assertShown('pinPrompt');
+    assertFalse(dialog.$.currentPINEntry.hidden);
+
+    setChangePINEntries('123', '', '');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setChangePINEntries('123', '123', '');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setChangePINEntries('1234', '123', '1234');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setChangePINEntries('123', '1234', '1234');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setChangePINEntries('4321', '1234', '1234');
+    assertFalse(dialog.$.pinSubmit.disabled);  // Note True -> False
+
+    let setPINResolver = new PromiseResolver();
+    browserProxy.setResponseFor('setPIN', setPINResolver.promise);
+    dialog.$.pinSubmit.click();
+    let {oldPIN, newPIN} = await browserProxy.whenCalled('setPIN');
+    assertShown('pinPrompt');
+    assertNotComplete();
+    assertTrue(dialog.$.pinSubmit.disabled);
+    assertEquals(oldPIN, '4321');
+    assertEquals(newPIN, '1234');
+
+    // Simulate an incorrect PIN.
+    uiReady = test_util.eventToPromise('ui-ready', dialog);
+    setPINResolver.resolve([1 /* complete */, 49 /* incorrect PIN */]);
+    await uiReady;
+    // Text box for current PIN should be cleared.
+    assertEquals(dialog.$.currentPIN.value, '');
+    assertTrue(dialog.$.pinSubmit.disabled);
+
+    setChangePINEntries('43211', '1234', '1234');
+    assertFalse(dialog.$.pinSubmit.disabled);
+
+    browserProxy.resetResolver('setPIN');
+    setPINResolver = new PromiseResolver();
+    browserProxy.setResponseFor('setPIN', setPINResolver.promise);
+    dialog.$.pinSubmit.click();
+    ({oldPIN, newPIN} = await browserProxy.whenCalled('setPIN'));
+    assertTrue(dialog.$.pinSubmit.disabled);
+    assertEquals(oldPIN, '43211');
+    assertEquals(newPIN, '1234');
+
+    setPINResolver.resolve([1 /* complete */, 0 /* success */]);
+    await browserProxy.whenCalled('close');
+    assertShown('success');
+    assertComplete();
+  });
+});
diff --git a/chrome/test/vr/perf/BUILD.gn b/chrome/test/vr/perf/BUILD.gn
index a58e971..ab0aa92 100644
--- a/chrome/test/vr/perf/BUILD.gn
+++ b/chrome/test/vr/perf/BUILD.gn
@@ -7,7 +7,7 @@
   "./android_vr_perf_test.py",
   "./vr_perf_test.py",
   "./vr_test_arg_parser.py",
-  "//third_party/android_tools/sdk/platform-tools/adb",
+  "//third_party/android_sdk/public/platform-tools/adb",
   "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
 ]
 
diff --git a/chrome/test/vr/perf/vr_test_arg_parser.py b/chrome/test/vr/perf/vr_test_arg_parser.py
index f27f986..da23317 100644
--- a/chrome/test/vr/perf/vr_test_arg_parser.py
+++ b/chrome/test/vr/perf/vr_test_arg_parser.py
@@ -7,7 +7,7 @@
 import os
 
 
-DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_tools/sdk/'
+DEFAULT_ADB_PATH = os.path.realpath('../../third_party/android_sdk/public/'
                                     'platform-tools/adb')
 DEFAULT_DURATION_SECONDS = 30
 # TODO(bsheedy): See about adding tool via DEPS instead of relying on it
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 60df8f1..cf29b41 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -95,10 +95,7 @@
   }
 
   if (is_linux || is_fuchsia) {
-    tests += [
-      "//chromecast/media/cma/backend:cast_audio_backend_unittests",
-      "//chromecast/media/cma/backend:cast_av_sync_backend_unittests",
-    ]
+    tests += [ "//chromecast/media/cma/backend:cast_audio_backend_unittests" ]
   }
 
   if (is_android && is_cast_using_cma_backend) {
diff --git a/chromecast/browser/cast_web_view_default.cc b/chromecast/browser/cast_web_view_default.cc
index f13b591..8427905 100644
--- a/chromecast/browser/cast_web_view_default.cc
+++ b/chromecast/browser/cast_web_view_default.cc
@@ -140,17 +140,22 @@
                                           CastWindowManager::WindowId z_order,
                                           VisibilityPriority initial_priority) {
   DCHECK(window_manager);
+  DCHECK(window_);
   window_->CreateWindowForWebContents(web_contents_.get(), window_manager,
                                       z_order, initial_priority);
   web_contents_->Focus();
 }
 
 void CastWebViewDefault::GrantScreenAccess() {
+  if (!window_)
+    return;
   window_->GrantScreenAccess();
 }
 
 void CastWebViewDefault::RevokeScreenAccess() {
   resize_window_when_navigation_starts_ = false;
+  if (!window_)
+    return;
   window_->RevokeScreenAccess();
 }
 
diff --git a/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc b/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc
index 3daa2d1..e9f85d05 100644
--- a/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc
+++ b/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc
@@ -160,6 +160,24 @@
   }
 }
 
+bool GattClientManagerImpl::SetGattClientConnectable(bool connectable) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+  if (connectable) {
+    if (disconnect_all_pending_) {
+      LOG(ERROR) << "Can't enable GATT client connectability while "
+                    "DisconectAll is pending";
+      return false;
+    }
+    LOG(INFO) << "Enabling GATT client connectability";
+  } else {
+    LOG(INFO) << "Disabling GATT client connectability";
+  }
+
+  gatt_client_connectable_ = connectable;
+  return true;
+}
+
 void GattClientManagerImpl::DisconnectAll(StatusCallback cb) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   if (disconnect_all_pending_) {
@@ -203,12 +221,18 @@
     return;
   }
 
-  it->second->SetConnected(connected);
   if (connected) {
+    if (!gatt_client_connectable_) {
+      LOG(ERROR) << "GATT client not connectable, disconnecting";
+      gatt_client_->Disconnect(addr);
+      return;
+    }
     // We won't declare the device connected until service discovery completes,
     // so we won't start next Connect request until then.
+    it->second->SetConnected(true);
     connected_devices_.insert(addr);
   } else {
+    it->second->SetConnected(false);
     connected_devices_.erase(addr);
     if (!pending_connect_requests_.empty() &&
         addr == pending_connect_requests_.front().first) {
@@ -410,14 +434,19 @@
     auto addr = pending_connect_requests_.front().first;
     bool is_connect = pending_connect_requests_.front().second;
     if (is_connect) {
-      if (gatt_client_->Connect(addr)) {
-        connect_timeout_timer_.Start(
-            FROM_HERE, kConnectTimeout,
-            base::BindOnce(&GattClientManagerImpl::OnConnectTimeout, weak_this_,
-                           addr));
-        return;
+      if (gatt_client_connectable_) {
+        if (gatt_client_->Connect(addr)) {
+          connect_timeout_timer_.Start(
+              FROM_HERE, kConnectTimeout,
+              base::BindOnce(&GattClientManagerImpl::OnConnectTimeout,
+                             weak_this_, addr));
+          return;
+        } else {
+          LOG(ERROR) << "Connect failed";
+        }
+      } else {
+        LOG(ERROR) << "GATT client not connectable";
       }
-      LOG(ERROR) << "Connect failed";
       auto it = addr_to_device_.find(addr);
       if (it != addr_to_device_.end()) {
         it->second->SetConnected(false);
diff --git a/chromecast/device/bluetooth/le/gatt_client_manager_impl.h b/chromecast/device/bluetooth/le/gatt_client_manager_impl.h
index 1b68163..5d35865a 100644
--- a/chromecast/device/bluetooth/le/gatt_client_manager_impl.h
+++ b/chromecast/device/bluetooth/le/gatt_client_manager_impl.h
@@ -72,8 +72,15 @@
   // serially.
   void EnqueueReadRemoteRssiRequest(const bluetooth_v2_shlib::Addr& addr);
 
+  // Enable or disable GATT client connectability. Returns |true| if successful
+  // otherwise |false|.
+  bool SetGattClientConnectable(bool connectable);
+
   // Disconnect all connected devices. Callback will return |true| if all
   // devices are disconnected, otherwise false.
+  // When disabling GATT client, caller should call
+  // SetGattClientConnectable(false) before calling DisconnectAll so that
+  // upcoming GATT client connections can also be blocked.
   void DisconnectAll(StatusCallback cb);
 
   // True if it is a connected BLE device. Must be called on IO task runner.
@@ -83,6 +90,8 @@
   // RemoteDevice, RemoteCharacteristic).
   bluetooth_v2_shlib::GattClient* gatt_client() const { return gatt_client_; }
 
+  bool gatt_client_connectable() const { return gatt_client_connectable_; }
+
  private:
   // bluetooth_v2_shlib::Gatt::Client::Delegate implementation:
   void OnConnectChanged(const bluetooth_v2_shlib::Addr& addr,
@@ -169,6 +178,10 @@
 
   bool disconnect_all_pending_ = false;
 
+  // True if we are allowed connect to a remote device. This value should be set
+  // false when device is in GATT server mode.
+  bool gatt_client_connectable_ = true;
+
   // Callback of DisconnectAll request.
   StatusCallback disconnect_all_cb_;
 
diff --git a/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc b/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc
index 5fa032d..99b00ef 100644
--- a/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc
+++ b/chromecast/device/bluetooth/le/gatt_client_manager_impl_test.cc
@@ -272,8 +272,14 @@
   EXPECT_CALL(cb_, Run(false));
   device->ConnectionParameterUpdate(10, 10, 50, 100, cb_.Get());
 
-  EXPECT_CALL(*gatt_client_, Connect(kTestAddr1)).WillOnce(Return(true));
+  // First connect request fails right away.
+  EXPECT_CALL(*gatt_client_, Connect(kTestAddr1)).WillOnce(Return(false));
+  EXPECT_CALL(cb_, Run(false));
+  device->Connect(cb_.Get());
+  EXPECT_FALSE(device->IsConnected());
 
+  // Second connect request succeeds.
+  EXPECT_CALL(*gatt_client_, Connect(kTestAddr1)).WillOnce(Return(true));
   EXPECT_CALL(cb_, Run(true));
   device->Connect(cb_.Get());
   EXPECT_CALL(*gatt_client_, GetServices(kTestAddr1)).WillOnce(Return(true));
@@ -519,8 +525,15 @@
   scoped_refptr<RemoteDevice> device = GetDevice(kTestAddr1);
 
   Connect(kTestAddr1);
-
   base::MockCallback<RemoteDevice::RssiCallback> rssi_cb;
+
+  // First ReadRemoteRssi request fails right away.
+  EXPECT_CALL(*gatt_client_, ReadRemoteRssi(kTestAddr1))
+      .WillOnce(Return(false));
+  EXPECT_CALL(rssi_cb, Run(false, 0));
+  device->ReadRemoteRssi(rssi_cb.Get());
+
+  // Second ReadRemoteRssi request succeeds.
   EXPECT_CALL(*gatt_client_, ReadRemoteRssi(kTestAddr1)).WillOnce(Return(true));
   device->ReadRemoteRssi(rssi_cb.Get());
 
@@ -546,6 +559,10 @@
   Connect(kTestAddr2);
   Connect(kTestAddr3);
 
+  // Disable GATT client connectability.
+  EXPECT_TRUE(gatt_client_manager_->SetGattClientConnectable(false));
+  EXPECT_FALSE(gatt_client_manager_->gatt_client_connectable());
+
   // Disconnect requests will be queued.
   EXPECT_CALL(*gatt_client_, Disconnect(kTestAddr1)).WillOnce(Return(true));
   gatt_client_manager_->DisconnectAll(cb.Get());
@@ -558,6 +575,10 @@
   delegate->OnConnectChanged(kTestAddr2, true /* status */,
                              false /* connected */);
 
+  // Shouldn't be able to enable connectability when DisconnectAll is pending.
+  EXPECT_FALSE(gatt_client_manager_->SetGattClientConnectable(true));
+  EXPECT_FALSE(gatt_client_manager_->gatt_client_connectable());
+
   EXPECT_CALL(cb, Run(true));
   delegate->OnConnectChanged(kTestAddr3, true /* status */,
                              false /* connected */);
@@ -567,6 +588,10 @@
   EXPECT_CALL(get_num_connected_callback, Run(0));
   gatt_client_manager_->GetNumConnected(get_num_connected_callback.Get());
 
+  // Re-enable connectability when DisconnectAll completes.
+  EXPECT_TRUE(gatt_client_manager_->SetGattClientConnectable(true));
+  EXPECT_TRUE(gatt_client_manager_->gatt_client_connectable());
+
   base::RunLoop().RunUntilIdle();
 }
 
@@ -606,6 +631,48 @@
   gatt_client_manager_->GetNumConnected(get_num_connected_callback.Get());
 }
 
+TEST_F(GattClientManagerTest, Connectability) {
+  bluetooth_v2_shlib::Gatt::Client::Delegate* delegate =
+      gatt_client_->delegate();
+  scoped_refptr<RemoteDevice> device = GetDevice(kTestAddr1);
+
+  // By default GATT client is connectable.
+  EXPECT_TRUE(gatt_client_manager_->gatt_client_connectable());
+
+  // Start a connection.
+  EXPECT_CALL(*gatt_client_, Connect(kTestAddr1)).WillOnce(Return(true));
+  device->Connect(cb_.Get());
+
+  // Disable GATT client connectability while connection is pending.
+  EXPECT_TRUE(gatt_client_manager_->SetGattClientConnectable(false));
+  EXPECT_FALSE(gatt_client_manager_->gatt_client_connectable());
+
+  // Expect to disconnect after receiving the connect callback.
+  EXPECT_CALL(*gatt_client_, Disconnect(kTestAddr1)).WillOnce(Return(true));
+  delegate->OnConnectChanged(kTestAddr1, true /* status */,
+                             true /* connected */);
+
+  EXPECT_CALL(cb_, Run(false));
+  delegate->OnConnectChanged(kTestAddr1, true /* status */,
+                             false /* connected */);
+  ASSERT_FALSE(device->IsConnected());
+
+  // Connect should fail when GATT client connectability is already disabled.
+  EXPECT_CALL(*gatt_client_, Connect(_)).Times(0);
+  EXPECT_CALL(cb_, Run(false));
+  device->Connect(cb_.Get());
+  ASSERT_FALSE(device->IsConnected());
+
+  // Re-enable connectability.
+  EXPECT_TRUE(gatt_client_manager_->SetGattClientConnectable(true));
+  EXPECT_TRUE(gatt_client_manager_->gatt_client_connectable());
+
+  // Connect succeeds.
+  Connect(kTestAddr1);
+
+  base::RunLoop().RunUntilIdle();
+}
+
 TEST_F(GattClientManagerTest, ReadRemoteRssiTimeout) {
   static const int kRssi = -34;
 
diff --git a/chromecast/device/bluetooth/le/remote_device_impl.cc b/chromecast/device/bluetooth/le/remote_device_impl.cc
index 369290a..13a74e3 100644
--- a/chromecast/device/bluetooth/le/remote_device_impl.cc
+++ b/chromecast/device/bluetooth/le/remote_device_impl.cc
@@ -70,12 +70,12 @@
 
 void RemoteDeviceImpl::Connect(StatusCallback cb) {
   MAKE_SURE_IO_THREAD(Connect, BindToCurrentSequence(std::move(cb)));
+  connect_cb_ = std::move(cb);
+
   if (!ConnectSync()) {
     // Error logged.
-    EXEC_CB_AND_RET(cb, false);
+    EXEC_CB_AND_RET(connect_cb_, false);
   }
-
-  connect_cb_ = std::move(cb);
 }
 
 bool RemoteDeviceImpl::ConnectSync() {
@@ -101,12 +101,12 @@
 
 void RemoteDeviceImpl::Disconnect(StatusCallback cb) {
   MAKE_SURE_IO_THREAD(Disconnect, BindToCurrentSequence(std::move(cb)));
+  disconnect_cb_ = std::move(cb);
+
   if (!DisconnectSync()) {
     // Error logged.
-    EXEC_CB_AND_RET(cb, false);
+    EXEC_CB_AND_RET(disconnect_cb_, false);
   }
-
-  disconnect_cb_ = std::move(cb);
 }
 
 bool RemoteDeviceImpl::DisconnectSync() {
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index f433fae..479e8fd 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -336,26 +336,3 @@
     deps += [ "fuchsia:unit_tests" ]
   }
 }
-
-test("cast_av_sync_backend_unittests") {
-  testonly = true
-  sources = [
-    "av_sync_unittest.cc",
-    "mock_audio_decoder_for_mixer.cc",
-    "mock_audio_decoder_for_mixer.h",
-    "mock_video_decoder_for_mixer.cc",
-    "mock_video_decoder_for_mixer.h",
-  ]
-
-  deps = [
-    ":for_mixer_audio",
-    "//base",
-    "//base/test:run_all_unittests",
-    "//base/test:test_support",
-    "//chromecast/base",
-    "//chromecast/media/cma/backend/video:av_sync_video",
-    "//chromecast/public/media",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
diff --git a/chromecast/media/cma/backend/av_sync_unittest.cc b/chromecast/media/cma/backend/av_sync_unittest.cc
deleted file mode 100644
index 84b56bc..0000000
--- a/chromecast/media/cma/backend/av_sync_unittest.cc
+++ /dev/null
@@ -1,165 +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 "chromecast/media/cma/backend/av_sync.h"
-
-#include <cmath>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/scoped_mock_time_message_loop_task_runner.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/time/time.h"
-#include "chromecast/base/task_runner_impl.h"
-#include "chromecast/media/cma/backend/mock_audio_decoder_for_mixer.h"
-#include "chromecast/media/cma/backend/mock_media_pipeline_backend_for_mixer.h"
-#include "chromecast/media/cma/backend/mock_video_decoder_for_mixer.h"
-#include "chromecast/media/cma/backend/video/av_sync_video.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromecast {
-namespace media {
-
-class AvSyncTest : public testing::Test, public AvSyncVideo::Delegate {
- public:
-  AvSyncTest()
-      : mock_task_runner_(new base::TestMockTimeTaskRunner()),
-        runner_(mock_task_runner_) {}
-
-  void SetupTest(base::OnceCallback<std::unique_ptr<VideoDecoderForTest>()>
-                     video_decoder_factory) {
-    base::TestMockTimeTaskRunner::ScopedContext scoped_context(
-        mock_task_runner_.get());
-
-    MediaPipelineDeviceParams params(&runner_, AudioContentType::kMedia,
-                                     "test");
-
-    backend_ = std::make_unique<MockMediaPipelineBackendForMixer>(params);
-
-    backend_->SetVideoDecoder(std::move(video_decoder_factory).Run());
-    backend_->SetAudioDecoder(MockAudioDecoderForMixer::Create(backend_.get()));
-
-    backend_->Initialize();
-    backend_->Start(0);
-  }
-
-  void NotifyAvSyncPlaybackStatistics(
-      int64_t unexpected_dropped_frames,
-      int64_t unexpected_repeated_frames,
-      double average_av_sync_difference_us,
-      int64_t current_apts,
-      int64_t current_vpts,
-      int64_t number_of_soft_corrections,
-      int64_t number_of_hard_corrections) override {
-    VideoDecoderForTest* video_decoder = static_cast<VideoDecoderForTest*>(
-        static_cast<MockMediaPipelineBackendForMixer*>(backend_.get())
-            ->video_decoder());
-
-    // TODO(almasrymina): ignore the first few seconds of playback, and don't
-    // assert anything about them.
-    //
-    // The reason for this is that I'm observing with broken video decoders
-    // that we'll start playback in sync, but the video decoder is broken,
-    // creating a gap, then the AV sync logic kicks in, then it slowly brings
-    // the media back in line.
-    //
-    // Need to find a better solution to this.
-    if (current_vpts < 10000000)
-      return;
-
-    // Assert the data here is within what's expected by this video decoder.
-    EXPECT_LT(std::abs(average_av_sync_difference_us),
-              video_decoder->GetAvSyncDriftTolerated());
-
-    int64_t expected_dropped_frames = video_decoder->GetExpectedDroppedFrames();
-    int64_t expected_repeated_frames =
-        video_decoder->GetExpectedRepeatedFrames();
-
-    EXPECT_LE(std::abs(unexpected_dropped_frames - expected_dropped_frames),
-              video_decoder->GetNumberOfFramesTolerated());
-
-    EXPECT_LE(std::abs(unexpected_repeated_frames - expected_repeated_frames),
-              video_decoder->GetNumberOfFramesTolerated());
-
-    EXPECT_LE(number_of_hard_corrections,
-              video_decoder->GetNumberOfHardCorrectionsTolerated());
-
-    EXPECT_LE(number_of_soft_corrections,
-              video_decoder->GetNumberOfSoftCorrectionsTolerated());
-    // TODO(almasrymina): b/73746352 add more tests. For example, probably we
-    // should assert the total number of dropped/repeated frames for the entire
-    // playback is within reason.
-    //
-    // Assert only 1 soft correction and 1 in sync correction is every
-    // executed.
-  }
-
- protected:
-  base::MessageLoop message_loop_;
-  std::unique_ptr<MockMediaPipelineBackendForMixer> backend_;
-  scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
-  TaskRunnerImpl runner_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AvSyncTest);
-};
-
-TEST_F(AvSyncTest, Baseline60) {
-  SetupTest(base::BindOnce(&NormalVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-
-TEST_F(AvSyncTest, Baseline30) {
-  SetupTest(base::BindOnce(&NormalVideoDecoder30::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-
-TEST_F(AvSyncTest, Baseline24) {
-  SetupTest(base::BindOnce(&NormalVideoDecoder24::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-
-TEST_F(AvSyncTest, LinearDoubleSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&LinearDoubleSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-
-TEST_F(AvSyncTest, LinearHalfSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&LinearHalfSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-
-TEST_F(AvSyncTest, Linear130PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear130PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-TEST_F(AvSyncTest, Linear120PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear120PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-TEST_F(AvSyncTest, Linear110PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear110PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-TEST_F(AvSyncTest, Linear90PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear90PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-TEST_F(AvSyncTest, Linear80PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear80PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-TEST_F(AvSyncTest, Linear70PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear70PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-TEST_F(AvSyncTest, Linear60PercentSpeedVideoDecoder) {
-  SetupTest(base::BindOnce(&Linear60PercentSpeedVideoDecoder::Create));
-  mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(600));
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mock_audio_decoder_for_mixer.cc b/chromecast/media/cma/backend/mock_audio_decoder_for_mixer.cc
deleted file mode 100644
index 0ce19f0e..0000000
--- a/chromecast/media/cma/backend/mock_audio_decoder_for_mixer.cc
+++ /dev/null
@@ -1,102 +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 "chromecast/media/cma/backend/mock_audio_decoder_for_mixer.h"
-
-#include "base/logging.h"
-#include "base/test/test_mock_time_task_runner.h"
-
-namespace chromecast {
-namespace media {
-
-std::unique_ptr<MockAudioDecoderForMixer> MockAudioDecoderForMixer::Create(
-    MediaPipelineBackendForMixer* backend) {
-  return std::make_unique<MockAudioDecoderForMixer>(backend);
-}
-
-MockAudioDecoderForMixer::MockAudioDecoderForMixer(
-    MediaPipelineBackendForMixer* backend)
-    : AudioDecoderForMixer(backend) {}
-
-MockAudioDecoderForMixer::~MockAudioDecoderForMixer() {}
-
-void MockAudioDecoderForMixer::PushBufferPeriodic() {
-  auto now_ticks =
-      static_cast<base::TestMockTimeTaskRunner*>(task_runner_.get())
-          ->NowTicks();
-
-  int64_t buffer_timestamp = next_push_buffer_pts_;
-  int64_t audio_play_delay =
-      next_push_buffer_pts_ - current_audio_pts_ + mixer_latency_us_;
-  next_push_buffer_pts_ += audio_buffer_duration_us_;
-  DCHECK_GT(audio_play_delay, 0);
-
-  MediaPipelineBackend::AudioDecoder::RenderingDelay delay(
-      audio_play_delay, (now_ticks - base::TimeTicks()).InMicroseconds());
-
-  DVLOG(4) << "audio_buffer_pushed"
-           << " current_audio_pts_=" << current_audio_pts_
-           << " buffer_timestamp=" << buffer_timestamp
-           << " delay.timestamp_microseconds=" << delay.timestamp_microseconds
-           << " delay.delay_microseconds=" << delay.delay_microseconds;
-}
-
-void MockAudioDecoderForMixer::PlayAudio() {
-  // This checks that we're not underruning, which I'm not interested in mocking
-  // at this time. We may want to improve the tests to assert that AV sync is
-  // maintained after an audio glitch.
-  if (next_push_buffer_pts_ >= (current_audio_pts_ + audio_play_interval_us_)) {
-    current_audio_pts_ += audio_play_interval_us_;
-    DVLOG(4) << "current_audio_pts_=" << current_audio_pts_;
-  }
-}
-
-void MockAudioDecoderForMixer::Initialize() {}
-
-bool MockAudioDecoderForMixer::Start(int64_t pts, bool start_playback_asap) {
-  next_push_buffer_pts_ = 0;
-  current_audio_pts_ = 0;
-  data_push_timer_.Start(
-      FROM_HERE,
-      base::TimeDelta::FromMicroseconds(audio_push_buffer_internal_us_), this,
-      &MockAudioDecoderForMixer::PushBufferPeriodic);
-  audio_play_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMicroseconds(audio_play_interval_us_),
-      this, &MockAudioDecoderForMixer::PlayAudio);
-  return true;
-}
-
-void MockAudioDecoderForMixer::Stop() {
-  next_push_buffer_pts_ = INT64_MIN;
-  data_push_timer_.Stop();
-  audio_play_timer_.Stop();
-}
-
-bool MockAudioDecoderForMixer::Pause() {
-  data_push_timer_.Stop();
-  audio_play_timer_.Stop();
-  return true;
-}
-
-bool MockAudioDecoderForMixer::Resume() {
-  data_push_timer_.Start(
-      FROM_HERE,
-      base::TimeDelta::FromMicroseconds(audio_push_buffer_internal_us_), this,
-      &MockAudioDecoderForMixer::PushBufferPeriodic);
-  audio_play_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMicroseconds(audio_play_interval_us_),
-      this, &MockAudioDecoderForMixer::PlayAudio);
-  return true;
-}
-
-float MockAudioDecoderForMixer::SetPlaybackRate(float rate) {
-  return 1.0;
-}
-
-int64_t MockAudioDecoderForMixer::GetCurrentPts() const {
-  return current_audio_pts_;
-}
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mock_audio_decoder_for_mixer.h b/chromecast/media/cma/backend/mock_audio_decoder_for_mixer.h
deleted file mode 100644
index 780f09a..0000000
--- a/chromecast/media/cma/backend/mock_audio_decoder_for_mixer.h
+++ /dev/null
@@ -1,59 +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 CHROMECAST_MEDIA_CMA_BACKEND_MOCK_AUDIO_DECODER_FOR_MIXER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_AUDIO_DECODER_FOR_MIXER_H_
-
-#include <stdint.h>
-#include <memory>
-
-#include "base/macros.h"
-#include "base/timer/timer.h"
-#include "chromecast/media/cma/backend/audio_decoder_for_mixer.h"
-
-namespace chromecast {
-namespace media {
-
-class MediaPipelineBackendForMixer;
-
-class MockAudioDecoderForMixer : public AudioDecoderForMixer {
- public:
-  static std::unique_ptr<MockAudioDecoderForMixer> Create(
-      MediaPipelineBackendForMixer* backend);
-
-  explicit MockAudioDecoderForMixer(MediaPipelineBackendForMixer* backend);
-  ~MockAudioDecoderForMixer() override;
-
-  // AudioDecoderForMixer implementation:
-  void Initialize() override;
-  bool Start(int64_t pts, bool start_playback_asap) override;
-  void Stop() override;
-  bool Pause() override;
-  bool Resume() override;
-  float SetPlaybackRate(float rate) override;
-  int64_t GetCurrentPts() const override;
-
- private:
-  void PushBufferPeriodic();
-  void PlayAudio();
-
-  base::RepeatingTimer data_push_timer_;
-  base::RepeatingTimer audio_play_timer_;
-
-  // TODO(almasrymina): to enhance the tests further, we may want to add tests
-  // that tweak those params, such as add non-contsant mixer delay.
-  int64_t next_push_buffer_pts_ = INT64_MIN;
-  int64_t audio_buffer_duration_us_ = 100000;
-  int64_t audio_push_buffer_internal_us_ = 20000;
-  int64_t mixer_latency_us_ = 100000;
-  int64_t current_audio_pts_ = INT64_MIN;
-  int64_t audio_play_interval_us_ = 1000;
-
-  DISALLOW_COPY_AND_ASSIGN(MockAudioDecoderForMixer);
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_AUDIO_DECODER_FOR_MIXER_H_
diff --git a/chromecast/media/cma/backend/mock_video_decoder_for_mixer.cc b/chromecast/media/cma/backend/mock_video_decoder_for_mixer.cc
deleted file mode 100644
index c972ef4..0000000
--- a/chromecast/media/cma/backend/mock_video_decoder_for_mixer.cc
+++ /dev/null
@@ -1,247 +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 "chromecast/media/cma/backend/mock_video_decoder_for_mixer.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/logging.h"
-#include "base/time/time.h"
-
-namespace chromecast {
-namespace media {
-
-namespace {  // namespace
-
-int64_t RoundDownToNearestMultiple(int64_t number, int64_t multiple) {
-  return number - (number % multiple);
-}
-
-}  // namespace
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-MockVideoDecoderForMixer<CRN, CRD, CF>::MockVideoDecoderForMixer() {
-  DCHECK(linear_clock_rate_ != 0.0);
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::Initialize() {
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::Start(int64_t start_pts,
-                                                   bool need_avsync) {
-  DVLOG(4) << "start_pts=" << start_pts;
-  start_pts_ = start_pts;
-  vsync_timer_.Start(FROM_HERE,
-                     base::TimeDelta::FromMicroseconds(
-                         std::round(GetVsyncPeriodUs() / linear_clock_rate_)),
-                     this, &MockVideoDecoderForMixer::UpkeepVsync);
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-void MockVideoDecoderForMixer<CRN, CRD, CF>::Stop() {
-  vsync_timer_.Stop();
-  current_video_pts_ = INT64_MIN;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::Pause() {
-  vsync_timer_.Stop();
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::Resume() {
-  vsync_timer_.Start(FROM_HERE,
-                     base::TimeDelta::FromMicroseconds(
-                         std::round(GetVsyncPeriodUs() / linear_clock_rate_)),
-                     this, &MockVideoDecoderForMixer::UpkeepVsync);
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::GetCurrentPts(int64_t* timestamp,
-                                                           int64_t* pts) const {
-  *timestamp = 0;
-  *pts = last_displayed_frame_pts_;
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::SetPlaybackRate(float rate) {
-  linear_pts_rate_ = rate;
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::SetPts(int64_t timestamp,
-                                                    int64_t pts) {
-  current_video_pts_ = pts;
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetDroppedFrames() {
-  return dropped_frames_;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetRepeatedFrames() {
-  return repeated_frames_;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetOutputRefreshRate() {
-  return 60000;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetCurrentContentRefreshRate() {
-  return content_fps_ * 1000;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-void MockVideoDecoderForMixer<CRN, CRD, CF>::SetDelegate(
-    MediaPipelineBackend::Decoder::Delegate* delegate) {}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-MediaPipelineBackend::BufferStatus
-MockVideoDecoderForMixer<CRN, CRD, CF>::PushBuffer(CastDecoderBuffer* buffer) {
-  return MediaPipelineBackend::kBufferSuccess;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-void MockVideoDecoderForMixer<CRN, CRD, CF>::GetStatistics(
-    Statistics* statistics) {}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-bool MockVideoDecoderForMixer<CRN, CRD, CF>::SetConfig(
-    const VideoConfig& config) {
-  return true;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetVsyncPeriodUs() {
-  return std::round(1000000.0 / display_refresh_rate_);
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-void MockVideoDecoderForMixer<CRN, CRD, CF>::UpkeepVsync() {
-  int64_t frame_period_us = std::round(1000000.0 / content_fps_);
-  current_video_pts_ += std::round(GetVsyncPeriodUs() * linear_pts_rate_);
-
-  if (current_video_pts_ > start_pts_) {
-    int64_t current_displayed_frame =
-        RoundDownToNearestMultiple(current_video_pts_, frame_period_us);
-
-    int64_t difference_in_frames =
-        (current_displayed_frame - last_displayed_frame_pts_) / frame_period_us;
-
-    if (difference_in_frames != 1) {
-      dropped_frames_ +=
-          std::max(difference_in_frames - 1, static_cast<int64_t>(0));
-      repeated_frames_ +=
-          std::max(1 - difference_in_frames, static_cast<int64_t>(0));
-      DVLOG(4) << "last_displayed_frame_pts_=" << last_displayed_frame_pts_
-               << " current_displayed_frame=" << current_displayed_frame
-               << " difference_in_frames=" << difference_in_frames
-               << " difference_in_time="
-               << (current_displayed_frame - last_displayed_frame_pts_)
-               << " dropped_frames_=" << dropped_frames_;
-    }
-
-    last_displayed_frame_pts_ = current_displayed_frame;
-  }
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-MockVideoDecoderForMixer<CRN, CRD, CF>::~MockVideoDecoderForMixer() {}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetExpectedDroppedFrames() {
-  int64_t expected_dropped_frames =
-      std::round((1.0 - linear_clock_rate_) * content_fps_);
-  return std::max(static_cast<int64_t>(0), expected_dropped_frames);
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetExpectedRepeatedFrames() {
-  int64_t expected_repeated_frames =
-      std::round((linear_clock_rate_ - 1.0) * content_fps_);
-  return std::max(static_cast<int64_t>(0), expected_repeated_frames);
-}
-
-std::unique_ptr<VideoDecoderForMixer> VideoDecoderForMixer::Create(
-    const MediaPipelineDeviceParams& params) {
-  return MockVideoDecoderForMixer<1, 1, 60>::Create();
-}
-
-void VideoDecoderForMixer::InitializeGraphicsForTesting() {
-  // No initialization required.
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-std::unique_ptr<VideoDecoderForTest>
-MockVideoDecoderForMixer<CRN, CRD, CF>::Create() {
-  return std::unique_ptr<VideoDecoderForTest>(
-      new MockVideoDecoderForMixer<CRN, CRD, CF>());
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetNumberOfFramesTolerated() {
-  if (CRN == 1 && CRD == 1) {
-    // TODO(almasrymina): somehow the 30fps normal decoder very ocasionally
-    // drops frames...?
-    if (CF == 30)
-      return 1;
-    else
-      return 0;
-  }
-  return 6;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t
-MockVideoDecoderForMixer<CRN, CRD, CF>::GetNumberOfHardCorrectionsTolerated() {
-  return 0;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t
-MockVideoDecoderForMixer<CRN, CRD, CF>::GetNumberOfSoftCorrectionsTolerated() {
-  return 1;
-}
-
-template <int64_t CRN, int64_t CRD, int64_t CF>
-int64_t MockVideoDecoderForMixer<CRN, CRD, CF>::GetAvSyncDriftTolerated() {
-  if (CRN == 1 && CRD == 1)
-    return 25000;
-  // TODO(almasrymina): really need to tighten this. The problem is that on
-  // very broken decoders (130% speed) AV starts in sync, and then drifts while
-  // we're building our vpts slope. Then we start correcting but we've drifted
-  // so much that we need some time to get back in sync, which triggers our
-  // unittests.
-  return 100000;
-}
-
-template class MockVideoDecoderForMixer<1, 1, 30>;
-template class MockVideoDecoderForMixer<1, 1, 24>;
-template class MockVideoDecoderForMixer<1, 1, 60>;
-template class MockVideoDecoderForMixer<2, 1, 60>;
-template class MockVideoDecoderForMixer<1, 2, 60>;
-template class MockVideoDecoderForMixer<14, 10, 60>;
-template class MockVideoDecoderForMixer<13, 10, 60>;
-template class MockVideoDecoderForMixer<12, 10, 60>;
-template class MockVideoDecoderForMixer<11, 10, 60>;
-template class MockVideoDecoderForMixer<9, 10, 60>;
-template class MockVideoDecoderForMixer<8, 10, 60>;
-template class MockVideoDecoderForMixer<7, 10, 60>;
-template class MockVideoDecoderForMixer<6, 10, 60>;
-
-}  // namespace media
-}  // namespace chromecast
diff --git a/chromecast/media/cma/backend/mock_video_decoder_for_mixer.h b/chromecast/media/cma/backend/mock_video_decoder_for_mixer.h
deleted file mode 100644
index ab5938b..0000000
--- a/chromecast/media/cma/backend/mock_video_decoder_for_mixer.h
+++ /dev/null
@@ -1,104 +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 CHROMECAST_MEDIA_CMA_BACKEND_MOCK_VIDEO_DECODER_FOR_MIXER_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MOCK_VIDEO_DECODER_FOR_MIXER_H_
-
-#include <stdint.h>
-#include <memory>
-
-#include "base/timer/timer.h"
-#include "chromecast/media/cma/backend/video_decoder_for_mixer.h"
-#include "chromecast/public/media/media_pipeline_backend.h"
-#include "chromecast/public/media/media_pipeline_device_params.h"
-
-namespace chromecast {
-namespace media {
-
-class VideoDecoderForTest : public VideoDecoderForMixer {
- public:
-  virtual int64_t GetExpectedDroppedFrames() = 0;
-  virtual int64_t GetExpectedRepeatedFrames() = 0;
-  virtual int64_t GetNumberOfFramesTolerated() = 0;
-  virtual int64_t GetNumberOfHardCorrectionsTolerated() = 0;
-  virtual int64_t GetNumberOfSoftCorrectionsTolerated() = 0;
-  virtual int64_t GetAvSyncDriftTolerated() = 0;
-};
-
-template <int64_t kClockRateNumerator,
-          int64_t kClockRateDenominator,
-          int64_t kContentFps>
-class MockVideoDecoderForMixer : public VideoDecoderForTest {
- public:
-  static std::unique_ptr<VideoDecoderForTest> Create();
-  MockVideoDecoderForMixer();
-  ~MockVideoDecoderForMixer() override;
-
-  // VideoDecoderForMixer implementation:
-  bool Initialize() override;
-  void SetObserver(VideoDecoderForMixer::Observer* observer) override {}
-  bool Start(int64_t start_pts, bool need_avsync) override;
-  void Stop() override;
-  bool Pause() override;
-  bool Resume() override;
-  bool GetCurrentPts(int64_t* timestamp, int64_t* pts) const override;
-  bool SetPlaybackRate(float rate) override;
-  bool SetPts(int64_t timestamp, int64_t pts) override;
-  int64_t GetDroppedFrames() override;
-  int64_t GetRepeatedFrames() override;
-  int64_t GetOutputRefreshRate() override;
-  int64_t GetCurrentContentRefreshRate() override;
-
-  // VideoDecoder implementation:
-  void SetDelegate(MediaPipelineBackend::Decoder::Delegate* delegate) override;
-  BufferStatus PushBuffer(CastDecoderBuffer* buffer) override;
-  void GetStatistics(Statistics* statistics) override;
-  bool SetConfig(const VideoConfig& config) override;
-
-  // VideoDecoderForTest implementation:
-  int64_t GetExpectedDroppedFrames() override;
-  int64_t GetExpectedRepeatedFrames() override;
-  int64_t GetNumberOfFramesTolerated() override;
-  int64_t GetNumberOfHardCorrectionsTolerated() override;
-  int64_t GetNumberOfSoftCorrectionsTolerated() override;
-  int64_t GetAvSyncDriftTolerated() override;
-
- private:
-  void UpkeepVsync();
-  int64_t GetVsyncPeriodUs();
-
-  base::RepeatingTimer vsync_timer_;
-
-  double linear_clock_rate_ =
-      (kClockRateNumerator * 1.0) / (kClockRateDenominator * 1.0);
-  int64_t content_fps_ = kContentFps;
-
-  int64_t display_refresh_rate_ = 60;
-
-  double linear_pts_rate_ = 1.0;
-  int64_t current_video_pts_ = INT64_MIN;
-  int64_t last_displayed_frame_pts_ = 0.0;
-  int64_t start_pts_ = 0;
-  int64_t dropped_frames_ = 0;
-  int64_t repeated_frames_ = 0;
-};
-
-typedef MockVideoDecoderForMixer<1, 1, 60> NormalVideoDecoder;
-typedef MockVideoDecoderForMixer<1, 1, 30> NormalVideoDecoder30;
-typedef MockVideoDecoderForMixer<1, 1, 24> NormalVideoDecoder24;
-typedef MockVideoDecoderForMixer<2, 1, 60> LinearDoubleSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<1, 2, 60> LinearHalfSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<14, 10, 60> Linear140PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<13, 10, 60> Linear130PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<12, 10, 60> Linear120PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<11, 10, 60> Linear110PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<9, 10, 60> Linear90PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<8, 10, 60> Linear80PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<7, 10, 60> Linear70PercentSpeedVideoDecoder;
-typedef MockVideoDecoderForMixer<6, 10, 60> Linear60PercentSpeedVideoDecoder;
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MOCK_VIDEO_DECODER_FOR_MIXER_H_
diff --git a/chromecast/renderer/cast_extensions_dispatcher_delegate.cc b/chromecast/renderer/cast_extensions_dispatcher_delegate.cc
index 1d6e519..fe9bbb6 100644
--- a/chromecast/renderer/cast_extensions_dispatcher_delegate.cc
+++ b/chromecast/renderer/cast_extensions_dispatcher_delegate.cc
@@ -27,7 +27,6 @@
 #include "extensions/renderer/bindings/api_bindings_system.h"
 #include "extensions/renderer/css_native_handler.h"
 #include "extensions/renderer/dispatcher.h"
-#include "extensions/renderer/i18n_custom_bindings.h"
 #include "extensions/renderer/lazy_background_page_native_handler.h"
 #include "extensions/renderer/native_extension_bindings_system.h"
 #include "extensions/renderer/native_handler.h"
@@ -56,9 +55,6 @@
       std::make_unique<extensions::cast::AutomationInternalCustomBindings>(
           context, bindings_system));
   module_system->RegisterNativeHandler(
-      "i18n", std::unique_ptr<NativeHandler>(
-                  new extensions::I18NCustomBindings(context)));
-  module_system->RegisterNativeHandler(
       "lazy_background_page",
       std::make_unique<extensions::LazyBackgroundPageNativeHandler>(context));
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 838cb6ad..95d66b85 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-11945.0.0
\ No newline at end of file
+11951.0.0
\ No newline at end of file
diff --git a/chromeos/components/proximity_auth/screenlock_bridge.cc b/chromeos/components/proximity_auth/screenlock_bridge.cc
index be5c0ac..8391263 100644
--- a/chromeos/components/proximity_auth/screenlock_bridge.cc
+++ b/chromeos/components/proximity_auth/screenlock_bridge.cc
@@ -12,7 +12,7 @@
 #include "build/build_config.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 namespace proximity_auth {
 namespace {
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index acfb172d..d42a98930 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -139,8 +139,6 @@
     "fake_runtime_probe_client.h",
     "fake_seneschal_client.cc",
     "fake_seneschal_client.h",
-    "fake_session_manager_client.cc",
-    "fake_session_manager_client.h",
     "fake_shill_device_client.cc",
     "fake_shill_device_client.h",
     "fake_shill_ipconfig_client.cc",
@@ -197,8 +195,10 @@
     "runtime_probe_client.h",
     "seneschal_client.cc",
     "seneschal_client.h",
-    "session_manager_client.cc",
-    "session_manager_client.h",
+    "session_manager/fake_session_manager_client.cc",
+    "session_manager/fake_session_manager_client.h",
+    "session_manager/session_manager_client.cc",
+    "session_manager/session_manager_client.h",
     "shill_client_helper.cc",
     "shill_client_helper.h",
     "shill_device_client.cc",
diff --git a/chromeos/dbus/dbus_clients_common.cc b/chromeos/dbus/dbus_clients_common.cc
index 40a5b24..905a838 100644
--- a/chromeos/dbus/dbus_clients_common.cc
+++ b/chromeos/dbus/dbus_clients_common.cc
@@ -26,7 +26,7 @@
 #include "chromeos/dbus/machine_learning_client.h"
 #include "chromeos/dbus/modem_messaging_client.h"
 #include "chromeos/dbus/permission_broker_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/shill_device_client.h"
 #include "chromeos/dbus/shill_ipconfig_client.h"
 #include "chromeos/dbus/shill_manager_client.h"
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 4413925b..09823b1 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -37,7 +37,7 @@
 #include "chromeos/dbus/permission_broker_client.h"
 #include "chromeos/dbus/runtime_probe_client.h"
 #include "chromeos/dbus/seneschal_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/shill_device_client.h"
 #include "chromeos/dbus/shill_ipconfig_client.h"
 #include "chromeos/dbus/shill_manager_client.h"
diff --git a/chromeos/dbus/fake_auth_policy_client.cc b/chromeos/dbus/fake_auth_policy_client.cc
index d798ef2..77c7e21 100644
--- a/chromeos/dbus/fake_auth_policy_client.cc
+++ b/chromeos/dbus/fake_auth_policy_client.cc
@@ -17,7 +17,7 @@
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/proto/cloud_policy.pb.h"
diff --git a/chromeos/dbus/fake_auth_policy_client.h b/chromeos/dbus/fake_auth_policy_client.h
index cb65912c..882c440 100644
--- a/chromeos/dbus/fake_auth_policy_client.h
+++ b/chromeos/dbus/fake_auth_policy_client.h
@@ -14,7 +14,7 @@
 #include "base/time/time.h"
 
 #include "chromeos/dbus/auth_policy_client.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 
diff --git a/chromeos/dbus/fake_auth_policy_client_unittest.cc b/chromeos/dbus/fake_auth_policy_client_unittest.cc
index 5b4d3b1..f4631df 100644
--- a/chromeos/dbus/fake_auth_policy_client_unittest.cc
+++ b/chromeos/dbus/fake_auth_policy_client_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/run_loop.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/util/tpm_util.h"
 #include "components/account_id/account_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/dbus/kerberos/BUILD.gn b/chromeos/dbus/kerberos/BUILD.gn
new file mode 100644
index 0000000..37da5256
--- /dev/null
+++ b/chromeos/dbus/kerberos/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
+
+component("kerberos") {
+  defines = [ "IS_KERBEROS_IMPL" ]
+
+  deps = [
+    ":kerberos_proto",
+    "//base",
+    "//dbus",
+  ]
+
+  sources = [
+    "fake_kerberos_client.cc",
+    "fake_kerberos_client.h",
+    "kerberos_client.cc",
+    "kerberos_client.h",
+  ]
+}
+
+proto_library("kerberos_proto") {
+  sources = [
+    "//third_party/cros_system_api/dbus/kerberos/kerberos_service.proto",
+  ]
+
+  proto_out_dir = "chromeos/dbus/kerberos"
+}
diff --git a/chromeos/dbus/kerberos/fake_kerberos_client.cc b/chromeos/dbus/kerberos/fake_kerberos_client.cc
new file mode 100644
index 0000000..736f84c
--- /dev/null
+++ b/chromeos/dbus/kerberos/fake_kerberos_client.cc
@@ -0,0 +1,133 @@
+// 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 "chromeos/dbus/kerberos/fake_kerberos_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "third_party/cros_system_api/dbus/kerberos/dbus-constants.h"
+
+namespace chromeos {
+namespace {
+
+// Posts |callback| on the current thread's task runner, passing it the
+// |response| message.
+template <class TProto>
+void PostProtoResponse(base::OnceCallback<void(const TProto&)> callback,
+                       const TProto& response) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), response));
+}
+
+// Similar to PostProtoResponse(), but posts |callback| with a proto containing
+// only the given |error|.
+template <class TProto>
+void PostResponse(base::OnceCallback<void(const TProto&)> callback,
+                  kerberos::ErrorType error) {
+  TProto response;
+  response.set_error(error);
+  PostProtoResponse(std::move(callback), response);
+}
+
+}  // namespace
+
+FakeKerberosClient::FakeKerberosClient() = default;
+
+FakeKerberosClient::~FakeKerberosClient() = default;
+
+void FakeKerberosClient::AddAccount(const kerberos::AddAccountRequest& request,
+                                    AddAccountCallback callback) {
+  if (accounts_.find(request.principal_name()) != accounts_.end()) {
+    PostResponse(std::move(callback), kerberos::ERROR_DUPLICATE_PRINCIPAL_NAME);
+    return;
+  }
+
+  accounts_[request.principal_name()] = AccountData();
+  PostResponse(std::move(callback), kerberos::ERROR_NONE);
+}
+
+void FakeKerberosClient::RemoveAccount(
+    const kerberos::RemoveAccountRequest& request,
+    RemoveAccountCallback callback) {
+  kerberos::ErrorType error = accounts_.erase(request.principal_name()) == 0
+                                  ? kerberos::ERROR_UNKNOWN_PRINCIPAL_NAME
+                                  : kerberos::ERROR_NONE;
+  PostResponse(std::move(callback), error);
+}
+
+void FakeKerberosClient::SetConfig(const kerberos::SetConfigRequest& request,
+                                   SetConfigCallback callback) {
+  base::Optional<AccountData> data = GetAccountData(request.principal_name());
+  if (!data) {
+    PostResponse(std::move(callback), kerberos::ERROR_UNKNOWN_PRINCIPAL_NAME);
+    return;
+  }
+
+  data->krb5conf = request.krb5conf();
+  PostResponse(std::move(callback), kerberos::ERROR_NONE);
+}
+
+void FakeKerberosClient::AcquireKerberosTgt(
+    const kerberos::AcquireKerberosTgtRequest& request,
+    int password_fd,
+    AcquireKerberosTgtCallback callback) {
+  base::Optional<AccountData> data = GetAccountData(request.principal_name());
+  if (!data) {
+    PostResponse(std::move(callback), kerberos::ERROR_UNKNOWN_PRINCIPAL_NAME);
+    return;
+  }
+
+  // It worked! Magic!
+  data->has_tgt = true;
+  PostResponse(std::move(callback), kerberos::ERROR_NONE);
+}
+
+void FakeKerberosClient::GetKerberosFiles(
+    const kerberos::GetKerberosFilesRequest& request,
+    GetKerberosFilesCallback callback) {
+  base::Optional<AccountData> data = GetAccountData(request.principal_name());
+  if (!data) {
+    PostResponse(std::move(callback), kerberos::ERROR_UNKNOWN_PRINCIPAL_NAME);
+    return;
+  }
+
+  kerberos::GetKerberosFilesResponse response;
+  if (data->has_tgt) {
+    response.mutable_files()->set_krb5cc("Fake Kerberos credential cache");
+    response.mutable_files()->set_krb5conf("Fake Kerberos configuration");
+  }
+  response.set_error(kerberos::ERROR_NONE);
+  PostProtoResponse(std::move(callback), response);
+}
+
+void FakeKerberosClient::ConnectToKerberosFileChangedSignal(
+    KerberosFilesChangedCallback callback) {
+  DCHECK(!kerberos_files_changed_callback_);
+  kerberos_files_changed_callback_ = callback;
+}
+
+base::Optional<FakeKerberosClient::AccountData>
+FakeKerberosClient::GetAccountData(const std::string& principal_name) {
+  auto it = accounts_.find(principal_name);
+  if (it == accounts_.end())
+    return base::nullopt;
+  return it->second;
+}
+
+KerberosClient::TestInterface* FakeKerberosClient::GetTestInterface() {
+  return this;
+}
+
+void FakeKerberosClient::FakeKerberosClient::set_started(bool started) {
+  started_ = started;
+}
+
+bool FakeKerberosClient::FakeKerberosClient::started() const {
+  return started_;
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/kerberos/fake_kerberos_client.h b/chromeos/dbus/kerberos/fake_kerberos_client.h
new file mode 100644
index 0000000..3699e42
--- /dev/null
+++ b/chromeos/dbus/kerberos/fake_kerberos_client.h
@@ -0,0 +1,71 @@
+// 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 CHROMEOS_DBUS_KERBEROS_FAKE_KERBEROS_CLIENT_H_
+#define CHROMEOS_DBUS_KERBEROS_FAKE_KERBEROS_CLIENT_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "base/optional.h"
+#include "chromeos/dbus/kerberos/kerberos_client.h"
+#include "chromeos/dbus/kerberos/kerberos_service.pb.h"
+#include "dbus/object_proxy.h"
+
+namespace chromeos {
+
+class COMPONENT_EXPORT(CHROMEOS_DBUS) FakeKerberosClient
+    : public KerberosClient,
+      public KerberosClient::TestInterface {
+ public:
+  FakeKerberosClient();
+  ~FakeKerberosClient() override;
+
+  // KerberosClient:
+  void AddAccount(const kerberos::AddAccountRequest& request,
+                  AddAccountCallback callback) override;
+  void RemoveAccount(const kerberos::RemoveAccountRequest& request,
+                     RemoveAccountCallback callback) override;
+  void SetConfig(const kerberos::SetConfigRequest& request,
+                 SetConfigCallback callback) override;
+  void AcquireKerberosTgt(const kerberos::AcquireKerberosTgtRequest& request,
+                          int password_fd,
+                          AcquireKerberosTgtCallback callback) override;
+  void GetKerberosFiles(const kerberos::GetKerberosFilesRequest& request,
+                        GetKerberosFilesCallback callback) override;
+  void ConnectToKerberosFileChangedSignal(
+      KerberosFilesChangedCallback callback) override;
+  KerberosClient::TestInterface* GetTestInterface() override;
+
+  // KerberosClient::TestInterface:
+  void set_started(bool started) override;
+  bool started() const override;
+
+ private:
+  struct AccountData {
+    // Kerberos configuration file.
+    std::string krb5conf;
+    // Gets set to true if AcquireKerberosTgt succeeds.
+    bool has_tgt = false;
+  };
+
+  // Returns the AccountData for |principal_name| if available or nullopt
+  // otherwise.
+  base::Optional<AccountData> GetAccountData(const std::string& principal_name);
+
+  // Maps principal name (user@REALM.COM) to account data.
+  using AccountsMap = std::unordered_map<std::string, AccountData>;
+  AccountsMap accounts_;
+
+  bool started_ = false;
+
+  KerberosFilesChangedCallback kerberos_files_changed_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeKerberosClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_KERBEROS_FAKE_KERBEROS_CLIENT_H_
diff --git a/chromeos/dbus/kerberos/kerberos_client.cc b/chromeos/dbus/kerberos/kerberos_client.cc
new file mode 100644
index 0000000..1cf12ca
--- /dev/null
+++ b/chromeos/dbus/kerberos/kerberos_client.cc
@@ -0,0 +1,226 @@
+// 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 "chromeos/dbus/kerberos/kerberos_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromeos/dbus/kerberos/fake_kerberos_client.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "third_party/cros_system_api/dbus/kerberos/dbus-constants.h"
+
+namespace chromeos {
+namespace {
+
+// Tries to parse a proto message from |response| into |proto|.
+// Returns false if |response| is nullptr or the message cannot be parsed.
+bool ParseProto(dbus::Response* response,
+                google::protobuf::MessageLite* proto) {
+  if (!response) {
+    LOG(ERROR) << "Failed to call kerberosd";
+    return false;
+  }
+
+  dbus::MessageReader reader(response);
+  if (!reader.PopArrayOfBytesAsProto(proto)) {
+    LOG(ERROR) << "Failed to parse response message from kerberosd";
+    return false;
+  }
+
+  return true;
+}
+
+KerberosClient* g_instance = nullptr;
+
+// "Real" implementation of KerberosClient taking to the Kerberos daemon on the
+// Chrome OS side.
+class KerberosClientImpl : public KerberosClient {
+ public:
+  explicit KerberosClientImpl(dbus::Bus* bus) {
+    CHECK(bus);
+    InitDBus(bus);
+  }
+
+  ~KerberosClientImpl() override = default;
+
+  // KerberosClient overrides:
+  void AddAccount(const kerberos::AddAccountRequest& request,
+                  AddAccountCallback callback) override {
+    CallProtoMethod(kerberos::kAddAccountMethod, request, std::move(callback));
+  }
+
+  void RemoveAccount(const kerberos::RemoveAccountRequest& request,
+                     RemoveAccountCallback callback) override {
+    CallProtoMethod(kerberos::kRemoveAccountMethod, request,
+                    std::move(callback));
+  }
+
+  void SetConfig(const kerberos::SetConfigRequest& request,
+                 SetConfigCallback callback) override {
+    CallProtoMethod(kerberos::kSetConfigMethod, request, std::move(callback));
+  }
+
+  void AcquireKerberosTgt(const kerberos::AcquireKerberosTgtRequest& request,
+                          int password_fd,
+                          AcquireKerberosTgtCallback callback) override {
+    // kAcquireKerberosTgtMethod takes |password_fd| as extra arg.
+    CallProtoMethodWithExtraArgs(
+        kerberos::kAcquireKerberosTgtMethod, request, std::move(callback),
+        base::BindOnce(
+            [](int in_password_fd, dbus::MessageWriter* writer) {
+              writer->AppendFileDescriptor(in_password_fd);
+            },
+            password_fd));
+  }
+
+  void GetKerberosFiles(const kerberos::GetKerberosFilesRequest& request,
+                        GetKerberosFilesCallback callback) override {
+    CallProtoMethod(kerberos::kGetKerberosFilesMethod, request,
+                    std::move(callback));
+  }
+
+  void ConnectToKerberosFileChangedSignal(
+      KerberosFilesChangedCallback callback) override {
+    DCHECK(callback);
+    kerberos_files_changed_callback_ = callback;
+
+    proxy_->ConnectToSignal(
+        kerberos::kKerberosInterface, kerberos::kKerberosFilesChangedSignal,
+        base::BindRepeating(&KerberosClientImpl::OnKerberosFilesChanged,
+                            weak_factory_.GetWeakPtr()),
+        base::BindOnce(&KerberosClientImpl::OnKerberosFilesChangedConnected,
+                       weak_factory_.GetWeakPtr()));
+  }
+
+  void OnKerberosFilesChanged(dbus::Signal* signal) {
+    DCHECK_EQ(signal->GetInterface(), kerberos::kKerberosInterface);
+    DCHECK_EQ(signal->GetMember(), kerberos::kKerberosFilesChangedSignal);
+
+    dbus::MessageReader signal_reader(signal);
+    std::string principal_name;
+    if (!signal_reader.PopString(&principal_name)) {
+      LOG(ERROR)
+          << "Failed to read principal name for KerberosFilesChanged signal";
+      return;
+    }
+
+    DCHECK(kerberos_files_changed_callback_);
+    kerberos_files_changed_callback_.Run(principal_name);
+  }
+
+  void OnKerberosFilesChangedConnected(const std::string& interface_name,
+                                       const std::string& signal_name,
+                                       bool success) {
+    DCHECK_EQ(interface_name, kerberos::kKerberosInterface);
+    DCHECK_EQ(signal_name, kerberos::kKerberosFilesChangedSignal);
+    DCHECK(success);
+  }
+
+  TestInterface* GetTestInterface() override { return nullptr; }
+
+ private:
+  void InitDBus(dbus::Bus* bus) {
+    proxy_ =
+        bus->GetObjectProxy(kerberos::kKerberosServiceName,
+                            dbus::ObjectPath(kerberos::kKerberosServicePath));
+  }
+
+  // Calls kerberosd's |method_name| method, passing in |request| as input. Once
+  // the (asynchronous) call finishes, |callback| is called with the response
+  // proto (on the same thread as this call).
+  template <class TRequest, class TResponse>
+  void CallProtoMethodWithExtraArgs(
+      const char* method_name,
+      const TRequest& request,
+      base::OnceCallback<void(const TResponse&)> callback,
+      base::OnceCallback<void(dbus::MessageWriter*)> write_extra_args) {
+    dbus::MethodCall method_call(kerberos::kKerberosInterface, method_name);
+    dbus::MessageWriter writer(&method_call);
+    if (!writer.AppendProtoAsArrayOfBytes(request)) {
+      TResponse response;
+      response.set_error(kerberos::ERROR_DBUS_FAILURE);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(std::move(callback), response));
+      return;
+    }
+    if (write_extra_args)
+      std::move(write_extra_args).Run(&writer);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&KerberosClientImpl::HandleResponse<TResponse>,
+                       weak_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  // Same as CallProtoMethodWithExtraArgs, but doesn't pass in extra args.
+  // Use for methods that only take a request proto as input.
+  template <class TRequest, class TResponse>
+  void CallProtoMethod(const char* method_name,
+                       const TRequest& request,
+                       base::OnceCallback<void(const TResponse&)> callback) {
+    CallProtoMethodWithExtraArgs(method_name, request, std::move(callback), {});
+  }
+
+  // Parses the response proto message from |response| and calls |callback| with
+  // the decoded message. Calls |callback| with an |ERROR_DBUS_FAILURE| message
+  // on error.
+  template <class TProto>
+  void HandleResponse(base::OnceCallback<void(const TProto&)> callback,
+                      dbus::Response* response) {
+    TProto response_proto;
+    if (!ParseProto(response, &response_proto))
+      response_proto.set_error(kerberos::ERROR_DBUS_FAILURE);
+    std::move(callback).Run(response_proto);
+  }
+
+  // D-Bus proxy for the Kerberos daemon, not owned.
+  dbus::ObjectProxy* proxy_ = nullptr;
+
+  // Callback for the KerberosFilesChanged signal.
+  KerberosFilesChangedCallback kerberos_files_changed_callback_;
+
+  base::WeakPtrFactory<KerberosClientImpl> weak_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(KerberosClientImpl);
+};
+
+}  // namespace
+
+KerberosClient::KerberosClient() {
+  CHECK(!g_instance);
+  g_instance = this;
+}
+
+KerberosClient::~KerberosClient() {
+  CHECK_EQ(this, g_instance);
+  g_instance = nullptr;
+}
+
+// static
+void KerberosClient::Initialize(dbus::Bus* bus) {
+  CHECK(bus);
+  new KerberosClientImpl(bus);
+}
+
+// static
+void KerberosClient::InitializeFake() {
+  new FakeKerberosClient();
+}
+
+// static
+void KerberosClient::Shutdown() {
+  CHECK(g_instance);
+  delete g_instance;
+}
+
+// static
+KerberosClient* KerberosClient::Get() {
+  return g_instance;
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/kerberos/kerberos_client.h b/chromeos/dbus/kerberos/kerberos_client.h
new file mode 100644
index 0000000..01f9ae05
--- /dev/null
+++ b/chromeos/dbus/kerberos/kerberos_client.h
@@ -0,0 +1,97 @@
+// 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 CHROMEOS_DBUS_KERBEROS_KERBEROS_CLIENT_H_
+#define CHROMEOS_DBUS_KERBEROS_KERBEROS_CLIENT_H_
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "chromeos/dbus/kerberos/kerberos_service.pb.h"
+#include "dbus/object_proxy.h"
+
+namespace dbus {
+class Bus;
+}
+
+namespace chromeos {
+
+// KerberosClient is used to communicate with the org.chromium.Kerberos
+// service. All method should be called from the origin thread (UI thread) which
+// initializes the DBusThreadManager instance.
+class COMPONENT_EXPORT(KERBEROS) KerberosClient {
+ public:
+  using AddAccountCallback =
+      base::OnceCallback<void(const kerberos::AddAccountResponse& response)>;
+  using RemoveAccountCallback =
+      base::OnceCallback<void(const kerberos::RemoveAccountResponse& response)>;
+  using SetConfigCallback =
+      base::OnceCallback<void(const kerberos::SetConfigResponse& response)>;
+  using AcquireKerberosTgtCallback = base::OnceCallback<void(
+      const kerberos::AcquireKerberosTgtResponse& response)>;
+  using GetKerberosFilesCallback = base::OnceCallback<void(
+      const kerberos::GetKerberosFilesResponse& response)>;
+  using KerberosFilesChangedCallback =
+      base::RepeatingCallback<void(const std::string& principal_name)>;
+
+  // Interface for testing. Only implemented in the fake implementation.
+  class TestInterface {
+   public:
+    // Sets whether the (fake) daemon has been started by Upstart.
+    virtual void set_started(bool started) = 0;
+
+    // Whether the (fake) daemon has been started and is in a running state.
+    virtual bool started() const = 0;
+  };
+
+  // Creates and initializes the global instance. |bus| must not be null.
+  static void Initialize(dbus::Bus* bus);
+
+  // Creates and initializes a fake global instance if not already created.
+  static void InitializeFake();
+
+  // Destroys the global instance.
+  static void Shutdown();
+
+  // Returns the global instance which may be null if not initialized.
+  static KerberosClient* Get();
+
+  // Kerberos daemon D-Bus method calls. See org.chromium.Kerberos.xml and
+  // kerberos_service.proto in Chromium OS code for the documentation of the
+  // methods and request/response messages.
+  virtual void AddAccount(const kerberos::AddAccountRequest& request,
+                          AddAccountCallback callback) = 0;
+
+  virtual void RemoveAccount(const kerberos::RemoveAccountRequest& request,
+                             RemoveAccountCallback callback) = 0;
+
+  virtual void SetConfig(const kerberos::SetConfigRequest& request,
+                         SetConfigCallback callback) = 0;
+
+  virtual void AcquireKerberosTgt(
+      const kerberos::AcquireKerberosTgtRequest& request,
+      int password_fd,
+      AcquireKerberosTgtCallback callback) = 0;
+
+  virtual void GetKerberosFiles(
+      const kerberos::GetKerberosFilesRequest& request,
+      GetKerberosFilesCallback callback) = 0;
+
+  virtual void ConnectToKerberosFileChangedSignal(
+      KerberosFilesChangedCallback callback) = 0;
+
+  virtual TestInterface* GetTestInterface() = 0;
+
+ protected:
+  // Initialize/Shutdown should be used instead.
+  KerberosClient();
+  virtual ~KerberosClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(KerberosClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_KERBEROS_KERBEROS_CLIENT_H_
diff --git a/chromeos/dbus/power/fake_power_manager_client.cc b/chromeos/dbus/power/fake_power_manager_client.cc
index ef025fe..e2178f06 100644
--- a/chromeos/dbus/power/fake_power_manager_client.cc
+++ b/chromeos/dbus/power/fake_power_manager_client.cc
@@ -255,10 +255,6 @@
                     base::Unretained(this));
 }
 
-int FakePowerManagerClient::GetNumPendingSuspendReadinessCallbacks() {
-  return num_pending_suspend_readiness_callbacks_;
-}
-
 void FakePowerManagerClient::CreateArcTimers(
     const std::string& tag,
     std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests,
diff --git a/chromeos/dbus/power/fake_power_manager_client.h b/chromeos/dbus/power/fake_power_manager_client.h
index cdc3fdf..e2ed21a 100644
--- a/chromeos/dbus/power/fake_power_manager_client.h
+++ b/chromeos/dbus/power/fake_power_manager_client.h
@@ -48,6 +48,9 @@
   int num_wake_notification_calls() const {
     return num_wake_notification_calls_;
   }
+  int num_pending_suspend_readiness_callbacks() const {
+    return num_pending_suspend_readiness_callbacks_;
+  }
   double screen_brightness_percent() const {
     return screen_brightness_percent_.value();
   }
@@ -109,7 +112,6 @@
       override;
   base::Closure GetSuspendReadinessCallback(
       const base::Location& from_where) override;
-  int GetNumPendingSuspendReadinessCallbacks() override;
   void CreateArcTimers(
       const std::string& tag,
       std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests,
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc
index c367149..44b94e0 100644
--- a/chromeos/dbus/power/power_manager_client.cc
+++ b/chromeos/dbus/power/power_manager_client.cc
@@ -463,10 +463,6 @@
                       suspending_from_dark_resume_, callback_id);
   }
 
-  int GetNumPendingSuspendReadinessCallbacks() override {
-    return pending_suspend_readiness_callbacks_.size();
-  }
-
   void CreateArcTimers(
       const std::string& tag,
       std::vector<std::pair<clockid_t, base::ScopedFD>> arc_timer_requests,
@@ -1054,7 +1050,7 @@
     if (notifying_observers_about_suspend_imminent_)
       return;
 
-    if (GetNumPendingSuspendReadinessCallbacks() > 0)
+    if (!pending_suspend_readiness_callbacks_.empty())
       return;
 
     std::string method_name;
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h
index e22e35c4..b1f2938a 100644
--- a/chromeos/dbus/power/power_manager_client.h
+++ b/chromeos/dbus/power/power_manager_client.h
@@ -279,10 +279,6 @@
   virtual base::Closure GetSuspendReadinessCallback(
       const base::Location& from_where) = 0;
 
-  // Returns the number of callbacks returned by GetSuspendReadinessCallback()
-  // for the current suspend attempt but not yet called. Used by tests.
-  virtual int GetNumPendingSuspendReadinessCallbacks() = 0;
-
   // Creates timers corresponding to clocks present in |arc_timer_requests|.
   // ScopedFDs are used to indicate timer expiration as described in
   // |StartArcTimer|. Aysnchronously runs |callback| with the created timers'
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/session_manager/fake_session_manager_client.cc
similarity index 99%
rename from chromeos/dbus/fake_session_manager_client.cc
rename to chromeos/dbus/session_manager/fake_session_manager_client.cc
index b8d142c..e628292 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/session_manager/fake_session_manager_client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 
 #include <utility>
 
diff --git a/chromeos/dbus/fake_session_manager_client.h b/chromeos/dbus/session_manager/fake_session_manager_client.h
similarity index 97%
rename from chromeos/dbus/fake_session_manager_client.h
rename to chromeos/dbus/session_manager/fake_session_manager_client.h
index ff7e2356..5aded90 100644
--- a/chromeos/dbus/fake_session_manager_client.h
+++ b/chromeos/dbus/session_manager/fake_session_manager_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_FAKE_SESSION_MANAGER_CLIENT_H_
-#define CHROMEOS_DBUS_FAKE_SESSION_MANAGER_CLIENT_H_
+#ifndef CHROMEOS_DBUS_SESSION_MANAGER_FAKE_SESSION_MANAGER_CLIENT_H_
+#define CHROMEOS_DBUS_SESSION_MANAGER_FAKE_SESSION_MANAGER_CLIENT_H_
 
 #include <map>
 #include <string>
@@ -16,7 +16,7 @@
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/login_manager/arc.pb.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 namespace chromeos {
 
@@ -258,4 +258,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_FAKE_SESSION_MANAGER_CLIENT_H_
+#endif  // CHROMEOS_DBUS_SESSION_MANAGER_FAKE_SESSION_MANAGER_CLIENT_H_
diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager/session_manager_client.cc
similarity index 99%
rename from chromeos/dbus/session_manager_client.cc
rename to chromeos/dbus/session_manager/session_manager_client.cc
index f83547e..def291b 100644
--- a/chromeos/dbus/session_manager_client.cc
+++ b/chromeos/dbus/session_manager/session_manager_client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -24,9 +24,9 @@
 #include "chromeos/dbus/blocking_method_caller.h"
 #include "chromeos/dbus/cryptohome/rpc.pb.h"
 #include "chromeos/dbus/cryptohome_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/login_manager/arc.pb.h"
 #include "chromeos/dbus/login_manager/policy_descriptor.pb.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
diff --git a/chromeos/dbus/session_manager_client.h b/chromeos/dbus/session_manager/session_manager_client.h
similarity index 98%
rename from chromeos/dbus/session_manager_client.h
rename to chromeos/dbus/session_manager/session_manager_client.h
index 24260a4a..ac4fe5d 100644
--- a/chromeos/dbus/session_manager_client.h
+++ b/chromeos/dbus/session_manager/session_manager_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_DBUS_SESSION_MANAGER_CLIENT_H_
-#define CHROMEOS_DBUS_SESSION_MANAGER_CLIENT_H_
+#ifndef CHROMEOS_DBUS_SESSION_MANAGER_SESSION_MANAGER_CLIENT_H_
+#define CHROMEOS_DBUS_SESSION_MANAGER_SESSION_MANAGER_CLIENT_H_
 
 #include <map>
 #include <string>
@@ -377,4 +377,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_DBUS_SESSION_MANAGER_CLIENT_H_
+#endif  // CHROMEOS_DBUS_SESSION_MANAGER_SESSION_MANAGER_CLIENT_H_
diff --git a/chromeos/disks/suspend_unmount_manager_unittest.cc b/chromeos/disks/suspend_unmount_manager_unittest.cc
index b2e513e..cae05c9 100644
--- a/chromeos/disks/suspend_unmount_manager_unittest.cc
+++ b/chromeos/disks/suspend_unmount_manager_unittest.cc
@@ -91,7 +91,7 @@
   fake_power_client_.SendSuspendImminent(
       power_manager::SuspendImminent_Reason_OTHER);
 
-  EXPECT_EQ(1, fake_power_client_.GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, fake_power_client_.num_pending_suspend_readiness_callbacks());
   EXPECT_EQ(2u, disk_mount_manager_.unmounting_mount_paths().size());
   EXPECT_EQ(1, std::count(disk_mount_manager_.unmounting_mount_paths().begin(),
                           disk_mount_manager_.unmounting_mount_paths().end(),
@@ -103,7 +103,7 @@
                           disk_mount_manager_.unmounting_mount_paths().end(),
                           kDummyMountPathUnknown));
   disk_mount_manager_.NotifyUnmountDeviceComplete(MOUNT_ERROR_NONE);
-  EXPECT_EQ(0, fake_power_client_.GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(0, fake_power_client_.num_pending_suspend_readiness_callbacks());
 }
 
 TEST_F(SuspendUnmountManagerTest, CancelAndSuspendAgain) {
@@ -119,7 +119,7 @@
   disk_mount_manager_.SetupDefaultReplies();
   fake_power_client_.SendSuspendImminent(
       power_manager::SuspendImminent_Reason_OTHER);
-  EXPECT_EQ(1, fake_power_client_.GetNumPendingSuspendReadinessCallbacks());
+  EXPECT_EQ(1, fake_power_client_.num_pending_suspend_readiness_callbacks());
   ASSERT_EQ(1u, disk_mount_manager_.unmounting_mount_paths().size());
   EXPECT_EQ(kDummyMountPath,
             disk_mount_manager_.unmounting_mount_paths().front());
diff --git a/chromeos/login/auth/login_performer.cc b/chromeos/login/auth/login_performer.cc
index 6ed339d..b111581 100644
--- a/chromeos/login/auth/login_performer.cc
+++ b/chromeos/login/auth/login_performer.cc
@@ -15,7 +15,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/auth/login_event_recorder.h"
 #include "components/account_id/account_id.h"
 #include "components/prefs/pref_service.h"
diff --git a/chromeos/system/dark_resume_controller_unittest.cc b/chromeos/system/dark_resume_controller_unittest.cc
index 70cfce5e..4a2376c 100644
--- a/chromeos/system/dark_resume_controller_unittest.cc
+++ b/chromeos/system/dark_resume_controller_unittest.cc
@@ -96,7 +96,8 @@
   run_loop.RunUntilIdle();
   EXPECT_TRUE(dark_resume_controller_->IsDarkResumeStateClearedForTesting());
   EXPECT_EQ(
-      0, fake_power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+      0,
+      fake_power_manager_client()->num_pending_suspend_readiness_callbacks());
 
   // Trigger a dark resume event, acquire and release a wake lock and move time
   // forward to trigger a wake lock check. The device should re-suspend in this
@@ -110,7 +111,8 @@
   run_loop2.RunUntilIdle();
   EXPECT_TRUE(dark_resume_controller_->IsDarkResumeStateClearedForTesting());
   EXPECT_EQ(
-      0, fake_power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+      0,
+      fake_power_manager_client()->num_pending_suspend_readiness_callbacks());
 }
 
 TEST_F(DarkResumeControllerTest, CheckSuspendAfterDarkResumeWakeLocksHeld) {
@@ -136,7 +138,8 @@
   run_loop2.RunUntilIdle();
   EXPECT_TRUE(dark_resume_controller_->IsDarkResumeStateClearedForTesting());
   EXPECT_EQ(
-      0, fake_power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+      0,
+      fake_power_manager_client()->num_pending_suspend_readiness_callbacks());
 }
 
 TEST_F(DarkResumeControllerTest, CheckSuspendAfterDarkResumeHardTimeout) {
@@ -162,7 +165,8 @@
   run_loop2.RunUntilIdle();
   EXPECT_TRUE(dark_resume_controller_->IsDarkResumeStateClearedForTesting());
   EXPECT_EQ(
-      0, fake_power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+      0,
+      fake_power_manager_client()->num_pending_suspend_readiness_callbacks());
 }
 
 TEST_F(DarkResumeControllerTest, CheckStateResetAfterSuspendDone) {
diff --git a/components/arc/arc_client_adapter.h b/components/arc/arc_client_adapter.h
index a8add82..3d9812c 100644
--- a/components/arc/arc_client_adapter.h
+++ b/components/arc/arc_client_adapter.h
@@ -13,7 +13,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "chromeos/dbus/login_manager/arc.pb.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 namespace arc {
 
diff --git a/components/arc/arc_container_client_adapter.cc b/components/arc/arc_container_client_adapter.cc
index d9f08c6..3978b9f 100644
--- a/components/arc/arc_container_client_adapter.cc
+++ b/components/arc/arc_container_client_adapter.cc
@@ -12,7 +12,7 @@
 #include "chromeos/dbus/dbus_method_call_status.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/login_manager/arc.pb.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 
 namespace arc {
 
diff --git a/components/arc/arc_session_impl.cc b/components/arc/arc_session_impl.cc
index 3dc198a..0c638c3 100644
--- a/components/arc/arc_session_impl.cc
+++ b/components/arc/arc_session_impl.cc
@@ -53,21 +53,6 @@
   return base::HexEncode(random_bytes, 16);
 }
 
-// Creates a pipe. Returns true on success, otherwise false.
-// On success, |read_fd| will be set to the fd of the read side, and
-// |write_fd| will be set to the one of write side.
-bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) {
-  int fds[2];
-  if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) {
-    PLOG(ERROR) << "pipe2()";
-    return false;
-  }
-
-  read_fd->reset(fds[0]);
-  write_fd->reset(fds[1]);
-  return true;
-}
-
 // Waits until |raw_socket_fd| is readable.
 // The operation may be cancelled originally triggered by user interaction to
 // disable ARC, or ARC instance is unexpectedly stopped (e.g. crash).
@@ -189,8 +174,8 @@
   // Stop().
   base::ScopedFD cancel_fd;
   base::ScopedFD return_fd;
-  if (!CreatePipe(&cancel_fd, &return_fd)) {
-    LOG(ERROR) << "Failed to create a pipe to cancel accept()";
+  if (!base::CreatePipe(&cancel_fd, &return_fd, true)) {
+    PLOG(ERROR) << "Failed to create a pipe to cancel accept()";
     return base::ScopedFD();
   }
 
diff --git a/components/arc/arc_session_impl_unittest.cc b/components/arc/arc_session_impl_unittest.cc
index 2cd6bae8..16bacce 100644
--- a/components/arc/arc_session_impl_unittest.cc
+++ b/components/arc/arc_session_impl_unittest.cc
@@ -17,7 +17,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/account_id/account_id.h"
 #include "components/arc/arc_session_impl.h"
 #include "components/arc/test/fake_arc_bridge_host.h"
diff --git a/components/arc/arc_session_runner_unittest.cc b/components/arc/arc_session_runner_unittest.cc
index 57ef9318..4c0695d 100644
--- a/components/arc/arc_session_runner_unittest.cc
+++ b/components/arc/arc_session_runner_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_arc_session.h"
diff --git a/components/arc/arc_util.cc b/components/arc/arc_util.cc
index 4eaf4db..cfc3107 100644
--- a/components/arc/arc_util.cc
+++ b/components/arc/arc_util.cc
@@ -13,7 +13,7 @@
 #include "base/feature_list.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/arc/arc_features.h"
 #include "components/user_manager/user_manager.h"
 #include "ui/aura/client/aura_constants.h"
diff --git a/components/arc/arc_vm_client_adapter.cc b/components/arc/arc_vm_client_adapter.cc
index fc795c59..80703df 100644
--- a/components/arc/arc_vm_client_adapter.cc
+++ b/components/arc/arc_vm_client_adapter.cc
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/post_task.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 
 namespace arc {
@@ -21,7 +21,7 @@
 namespace {
 
 // TODO(yusukes): Move ArcContainerStopReason to arc:: and stop including
-// chromeos/dbus/session_manager_client.h.
+// chromeos/dbus/session_manager/session_manager_client.h.
 constexpr login_manager::ArcContainerStopReason kDummyReason =
     login_manager::ArcContainerStopReason::SESSION_MANAGER_SHUTDOWN;
 
diff --git a/components/arc/metrics/arc_metrics_service.cc b/components/arc/metrics/arc_metrics_service.cc
index ad2859d6..dff0128 100644
--- a/components/arc/metrics/arc_metrics_service.cc
+++ b/components/arc/metrics/arc_metrics_service.cc
@@ -18,7 +18,7 @@
 #include "base/time/default_tick_clock.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/arc/arc_prefs.h"
diff --git a/components/arc/metrics/arc_metrics_service_unittest.cc b/components/arc/metrics/arc_metrics_service_unittest.cc
index 8e95523..d838a75 100644
--- a/components/arc/metrics/arc_metrics_service_unittest.cc
+++ b/components/arc/metrics/arc_metrics_service_unittest.cc
@@ -17,9 +17,9 @@
 #include "base/time/clock.h"
 #include "base/time/tick_clock.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/idle.pb.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/metrics/arc_metrics_constants.h"
diff --git a/components/arc/power/arc_power_bridge_unittest.cc b/components/arc/power/arc_power_bridge_unittest.cc
index 21c34971..8ca5853 100644
--- a/components/arc/power/arc_power_bridge_unittest.cc
+++ b/components/arc/power/arc_power_bridge_unittest.cc
@@ -128,12 +128,12 @@
   EXPECT_EQ(1, power_instance_->num_suspend());
   EXPECT_EQ(0, power_instance_->num_resume());
   EXPECT_EQ(1,
-            power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+            power_manager_client()->num_pending_suspend_readiness_callbacks());
 
   // Simulate Android acknowledging that it's ready for the system to suspend.
   power_instance_->GetSuspendCallback().Run();
   EXPECT_EQ(0,
-            power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+            power_manager_client()->num_pending_suspend_readiness_callbacks());
 
   power_manager_client()->SendSuspendDone();
   EXPECT_EQ(1, power_instance_->num_suspend());
@@ -144,7 +144,7 @@
   power_manager_client()->SendSuspendImminent(
       power_manager::SuspendImminent_Reason_OTHER);
   EXPECT_EQ(0,
-            power_manager_client()->GetNumPendingSuspendReadinessCallbacks());
+            power_manager_client()->num_pending_suspend_readiness_callbacks());
   power_manager_client()->SendSuspendDone();
 }
 
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index e46c751..c7c3a5da 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -568,11 +568,6 @@
   return input ? *input : WebInputElement();
 }
 
-void LogSendPasswordForm(SendPasswordFormToBrowserProcess value) {
-  UMA_HISTOGRAM_ENUMERATION("PasswordManager.SendPasswordFormToBrowserProcess",
-                            value);
-}
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1142,11 +1137,6 @@
     FormStructureInfo form_structure_info =
         ExtractFormStructureInfo(password_form->form_data);
     if (only_visible || WasFormStructureChanged(form_structure_info)) {
-      if (only_visible) {
-        LogSendPasswordForm(
-            SendPasswordFormToBrowserProcess::kPasswordFormSentByOnlyVisible);
-      }
-
       forms_structure_cache_[form_structure_info.unique_renderer_id] =
           std::move(form_structure_info);
 
@@ -1154,9 +1144,6 @@
       continue;
     }
 
-    LogSendPasswordForm(
-        SendPasswordFormToBrowserProcess::kPasswordFormWasNotSent);
-
     WebVector<WebFormControlElement> control_elements_vector;
     form.GetFormControlElements(control_elements_vector);
 
@@ -1194,8 +1181,6 @@
       }
 
       password_forms.push_back(std::move(*password_form));
-      LogSendPasswordForm(
-          SendPasswordFormToBrowserProcess::kPasswordFormSentByNoFormTag);
     }
   }
 
@@ -1221,8 +1206,6 @@
       password_forms.back().signon_realm =
           GetSignOnRealm(password_forms.back().origin);
       password_forms.back().form_data.origin = password_forms.back().origin;
-      LogSendPasswordForm(
-          SendPasswordFormToBrowserProcess::kPasswordFormSentByNoFormTag);
     }
     if (!password_forms.empty()) {
       sent_request_to_store_ = true;
@@ -2092,55 +2075,35 @@
 
 bool PasswordAutofillAgent::WasFormStructureChanged(
     const FormStructureInfo& form_info) const {
-  if (form_info.unique_renderer_id == FormData::kNotSetFormRendererId) {
-    LogSendPasswordForm(
-        SendPasswordFormToBrowserProcess::kPasswordFormWithoutId);
+  if (form_info.unique_renderer_id == FormData::kNotSetFormRendererId)
     return true;
-  }
 
   auto cached_form = forms_structure_cache_.find(form_info.unique_renderer_id);
-  if (cached_form == forms_structure_cache_.end()) {
-    LogSendPasswordForm(
-        SendPasswordFormToBrowserProcess::kPasswordFormSentAsNewlyAdded);
+  if (cached_form == forms_structure_cache_.end())
     return true;
-  }
 
   const FormStructureInfo& cached_form_info = cached_form->second;
 
-  if (form_info.fields.size() != cached_form_info.fields.size()) {
-    LogSendPasswordForm(
-        SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange);
+  if (form_info.fields.size() != cached_form_info.fields.size())
     return true;
-  }
 
   for (size_t i = 0; i < form_info.fields.size(); ++i) {
     const FormFieldInfo& form_field = form_info.fields[i];
     const FormFieldInfo& cached_form_field = cached_form_info.fields[i];
 
-    if (form_field.unique_renderer_id != cached_form_field.unique_renderer_id) {
-      LogSendPasswordForm(
-          SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange);
+    if (form_field.unique_renderer_id != cached_form_field.unique_renderer_id)
       return true;
-    }
 
-    if (form_field.form_control_type != cached_form_field.form_control_type) {
-      LogSendPasswordForm(
-          SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange);
+    if (form_field.form_control_type != cached_form_field.form_control_type)
       return true;
-    }
 
     if (form_field.autocomplete_attribute !=
         cached_form_field.autocomplete_attribute) {
-      LogSendPasswordForm(
-          SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange);
       return true;
     }
 
-    if (form_field.is_focusable != cached_form_field.is_focusable) {
-      LogSendPasswordForm(
-          SendPasswordFormToBrowserProcess::kPasswordFormSentByStructureChange);
+    if (form_field.is_focusable != cached_form_field.is_focusable)
       return true;
-    }
   }
   return false;
 }
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 520d2ccb..cb35776 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -60,26 +60,6 @@
   kMaxValue = kPrefilledUsernameNotOverridden,
 };
 
-// Used in UMA histograms, please do NOT reorder.
-// Metric: "PasswordManager.SendPasswordFormToBrowserProcess".
-// This metrics is relevant for PasswordAutofillAgent::SendPasswordForms method.
-enum class SendPasswordFormToBrowserProcess {
-  // Password form wasn't sent to the browser process.
-  kPasswordFormWasNotSent = 0,
-  // Password form was sent, because only_visible == true.
-  kPasswordFormSentByOnlyVisible = 1,
-  // Password form was sent, because it's newly added form.
-  kPasswordFormSentAsNewlyAdded = 2,
-  // Password form was sent, because the form structure was changed.
-  kPasswordFormSentByStructureChange = 3,
-  // Password form was sent, because there is no form-tag.
-  kPasswordFormSentByNoFormTag = 4,
-  // Password form was sent, because there is no id. this should never happen;
-  // this enum value exists only for checking.
-  kPasswordFormWithoutId = 5,
-  kMaxValue = kPasswordFormWithoutId,
-};
-
 // Used in UMA histogram, please do NOT reorder.
 // Metric: "PasswordManager.FirstRendererFillingResult".
 // This metric records whether the PasswordAutofillAgent succeeded in filling
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index 6bb276e..db092d8 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -83,7 +83,12 @@
   // scripts, even though we're in the middle of a script. This includes
   // allowing access to the touchable elements set previously, in the same
   // script.
-  virtual void Prompt(std::unique_ptr<std::vector<Chip>> chips) = 0;
+  //
+  // |on_terminate| is called if the prompt is terminated, by Autofill Assistant
+  // shutting down. The action should return immediately with client error
+  // USER_ABORTED_ACTION.
+  virtual void Prompt(std::unique_ptr<std::vector<Chip>> chips,
+                      base::OnceCallback<void()> on_terminate) = 0;
 
   // Remove all chips from the UI.
   virtual void CancelPrompt() = 0;
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index f078280..b854c93 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -54,7 +54,9 @@
                void(const Selector& selector,
                     base::OnceCallback<void(bool)> callback));
 
-  MOCK_METHOD1(Prompt, void(std::unique_ptr<std::vector<Chip>> chips));
+  MOCK_METHOD2(Prompt,
+               void(std::unique_ptr<std::vector<Chip>> chips,
+                    base::OnceCallback<void()> on_terminate));
   MOCK_METHOD0(CancelPrompt, void());
 
   void FillAddressForm(const autofill::AutofillProfile* profile,
diff --git a/components/autofill_assistant/browser/actions/prompt_action.cc b/components/autofill_assistant/browser/actions/prompt_action.cc
index f850223..2a1f9bd 100644
--- a/components/autofill_assistant/browser/actions/prompt_action.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action.cc
@@ -130,7 +130,9 @@
                                             weak_ptr_factory_.GetWeakPtr(), i);
   }
   SetDefaultChipType(chips.get());
-  delegate_->Prompt(std::move(chips));
+  delegate_->Prompt(std::move(chips),
+                    base::BindOnce(&PromptAction::OnTerminated,
+                                   weak_ptr_factory_.GetWeakPtr()));
   precondition_changed_ = false;
 }
 
@@ -194,4 +196,14 @@
       proto_.prompt().choices(choice_index);
   std::move(callback_).Run(std::move(processed_action_proto_));
 }
+
+void PromptAction::OnTerminated() {
+  if (!callback_) {
+    NOTREACHED();
+    return;
+  }
+  UpdateProcessedAction(USER_ABORTED_ACTION);
+  std::move(callback_).Run(std::move(processed_action_proto_));
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/prompt_action.h b/components/autofill_assistant/browser/actions/prompt_action.h
index 57f821f..95465e77 100644
--- a/components/autofill_assistant/browser/actions/prompt_action.h
+++ b/components/autofill_assistant/browser/actions/prompt_action.h
@@ -40,6 +40,7 @@
   void OnAutoSelectElementExists(int choice_index, bool exists);
   void OnAutoSelectDone();
   void OnSuggestionChosen(int choice_index);
+  void OnTerminated();
 
   ProcessActionCallback callback_;
   ActionDelegate* delegate_;
diff --git a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
index a84ab5a..e169e431 100644
--- a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
@@ -43,9 +44,11 @@
           return std::make_unique<BatchElementChecker>(&mock_web_controller_);
         }));
 
-    ON_CALL(mock_action_delegate_, Prompt(_))
-        .WillByDefault(Invoke([this](std::unique_ptr<std::vector<Chip>> chips) {
+    ON_CALL(mock_action_delegate_, Prompt(_, _))
+        .WillByDefault(Invoke([this](std::unique_ptr<std::vector<Chip>> chips,
+                                     base::OnceCallback<void()> on_terminate) {
           chips_ = std::move(chips);
+          on_terminate_ = std::move(on_terminate);
         }));
     prompt_proto_ = proto_.mutable_prompt();
   }
@@ -61,6 +64,7 @@
   ActionProto proto_;
   PromptProto* prompt_proto_;
   std::unique_ptr<std::vector<Chip>> chips_;
+  base::OnceCallback<void()> on_terminate_;
 };
 
 TEST_F(PromptActionTest, ChoicesMissing) {
@@ -179,5 +183,19 @@
   task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
 }
 
+TEST_F(PromptActionTest, Terminate) {
+  auto* ok_proto = prompt_proto_->add_choices();
+  ok_proto->set_name("Ok");
+  ok_proto->set_chip_type(HIGHLIGHTED_ACTION);
+  ok_proto->set_server_payload("ok");
+
+  PromptAction action(proto_);
+  action.ProcessAction(&mock_action_delegate_, callback_.Get());
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              USER_ABORTED_ACTION))));
+  std::move(on_terminate_).Run();
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 7566bff..82513ebf 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -14,6 +14,7 @@
 #include "base/task/post_task.h"
 #include "base/time/tick_clock.h"
 #include "base/values.h"
+#include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
@@ -857,7 +858,10 @@
 
 void Controller::OnWebContentsFocused(
     content::RenderWidgetHost* render_widget_host) {
-  if (NeedsUI()) {
+  if (NeedsUI() &&
+      base::FeatureList::IsEnabled(features::kAutofillAssistantChromeEntry)) {
+    // Show UI again when re-focused in case the web contents moved activity.
+    // This is only enabled when tab-switching is enabled.
     client_->ShowUI();
   }
 }
@@ -887,6 +891,24 @@
   GetUiController()->OnPaymentRequestChanged(payment_request_options_.get());
 }
 
+void Controller::CancelPaymentRequest() {
+  payment_request_info_.reset();
+
+  if (!payment_request_options_)
+    return;
+
+  auto callback = std::move(payment_request_options_->callback);
+  SetPaymentRequestOptions(nullptr);
+
+  if (!callback) {
+    NOTREACHED();
+    return;
+  }
+  auto result = std::make_unique<PaymentInformation>();
+  result->succeed = false;
+  std::move(callback).Run(std::move(result));
+}
+
 ElementArea* Controller::touchable_element_area() {
   if (!touchable_element_area_) {
     touchable_element_area_ = std::make_unique<ElementArea>(this);
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 55d814c6d..671d33ba 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -100,6 +100,7 @@
   bool IsCookieExperimentEnabled() const;
   void SetPaymentRequestOptions(
       std::unique_ptr<PaymentRequestOptions> options) override;
+  void CancelPaymentRequest() override;
 
   // Overrides autofill_assistant::UiDelegate:
   AutofillAssistantState GetState() override;
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 7aa8aad..bdd24646 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -8,6 +8,8 @@
 #include <utility>
 
 #include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/mock_run_once_callback.h"
 #include "components/autofill_assistant/browser/mock_service.h"
 #include "components/autofill_assistant/browser/mock_ui_controller.h"
@@ -81,6 +83,8 @@
   ~ControllerTest() override {}
 
   void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kAutofillAssistantChromeEntry);
     auto web_controller = std::make_unique<NiceMock<MockWebController>>();
     mock_web_controller_ = web_controller.get();
     auto service = std::make_unique<NiceMock<MockService>>();
@@ -182,6 +186,7 @@
   // |thread_bundle_| must be the first field, to make sure that everything runs
   // in the same task environment.
   content::TestBrowserThreadBundle thread_bundle_;
+  base::test::ScopedFeatureList scoped_feature_list_;
   content::TestBrowserContext browser_context_;
   std::unique_ptr<content::WebContents> web_contents_;
   base::TimeTicks now_;
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index 7bd6aa0..7a3426c 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -85,4 +85,7 @@
     std::unique_ptr<PaymentRequestOptions> options) {
   payment_request_options_ = std::move(options);
 }
+
+void FakeScriptExecutorDelegate::CancelPaymentRequest() {}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index f7d8968..4670bac 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -42,6 +42,7 @@
   void SetChips(std::unique_ptr<std::vector<Chip>> chips) override;
   void SetPaymentRequestOptions(
       std::unique_ptr<PaymentRequestOptions> options) override;
+  void CancelPaymentRequest() override;
 
   void SetCurrentURL(const GURL& url) { current_url_ = url; }
 
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc
index 88e4ac52..b8f2614c 100644
--- a/components/autofill_assistant/browser/protocol_utils.cc
+++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -20,6 +20,7 @@
 #include "components/autofill_assistant/browser/actions/set_attribute_action.h"
 #include "components/autofill_assistant/browser/actions/set_form_field_value_action.h"
 #include "components/autofill_assistant/browser/actions/show_details_action.h"
+#include "components/autofill_assistant/browser/actions/show_info_box_action.h"
 #include "components/autofill_assistant/browser/actions/show_progress_bar_action.h"
 #include "components/autofill_assistant/browser/actions/stop_action.h"
 #include "components/autofill_assistant/browser/actions/tell_action.h"
@@ -241,6 +242,10 @@
         actions->emplace_back(std::make_unique<SetAttributeAction>(action));
         break;
       }
+      case ActionProto::ActionInfoCase::kShowInfoBox: {
+        actions->emplace_back(std::make_unique<ShowInfoBoxAction>(action));
+        break;
+      }
       default:
       case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: {
         DVLOG(1) << "Unknown or unsupported action with action_case="
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 702bb29..59f6083 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -249,7 +249,8 @@
   std::move(callback).Run(std::move(card), cvc);
 }
 
-void ScriptExecutor::Prompt(std::unique_ptr<std::vector<Chip>> chips) {
+void ScriptExecutor::Prompt(std::unique_ptr<std::vector<Chip>> chips,
+                            base::OnceCallback<void()> on_terminate) {
   if (touchable_element_area_) {
     // SetChips reproduces the end-of-script appearance and behavior during
     // script execution. This includes allowing access to touchable elements,
@@ -275,9 +276,14 @@
 
   delegate_->EnterState(AutofillAssistantState::PROMPT);
   delegate_->SetChips(std::move(chips));
+  on_terminate_prompt_ = std::move(on_terminate);
 }
 
 void ScriptExecutor::CancelPrompt() {
+  // Delete on_terminate_prompt_ if necessary, without running.
+  if (on_terminate_prompt_)
+    std::move(on_terminate_prompt_);
+
   delegate_->SetChips(nullptr);
   CleanUpAfterPrompt();
 }
@@ -390,6 +396,16 @@
     wait_with_interrupts_->Terminate();
   at_end_ = TERMINATE;
   should_stop_script_ = true;
+
+  // Force PR and other prompt-based actions to end.
+  //
+  // TODO(b/128300038): get rid of this special case. Instead, delete actions
+  // without waiting for them to return.
+  delegate_->CancelPaymentRequest();
+  if (on_terminate_prompt_) {
+    std::move(on_terminate_prompt_).Run();
+    CancelPrompt();
+  }
 }
 
 void ScriptExecutor::Close() {
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 2b9eef0..853078c 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -117,7 +117,8 @@
   void GetPaymentInformation(
       std::unique_ptr<PaymentRequestOptions> options) override;
   void GetFullCard(GetFullCardCallback callback) override;
-  void Prompt(std::unique_ptr<std::vector<Chip>> chips) override;
+  void Prompt(std::unique_ptr<std::vector<Chip>> chips,
+              base::OnceCallback<void()> on_terminate) override;
   void CancelPrompt() override;
   void FillAddressForm(const autofill::AutofillProfile* profile,
                        const Selector& selector,
@@ -311,6 +312,10 @@
 
   std::unique_ptr<WaitWithInterrupts> wait_with_interrupts_;
 
+  // Callback set by Prompt(). This is called when the prompt is terminated
+  // without selecting any chips. nullptr unless showing a prompt.
+  base::OnceCallback<void()> on_terminate_prompt_;
+
   base::WeakPtrFactory<ScriptExecutor> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(ScriptExecutor);
 };
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index a871dadb..8881a0f 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -54,6 +54,7 @@
   virtual void ClearInfoBox() = 0;
   virtual void SetPaymentRequestOptions(
       std::unique_ptr<PaymentRequestOptions> options) = 0;
+  virtual void CancelPaymentRequest() = 0;
   virtual void SetProgress(int progress) = 0;
   virtual void SetProgressVisible(bool visible) = 0;
   virtual void SetChips(std::unique_ptr<std::vector<Chip>> chips) = 0;
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index fff8f1dc..8309e6b 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -789,6 +789,7 @@
     "//net/android:net_java",
     "//net/android:net_java_test_support",
     "//url:url_java",
+    "//third_party/junit",
   ]
 
   android_library("cronet_javatests") {
@@ -843,7 +844,6 @@
       ":cronet_urlconnection_impl_java",
       "//third_party/android_support_test_runner:runner_java",
       "//third_party/hamcrest:hamcrest_core_java",
-      "//third_party/junit",
     ]
     deps += cronet_javatests_deps_to_package
     data = [
diff --git a/components/cronet/tools/generate_javadoc.py b/components/cronet/tools/generate_javadoc.py
index 062190d4..ba6133a 100755
--- a/components/cronet/tools/generate_javadoc.py
+++ b/components/cronet/tools/generate_javadoc.py
@@ -13,7 +13,7 @@
 REPOSITORY_ROOT = os.path.abspath(os.path.join(
     os.path.dirname(__file__), '..', '..', '..'))
 DOCLAVA_DIR = os.path.join(REPOSITORY_ROOT, 'buildtools', 'android', 'doclava')
-SDK_DIR = os.path.join(REPOSITORY_ROOT, 'third_party', 'android_tools', 'sdk')
+SDK_DIR = os.path.join(REPOSITORY_ROOT, 'third_party', 'android_sdk', 'public')
 
 sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util'))
 sys.path.append(os.path.join(REPOSITORY_ROOT, 'net/tools/net_docs'))
diff --git a/components/data_reduction_proxy/OWNERS b/components/data_reduction_proxy/OWNERS
index 84994dce..4207f58f 100644
--- a/components/data_reduction_proxy/OWNERS
+++ b/components/data_reduction_proxy/OWNERS
@@ -20,39 +20,42 @@
 # Leave ASCII Art in comments
 ################################################################################
 #                                                                              #
-#                                  ...........                                 #
-#                            .,**///(((((((((///**,.                           #
-#                        .*//(((((((((((((((((((((((/*,.                       #
-#                   .,//((((((((((((((////(((((((((((((((/*,                   #
-#                 .*/((((((((((//*,,........,,*//(((((((((((*.                 #
-#               .*/((((((((//*,.                .,*//((((((((/*.               #
-#             .*/(((((((((*.                        .*/((((((((/*.             #
-#           ,*/(((((((/*,                              .,*/(((((((/            #
-#          ./(((((((/*.                                   .*(((((((*.          #
-#         .*(((((((/,                                       */((((/,           #
-#        .*/((((((/.                                         ,*//,.            #
-#       ,/((((((/,                                                             #
-#      .*((((((/,                                                              #
-#      ,/(((((/,                                                    .,**,      #
-#     ,/((((/*                                                  .,*/((((*.     #
-#     */((((*.                                               .,*/(((((((/.     #
-#    .*(((/*           .*/*,.                              .//((((((((((/.     #
-#    .*/*.          .,//(((((/*,.                      .,*//((((((((((((/,     #
-#                .*/(((((((((((((//,.              .,//(((((((((///(((((/,     #
-#             .,//((((((((//((((((((//*.        .,*/(((((((((/*,..,(((((/.     #
-#           ,*/((((((((//*..,*/((((((((//*.   *//(((((((((//.     *(((((*.     #
-#       .,*/(((((((//,.         .*//(((((((((((((((((//*.        ./((((/,      #
-#      .*(((((((((/.               .,*/((((((((((((//.          .*/((((*.      #
-#       ,/(((((//,.                    *//((((((/*,.            ,/((((/,       #
-#        */((((/,                        .,*//*,.              ,/((((/*.       #
-#         ./((((/*.                                          .*/((((/,         #
-#          ./(((((/                                         ,/(((((/,          #
-#           */(((((*,                                      ,/((((((,           #
-#             ,//((((//*.                              .*/((((((/*.            #
-#               ,//(((((//,.                        .*/(((((((//,              #
-#                 ,/(((((((//*,..             ..,**//(((((((/*,                #
-#                  .,//(((((((((///*********///(((((((((((//.                  #
-#                       .,//(((((((((((((((((((((((((//*.                      #
-#                          .,,*//((((((((((((((///**,                          #
+#                            :=?I7777777777I777I+:,                            #
+#                      .,~?7777777777777777777777777I+:                        #
+#                   .~?777777777777777777777777777777777I=,                    #
+#                 ,=I777777777777I?+==~~~~=++?7777777777?:                     #
+#               ,?7777777777I~,                  ,+I7I~                        #
+#             ,?77777777I+,                                  .:,               #
+#           .=I7777777?:.                                  :?I,                #
+#           ?7777777I:                                 .,=I7?      ,           #
+#         ,I777777I:                                 ,+I777=      ~7+          #
+#        :I777777?,                                +I7777I:      =777+         #
+#       :I777777+                               :I777777I:      =I7777=        #
+#      ,?777777~                            .:?77777777?       ,?777777~       #
+#      =777777=                          .,=7777777777+         ,I77777I.      #
+#     ,?77777?,                        ,=I7777777777I~           ~777777+      #
+#     ~777777~                       =I777777777777?:            .I777777,     #
+#     +77777?,                   .,I77777777777777?               ~777777=     #
+#     ?77777?                    :777777777777777+                ,777777?     #
+#     I77777?                    I7777777777777I~                 .777777?     #
+#     I77777?                   .I777777777777?~.                 .777777?     #
+#     I77777?                   .:77777777777?                    ,777777?     #
+#     +77777?,                   .:I77777777+                     ~777777=     #
+#     ~I77777~                       :+++=,.                     .I777777,     #
+#     ,I77777?,                                                  ~777777+      #
+#      =777777=                                                 :I777777,      #
+#      ,?777777~                                               ,?777777~       #
+#       :I777777=                                             ,?777777=        #
+#        :I777777?                                           ,I777777+,        #
+#         ,I777777I:                                       .=7777777+          #
+#          .+7777777?:                                    =I7777777=           #
+#            =I7777777?~                               .=I7777777I:            #
+#             ,?777777777+,                          ~II7777777I~              #
+#               ,?7777777777I~,                  ,+I777777777I+                #
+#                 ,=I777777777777I?+=~~~~~~=+I7777777777777?~                  #
+#                    ~?I77777777777777777777777777777777I+,                    #
+#                       ,~?7777777777777777777777777I+:,                       #
+#                            :=?II777777777I7III+~,                            #
 #                                                                              #
 ################################################################################
+
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc
index f9ec2f1d..b7367a0 100644
--- a/components/download/internal/common/download_stats.cc
+++ b/components/download/internal/common/download_stats.cc
@@ -401,44 +401,52 @@
     FILE_PATH_LITERAL(".settingcontent-ms"),
     FILE_PATH_LITERAL(".oxt"),  // 317
     FILE_PATH_LITERAL(".pyd"),
-    FILE_PATH_LITERAL(".pyo"),           // 319
-    FILE_PATH_LITERAL(".desktop"),       // 320
-    FILE_PATH_LITERAL(".cpi"),           // 321
-    FILE_PATH_LITERAL(".jpg"),           // 322
-    FILE_PATH_LITERAL(".jpeg"),          // 323
-    FILE_PATH_LITERAL(".mp3"),           // 324
-    FILE_PATH_LITERAL(".mp4"),           // 325
-    FILE_PATH_LITERAL(".png"),           // 326
-    FILE_PATH_LITERAL(".xls"),           // 327
-    FILE_PATH_LITERAL(".doc"),           // 328
-    FILE_PATH_LITERAL(".pptx"),          // 329
-    FILE_PATH_LITERAL(".csv"),           // 330
-    FILE_PATH_LITERAL(".ica"),           // 331
-    FILE_PATH_LITERAL(".ppt"),           // 332
-    FILE_PATH_LITERAL(".gif"),           // 333
-    FILE_PATH_LITERAL(".txt"),           // 334
-    FILE_PATH_LITERAL(".package"),       // 335
-    FILE_PATH_LITERAL(".tif"),           // 336
-    FILE_PATH_LITERAL(".rtf"),           // 337
-    FILE_PATH_LITERAL(".webp"),          // 338
-    FILE_PATH_LITERAL(".mkv"),           // 339
-    FILE_PATH_LITERAL(".wav"),           // 340
-    FILE_PATH_LITERAL(".mov"),           // 341
-    FILE_PATH_LITERAL(".dot"),           // 342
-    FILE_PATH_LITERAL(".dotx"),          // 343
-    FILE_PATH_LITERAL(".xlsb"),          // 344
-    FILE_PATH_LITERAL(".xlt"),           // 345
-    FILE_PATH_LITERAL(".xlm"),           // 346
-    FILE_PATH_LITERAL(".xldm"),          // 347
-    FILE_PATH_LITERAL(".xla"),           // 348
-    FILE_PATH_LITERAL(".xlam"),          // 349
-    FILE_PATH_LITERAL(".xll"),           // 350
-    FILE_PATH_LITERAL(".xlw"),           // 351
-    FILE_PATH_LITERAL(".pot"),           // 352
-    FILE_PATH_LITERAL(".potm"),          // 353
-    FILE_PATH_LITERAL(".ppsm"),          // 354
-    FILE_PATH_LITERAL(".pps"),           // 355
-    FILE_PATH_LITERAL(".mobileconfig"),  // 356
+    FILE_PATH_LITERAL(".pyo"),              // 319
+    FILE_PATH_LITERAL(".desktop"),          // 320
+    FILE_PATH_LITERAL(".cpi"),              // 321
+    FILE_PATH_LITERAL(".jpg"),              // 322
+    FILE_PATH_LITERAL(".jpeg"),             // 323
+    FILE_PATH_LITERAL(".mp3"),              // 324
+    FILE_PATH_LITERAL(".mp4"),              // 325
+    FILE_PATH_LITERAL(".png"),              // 326
+    FILE_PATH_LITERAL(".xls"),              // 327
+    FILE_PATH_LITERAL(".doc"),              // 328
+    FILE_PATH_LITERAL(".pptx"),             // 329
+    FILE_PATH_LITERAL(".csv"),              // 330
+    FILE_PATH_LITERAL(".ica"),              // 331
+    FILE_PATH_LITERAL(".ppt"),              // 332
+    FILE_PATH_LITERAL(".gif"),              // 333
+    FILE_PATH_LITERAL(".txt"),              // 334
+    FILE_PATH_LITERAL(".package"),          // 335
+    FILE_PATH_LITERAL(".tif"),              // 336
+    FILE_PATH_LITERAL(".rtf"),              // 337
+    FILE_PATH_LITERAL(".webp"),             // 338
+    FILE_PATH_LITERAL(".mkv"),              // 339
+    FILE_PATH_LITERAL(".wav"),              // 340
+    FILE_PATH_LITERAL(".mov"),              // 341
+    FILE_PATH_LITERAL(".dot"),              // 342
+    FILE_PATH_LITERAL(".dotx"),             // 343
+    FILE_PATH_LITERAL(".xlsb"),             // 344
+    FILE_PATH_LITERAL(".xlt"),              // 345
+    FILE_PATH_LITERAL(".xlm"),              // 346
+    FILE_PATH_LITERAL(".xldm"),             // 347
+    FILE_PATH_LITERAL(".xla"),              // 348
+    FILE_PATH_LITERAL(".xlam"),             // 349
+    FILE_PATH_LITERAL(".xll"),              // 350
+    FILE_PATH_LITERAL(".xlw"),              // 351
+    FILE_PATH_LITERAL(".pot"),              // 352
+    FILE_PATH_LITERAL(".potm"),             // 353
+    FILE_PATH_LITERAL(".ppsm"),             // 354
+    FILE_PATH_LITERAL(".pps"),              // 355
+    FILE_PATH_LITERAL(".mobileconfig"),     // 356
+    FILE_PATH_LITERAL(".dylib"),            // 357
+    FILE_PATH_LITERAL(".service"),          // 358
+    FILE_PATH_LITERAL(".definition"),       // 359
+    FILE_PATH_LITERAL(".wflow"),            // 360
+    FILE_PATH_LITERAL(".caction"),          // 361
+    FILE_PATH_LITERAL(".configprofile"),    // 362
+    FILE_PATH_LITERAL(".internetconnect"),  // 363
+    FILE_PATH_LITERAL(".networkconnect"),   // 364
     // NOTE! When you add a type here, please add the UMA value as a comment.
     // These must all match DownloadItem.DangerousFileType in
     // enums.xml. From 263 onward, they should also match
diff --git a/components/exo/data_offer_unittest.cc b/components/exo/data_offer_unittest.cc
index 465dd05f..9f8232e 100644
--- a/components/exo/data_offer_unittest.cc
+++ b/components/exo/data_offer_unittest.cc
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/containers/flat_set.h"
+#include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
@@ -93,13 +94,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestFileHelper);
 };
 
-void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
-  int raw_pipe[2];
-  PCHECK(0 == pipe(raw_pipe));
-  read_pipe->reset(raw_pipe[0]);
-  write_pipe->reset(raw_pipe[1]);
-}
-
 bool ReadString(base::ScopedFD fd, std::string* out) {
   std::array<char, 128> buffer;
   char* it = buffer.begin();
@@ -202,7 +196,7 @@
 
   base::ScopedFD read_pipe;
   base::ScopedFD write_pipe;
-  CreatePipe(&read_pipe, &write_pipe);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
 
   data_offer.Receive("text/plain", std::move(write_pipe));
   base::string16 result;
@@ -221,7 +215,7 @@
 
   base::ScopedFD read_pipe;
   base::ScopedFD write_pipe;
-  CreatePipe(&read_pipe, &write_pipe);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
 
   data_offer.Receive("text/uri-list", std::move(write_pipe));
   base::string16 result;
@@ -253,7 +247,7 @@
 
   base::ScopedFD read_pipe;
   base::ScopedFD write_pipe;
-  CreatePipe(&read_pipe, &write_pipe);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
 
   // Receive is called after UrlsCallback runs.
   data_offer.Receive("text/uri-list", std::move(write_pipe));
@@ -283,10 +277,10 @@
 
   base::ScopedFD read_pipe1;
   base::ScopedFD write_pipe1;
-  CreatePipe(&read_pipe1, &write_pipe1);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe1, &write_pipe1));
   base::ScopedFD read_pipe2;
   base::ScopedFD write_pipe2;
-  CreatePipe(&read_pipe2, &write_pipe2);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe2, &write_pipe2));
 
   // Receive is called (twice) before UrlsFromPickleCallback runs.
   data_offer.Receive("text/uri-list", std::move(write_pipe1));
@@ -331,7 +325,7 @@
 
   base::ScopedFD read_pipe;
   base::ScopedFD write_pipe;
-  CreatePipe(&read_pipe, &write_pipe);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
 
   // Receive is called before UrlsCallback runs.
   data_offer.Receive("text/uri-list", std::move(write_pipe));
@@ -364,7 +358,7 @@
 
   base::ScopedFD read_pipe;
   base::ScopedFD write_pipe;
-  CreatePipe(&read_pipe, &write_pipe);
+  ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
 
   data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
   std::string result;
diff --git a/components/exo/data_source.cc b/components/exo/data_source.cc
index 5b5b372..fcea24a 100644
--- a/components/exo/data_source.cc
+++ b/components/exo/data_source.cc
@@ -5,6 +5,7 @@
 #include "components/exo/data_source.h"
 
 #include "base/bind.h"
+#include "base/files/file_util.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/task/post_task.h"
 #include "components/exo/data_source_delegate.h"
@@ -33,13 +34,6 @@
     }
   }
 }
-
-void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
-  int raw_pipe[2];
-  PCHECK(0 == pipe(raw_pipe));
-  read_pipe->reset(raw_pipe[0]);
-  write_pipe->reset(raw_pipe[1]);
-}
 }  // namespace
 
 ScopedDataSource::ScopedDataSource(DataSource* data_source,
@@ -93,7 +87,7 @@
 
   base::ScopedFD read_fd;
   base::ScopedFD write_fd;
-  CreatePipe(&read_fd, &write_fd);
+  PCHECK(base::CreatePipe(&read_fd, &write_fd));
   delegate_->OnSend(kTextMimeTypeUtf8, std::move(write_fd));
 
   base::PostTaskWithTraitsAndReplyWithResult(
diff --git a/components/exo/display.cc b/components/exo/display.cc
index d8065f4..46aa290 100644
--- a/components/exo/display.cc
+++ b/components/exo/display.cc
@@ -26,6 +26,7 @@
 #if defined(USE_OZONE)
 #include <GLES2/gl2extchromium.h>
 #include "components/exo/buffer.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
@@ -119,7 +120,10 @@
   bool is_overlay_candidate = format != gfx::BufferFormat::YUV_420_BIPLANAR;
 
   return std::make_unique<Buffer>(
-      std::move(gpu_memory_buffer), GL_TEXTURE_EXTERNAL_OES,
+      std::move(gpu_memory_buffer),
+      gpu::NativeBufferNeedsPlatformSpecificTextureTarget(format)
+          ? gpu::GetPlatformSpecificTextureTarget()
+          : GL_TEXTURE_2D,
       // COMMANDS_COMPLETED queries are required by native pixmaps.
       GL_COMMANDS_COMPLETED_CHROMIUM, use_zero_copy, is_overlay_candidate,
       y_invert);
diff --git a/components/exo/wayland/wayland_keyboard_delegate.cc b/components/exo/wayland/wayland_keyboard_delegate.cc
index f0a65de..80f82ca3 100644
--- a/components/exo/wayland/wayland_keyboard_delegate.cc
+++ b/components/exo/wayland/wayland_keyboard_delegate.cc
@@ -85,6 +85,11 @@
 }
 
 void WaylandKeyboardDelegate::OnKeyboardModifiers(int modifier_flags) {
+  // CrOS treats numlock as always on, but its event flags actually have that
+  // key disabled, (i.e. chromeos apps specially handle numpad key events as
+  // though numlock is on). In order to get the same result from the linux apps,
+  // we need to ensure they always treat numlock as on.
+  modifier_flags |= ui::EF_NUM_LOCK_ON;
   xkb_state_update_mask(xkb_state_.get(),
                         ModifierFlagsToXkbModifiers(modifier_flags), 0, 0, 0, 0,
                         0);
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index fbb4f3c..0ed681b 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -149,7 +149,7 @@
     SURVEY_INFOBAR_ANDROID = 78,
     NEAR_OOM_INFOBAR_ANDROID = 79,
     INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE = 80,
-    PAGE_LOAD_CAPPING_INFOBAR_DELEGATE = 81,
+    // Removed: PAGE_LOAD_CAPPING_INFOBAR_DELEGATE = 81,
     DOWNLOAD_PROGRESS_INFOBAR_ANDROID = 82,
     AR_CORE_UPGRADE_ANDROID = 83,
     BLOATED_RENDERER_INFOBAR_DELEGATE = 84,
diff --git a/components/leveldb_proto/OWNERS b/components/leveldb_proto/OWNERS
index a120a02..3bf6060c 100644
--- a/components/leveldb_proto/OWNERS
+++ b/components/leveldb_proto/OWNERS
@@ -1,4 +1,3 @@
-mathp@chromium.org
 nyquist@chromium.org
 ssid@chromium.org
 
diff --git a/components/omnibox/browser/clipboard_provider.cc b/components/omnibox/browser/clipboard_provider.cc
index d6a6c79..6811d7f 100644
--- a/components/omnibox/browser/clipboard_provider.cc
+++ b/components/omnibox/browser/clipboard_provider.cc
@@ -286,12 +286,6 @@
       base::string16::npos, 0, match.description.length(),
       ACMatchClassification::NONE, &match.description_class);
 
-  match.contents.assign(l10n_util::GetStringFUTF16(IDS_SEARCH_WEB_FOR_IMAGE,
-                                                   default_url->short_name()));
-  AutocompleteMatch::ClassifyLocationInString(
-      base::string16::npos, 0, match.contents.length(),
-      ACMatchClassification::NONE, &match.contents_class);
-
   TemplateURLRef::SearchTermsArgs search_args(base::ASCIIToUTF16(""));
   search_args.image_thumbnail_content.assign(image_bytes->front_as<char>(),
                                              image_bytes->size());
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp
index 6dd42d6..c4849674 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -32,9 +32,6 @@
   <message name="IDS_COPIED_TEXT_FROM_CLIPBOARD" desc="The actual text the user copied, surrounded by quotation marks.">
     &quot;<ph name="TEXT">$1<ex>search string</ex></ph>&quot;
   </message>
-  <message name="IDS_SEARCH_WEB_FOR_IMAGE" desc="Description for performing a search by image">
-    Search <ph name="SEARCH_ENGINE">$1<ex>Google</ex></ph> for Image
-  </message>
   <message name="IDS_SECURE_CONNECTION_EV" desc="Short text shown in the location bar when the connection is secure with an EV cert.">
     <ph name="ORGANIZATION">$1<ex>Paypal Inc.</ex></ph> [<ph name="COUNTRY">$2<ex>US</ex></ph>]
   </message>
diff --git a/components/password_manager/content/DEPS b/components/password_manager/content/DEPS
index f96967fa..74b17812 100644
--- a/components/password_manager/content/DEPS
+++ b/components/password_manager/content/DEPS
@@ -3,7 +3,7 @@
   "+content/public/common",
   "+mojo/public",
   # Allow inclusion of WebKit API files.
-  "+third_party/blink/public/platform",
+  "+third_party/blink/public/mojom/credentialmanager",
   "+third_party/blink/public/web",
 ]
 
diff --git a/components/password_manager/content/browser/content_credential_manager.h b/components/password_manager/content/browser/content_credential_manager.h
index 1c04868..1368b0c 100644
--- a/components/password_manager/content/browser/content_credential_manager.h
+++ b/components/password_manager/content/browser/content_credential_manager.h
@@ -8,7 +8,7 @@
 #include "components/password_manager/core/browser/credential_manager_impl.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.h"
 
 class GURL;
 
diff --git a/components/password_manager/content/common/credential_manager.typemap b/components/password_manager/content/common/credential_manager.typemap
index 8c87109..d0d170a 100644
--- a/components/password_manager/content/common/credential_manager.typemap
+++ b/components/password_manager/content/common/credential_manager.typemap
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-mojom = "//third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom"
+mojom = "//third_party/blink/public/mojom/credentialmanager/credential_manager.mojom"
 public_headers =
     [ "//components/password_manager/core/common/credential_manager_types.h" ]
 traits_headers = [ "//components/password_manager/content/common/credential_manager_mojom_traits.h" ]
diff --git a/components/password_manager/content/common/credential_manager_mojom_traits.h b/components/password_manager/content/common/credential_manager_mojom_traits.h
index d7b82804..90576469 100644
--- a/components/password_manager/content/common/credential_manager_mojom_traits.h
+++ b/components/password_manager/content/common/credential_manager_mojom_traits.h
@@ -9,7 +9,7 @@
 #include "base/strings/string16.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.h"
 
 namespace mojo {
 
diff --git a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
index 0a61502..01885d7a 100644
--- a/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
+++ b/components/services/heap_profiling/public/cpp/sampling_profiler_wrapper.cc
@@ -340,9 +340,6 @@
 
 void SerializeFramesFromAllocationContext(FrameSerializer* serializer,
                                           const char** context) {
-  // Allocation context is tracked in TLS. Return nothing if TLS was destroyed.
-  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
-    return;
   auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread();
   if (!tracker)
     return;
@@ -370,10 +367,6 @@
     serializer->AddCString(thread_name);
   }
 
-  // Task context requires access to TLS.
-  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
-    return;
-
   if (!*context) {
     const auto* tracker =
         AllocationContextTracker::GetInstanceForCurrentThread();
@@ -421,6 +414,11 @@
     size_t total,
     base::PoissonAllocationSampler::AllocatorType type,
     const char* context) {
+  // CaptureStack (on Android) and AllocationContext (all OSes) may use TLS.
+  // Bail out if it has been destroyed.
+  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
+    return;
+
   // The PoissonAllocationSampler that invokes this method guarantees
   // non-reentrancy, i.e. no allocations made within the scope of SampleAdded
   // will produce a sample.
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 3f4b2061..f6a1ff6 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -1170,8 +1170,13 @@
       base::OnceCallback<void(bool success)> callback = base::Bind(
           &GaiaCookieManagerService::OnCookieSet,
           weak_ptr_factory_.GetWeakPtr(), cookie.Name(), cookie.Domain());
+      net::CookieOptions options;
+      options.set_include_httponly();
+      // Permit it to set a SameSite cookie if it wants to.
+      options.set_same_site_cookie_context(
+          net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
       cookie_manager->SetCanonicalCookie(
-          cookie, "https", true,
+          cookie, "https", options,
           mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback),
                                                       false));
     } else {
diff --git a/components/ui_devtools/devtools_server.cc b/components/ui_devtools/devtools_server.cc
index a4a1c40..2d885ce2 100644
--- a/components/ui_devtools/devtools_server.cc
+++ b/components/ui_devtools/devtools_server.cc
@@ -214,8 +214,7 @@
   server_->AcceptWebSocket(connection_id, info, tag_);
 }
 
-void UiDevToolsServer::OnWebSocketMessage(int connection_id,
-                                          const std::string& data) {
+void UiDevToolsServer::OnWebSocketMessage(int connection_id, std::string data) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
   auto it = connections_.find(connection_id);
   DCHECK(it != connections_.end());
diff --git a/components/ui_devtools/devtools_server.h b/components/ui_devtools/devtools_server.h
index 12877d1..60ff011 100644
--- a/components/ui_devtools/devtools_server.h
+++ b/components/ui_devtools/devtools_server.h
@@ -81,7 +81,7 @@
   void OnWebSocketRequest(
       int connection_id,
       const network::server::HttpServerRequestInfo& info) override;
-  void OnWebSocketMessage(int connection_id, const std::string& data) override;
+  void OnWebSocketMessage(int connection_id, std::string data) override;
   void OnClose(int connection_id) override;
 
   using ClientsList = std::vector<std::unique_ptr<UiDevToolsClient>>;
diff --git a/components/ui_devtools/ui_element.h b/components/ui_devtools/ui_element.h
index 6fbdd8ae..fb3737d5 100644
--- a/components/ui_devtools/ui_element.h
+++ b/components/ui_devtools/ui_element.h
@@ -29,6 +29,8 @@
 
 class UI_DEVTOOLS_EXPORT UIElement {
  public:
+  using UIElements = std::vector<UIElement*>;
+
   virtual ~UIElement();
   int node_id() const { return node_id_; }
   std::string GetTypeName() const;
@@ -36,20 +38,20 @@
   void set_parent(UIElement* parent) { parent_ = parent; }
   UIElementDelegate* delegate() const { return delegate_; }
   UIElementType type() const { return type_; }
-  const std::vector<UIElement*>& children() const { return children_; }
+  const UIElements& children() const { return children_; }
   bool is_updating() const { return is_updating_; }
   void set_is_updating(bool is_updating) { is_updating_ = is_updating; }
   void set_owns_children(bool owns_children) { owns_children_ = owns_children; }
 
   using ElementCompare = bool (*)(const UIElement*, const UIElement*);
 
-  // |child| is inserted in front of |before|. If |before| is null, it
-  // is inserted at the end. Parent takes ownership of the added child.
+  // Inserts |child| in front of |before|. If |before| is null, it is inserted
+  // at the end. Parent takes ownership of the added child.
   void AddChild(UIElement* child, UIElement* before = nullptr);
 
-  // |child| is inserted according to a custom ordering function.
-  // |notify_delegate| calls OnUIElementAdded, which creates the subtree of
-  // UIElements at |child|, and the corresponding DOM nodes.
+  // Inserts |child| according to a custom ordering function. |notify_delegate|
+  // calls OnUIElementAdded(), which creates the subtree of UIElements at
+  // |child|, and the corresponding DOM nodes.
   void AddOrderedChild(UIElement* child,
                        ElementCompare compare,
                        bool notify_delegate = true);
@@ -58,9 +60,9 @@
   // children.
   void ClearChildren();
 
-  // Remove |child| out of vector |children_| but |child| is not destroyed.
-  // The caller is responsible for destroying |child|. |notify_delegate| calls
-  // OnUIElementRemoved, which destroys the DOM node for |child|.
+  // Removes |child| out of |children_| without destroying |child|. The caller
+  // is responsible for destroying |child|. |notify_delegate| calls
+  // OnUIElementRemoved(), which destroys the DOM node for |child|.
   void RemoveChild(UIElement* child, bool notify_delegate = true);
 
   // Move |child| to position new_index in |children_|.
@@ -69,19 +71,21 @@
   template <class T>
   int FindUIElementIdForBackendElement(T* element) const;
 
-  // Return a vector of pairs of properties' names and values.
+  // Returns properties' names and values.
   virtual std::vector<std::pair<std::string, std::string>> GetCustomProperties()
       const = 0;
+
   virtual void GetBounds(gfx::Rect* bounds) const = 0;
   virtual void SetBounds(const gfx::Rect& bounds) = 0;
   virtual void GetVisible(bool* visible) const = 0;
   virtual void SetVisible(bool visible) = 0;
 
-  // If element exists, return its associated native window and its screen
-  // bounds. Otherwise, return null and empty bounds.
+  // If element exists, returns its associated native window and its screen
+  // bounds. Otherwise, returns null and empty bounds.
   virtual std::pair<gfx::NativeWindow, gfx::Rect> GetNodeWindowAndScreenBounds()
       const = 0;
-  // Get a list of interleaved keys and values of attributes to be displayed
+
+  // Returns a list of interleaved keys and values of attributes to be displayed
   // on the element in the dev tools hierarchy view.
   virtual std::unique_ptr<protocol::Array<std::string>> GetAttributes()
       const = 0;
@@ -99,7 +103,7 @@
  private:
   const int node_id_;
   const UIElementType type_;
-  std::vector<UIElement*> children_;
+  UIElements children_;
   UIElement* parent_;
   UIElementDelegate* delegate_;
   bool is_updating_ = false;
diff --git a/components/viz/service/display_embedder/viz_process_context_provider.cc b/components/viz/service/display_embedder/viz_process_context_provider.cc
index 5ffab3f..36b2c4d 100644
--- a/components/viz/service/display_embedder/viz_process_context_provider.cc
+++ b/components/viz/service/display_embedder/viz_process_context_provider.cc
@@ -239,8 +239,9 @@
     const gpu::SharedMemoryLimits& mem_limits) {
   const bool is_offscreen = surface_handle == gpu::kNullSurfaceHandle;
 
-  command_buffer_ =
-      std::make_unique<gpu::InProcessCommandBuffer>(task_executor);
+  command_buffer_ = std::make_unique<gpu::InProcessCommandBuffer>(
+      task_executor,
+      GURL("chrome://gpu/VizProcessContextProvider::InitializeContext"));
   context_result_ = command_buffer_->Initialize(
       /*surface=*/nullptr, is_offscreen, surface_handle, attributes_,
       /*share_command_buffer=*/nullptr, gpu_memory_buffer_manager,
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 2c29bf9..a6a3065 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -16,7 +16,6 @@
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "components/crash/core/common/crash_key.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
 #include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
@@ -631,14 +630,6 @@
 }
 #endif
 
-void GpuServiceImpl::SetActiveURL(const GURL& url) {
-  DCHECK(main_runner_->BelongsToCurrentThread());
-  // Note that the url is intentionally excluded from webview crash dumps
-  // using a whitelist for privacy reasons. See kWebViewCrashKeyWhiteList.
-  static crash_reporter::CrashKeyString<1024> crash_key("url-chunk");
-  crash_key.Set(url.possibly_invalid_spec());
-}
-
 void GpuServiceImpl::EstablishGpuChannel(int32_t client_id,
                                          uint64_t client_tracing_id,
                                          bool is_gpu_host,
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index fdee651..2d6d056 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -251,7 +251,6 @@
   void SendCreatedChildWindow(gpu::SurfaceHandle parent_window,
                               gpu::SurfaceHandle child_window) override;
 #endif
-  void SetActiveURL(const GURL& url) override;
 
 #if defined(OS_CHROMEOS)
   void CreateArcVideoDecodeAcceleratorOnMainThread(
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 7c3df634..4994ea7 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -480,8 +480,6 @@
     "background_fetch/storage/start_next_pending_request_task.h",
     "background_sync/background_sync_context_impl.cc",
     "background_sync/background_sync_context_impl.h",
-    "background_sync/background_sync_launcher.cc",
-    "background_sync/background_sync_launcher.h",
     "background_sync/background_sync_manager.cc",
     "background_sync/background_sync_manager.h",
     "background_sync/background_sync_metrics.cc",
diff --git a/content/browser/background_sync/background_sync_browsertest.cc b/content/browser/background_sync/background_sync_browsertest.cc
index 09fe3964..bf5afe7 100644
--- a/content/browser/background_sync/background_sync_browsertest.cc
+++ b/content/browser/background_sync/background_sync_browsertest.cc
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
@@ -158,16 +157,9 @@
 
   WebContents* web_contents() { return shell_->web_contents(); }
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // TODO(jkarlin): Remove this once background sync is no longer
-    // experimental.
-    command_line->AppendSwitch(
-        switches::kEnableExperimentalWebPlatformFeatures);
-  }
-
   void SetUpOnMainThread() override {
-    https_server_.reset(
-        new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
+    https_server_ = std::make_unique<net::EmbeddedTestServer>(
+        net::EmbeddedTestServer::TYPE_HTTPS);
     https_server_->ServeFilesFromSourceDirectory("content/test/data");
     ASSERT_TRUE(https_server_->Start());
 
diff --git a/content/browser/background_sync/background_sync_context_impl.cc b/content/browser/background_sync/background_sync_context_impl.cc
index 8e25cf7..e2e9b9ce 100644
--- a/content/browser/background_sync/background_sync_context_impl.cc
+++ b/content/browser/background_sync/background_sync_context_impl.cc
@@ -9,8 +9,6 @@
 #include "base/bind.h"
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
-#include "base/task/task_traits.h"
-#include "content/browser/background_sync/background_sync_launcher.h"
 #include "content/browser/background_sync/background_sync_manager.h"
 #include "content/browser/background_sync/background_sync_service_impl.h"
 #include "content/browser/devtools/devtools_background_services_context.h"
@@ -33,27 +31,6 @@
   DCHECK(services_.empty());
 }
 
-// static
-#if defined(OS_ANDROID)
-void BackgroundSyncContext::FireBackgroundSyncEventsAcrossPartitions(
-    BrowserContext* browser_context,
-    const base::android::JavaParamRef<jobject>& j_runnable) {
-  DCHECK(browser_context);
-  BackgroundSyncLauncher::FireBackgroundSyncEvents(browser_context, j_runnable);
-}
-#endif
-
-// static
-void BackgroundSyncContext::GetSoonestWakeupDeltaAcrossPartitions(
-    BrowserContext* browser_context,
-    base::OnceCallback<void(base::TimeDelta)> callback) {
-  DCHECK(browser_context);
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  BackgroundSyncLauncher::GetSoonestWakeupDelta(browser_context,
-                                                std::move(callback));
-}
-
 void BackgroundSyncContextImpl::Init(
     const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context,
     const scoped_refptr<DevToolsBackgroundServicesContext>& devtools_context) {
@@ -103,44 +80,10 @@
   background_sync_manager_ = std::move(manager);
 }
 
-void BackgroundSyncContextImpl::set_wakeup_delta_for_testing(
-    base::TimeDelta wakeup_delta) {
-  test_wakeup_delta_ = wakeup_delta;
-}
-
-void BackgroundSyncContextImpl::GetSoonestWakeupDelta(
-    base::OnceCallback<void(base::TimeDelta)> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  base::PostTaskWithTraitsAndReplyWithResult(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(
-          &BackgroundSyncContextImpl::GetSoonestWakeupDeltaOnIOThread, this),
-      base::BindOnce(&BackgroundSyncContextImpl::DidGetSoonestWakeupDelta, this,
-                     std::move(callback)));
-}
-
-base::TimeDelta BackgroundSyncContextImpl::GetSoonestWakeupDeltaOnIOThread() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (!test_wakeup_delta_.is_max())
-    return test_wakeup_delta_;
-  if (!background_sync_manager_)
-    return base::TimeDelta::Max();
-
-  return background_sync_manager_->GetSoonestWakeupDelta();
-}
-
-void BackgroundSyncContextImpl::DidGetSoonestWakeupDelta(
-    base::OnceCallback<void(base::TimeDelta)> callback,
-    base::TimeDelta soonest_wakeup_delta) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  std::move(callback).Run(soonest_wakeup_delta);
-}
-
-void BackgroundSyncContextImpl::FireBackgroundSyncEvents(
+void BackgroundSyncContextImpl::FireBackgroundSyncEventsForStoragePartition(
+    content::StoragePartition* storage_partition,
     base::OnceClosure done_closure) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!background_sync_manager_) {
     std::move(done_closure).Run();
     return;
diff --git a/content/browser/background_sync/background_sync_context_impl.h b/content/browser/background_sync/background_sync_context_impl.h
index 10313fb..9365f80 100644
--- a/content/browser/background_sync/background_sync_context_impl.h
+++ b/content/browser/background_sync/background_sync_context_impl.h
@@ -11,8 +11,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/background_sync_context.h"
 #include "third_party/blink/public/mojom/background_sync/background_sync.mojom.h"
@@ -56,9 +54,9 @@
   BackgroundSyncManager* background_sync_manager() const;
 
   // BackgroundSyncContext implementation.
-  void FireBackgroundSyncEvents(base::OnceClosure done_closure) override;
-  void GetSoonestWakeupDelta(
-      base::OnceCallback<void(base::TimeDelta)> callback) override;
+  void FireBackgroundSyncEventsForStoragePartition(
+      content::StoragePartition* storage_partition,
+      base::OnceClosure done_closure) override;
 
  protected:
   friend class base::RefCountedDeleteOnSequence<BackgroundSyncContextImpl>;
@@ -67,11 +65,9 @@
 
   void set_background_sync_manager_for_testing(
       std::unique_ptr<BackgroundSyncManager> manager);
-  void set_wakeup_delta_for_testing(base::TimeDelta wakeup_delta);
 
  private:
   friend class BackgroundSyncServiceImplTest;
-  friend class BackgroundSyncLauncherTest;
 
   virtual void CreateBackgroundSyncManager(
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
@@ -82,11 +78,6 @@
 
   void ShutdownOnIO();
 
-  base::TimeDelta GetSoonestWakeupDeltaOnIOThread();
-  void DidGetSoonestWakeupDelta(
-      base::OnceCallback<void(base::TimeDelta)> callback,
-      base::TimeDelta soonest_wakeup_delta);
-
   // Only accessed on the IO thread.
   std::unique_ptr<BackgroundSyncManager> background_sync_manager_;
 
@@ -96,7 +87,6 @@
   std::map<BackgroundSyncServiceImpl*,
            std::unique_ptr<BackgroundSyncServiceImpl>>
       services_;
-  base::TimeDelta test_wakeup_delta_ = base::TimeDelta::Max();
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundSyncContextImpl);
 };
diff --git a/content/browser/background_sync/background_sync_launcher.cc b/content/browser/background_sync/background_sync_launcher.cc
deleted file mode 100644
index a6dd4b9..0000000
--- a/content/browser/background_sync/background_sync_launcher.cc
+++ /dev/null
@@ -1,145 +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.
-
-#include "content/browser/background_sync/background_sync_launcher.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/barrier_closure.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "content/public/browser/background_sync_context.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#if defined(OS_ANDROID)
-#include "base/android/callback_android.h"
-#endif
-
-namespace content {
-
-namespace {
-
-base::LazyInstance<BackgroundSyncLauncher>::DestructorAtExit
-    g_background_sync_launcher = LAZY_INSTANCE_INITIALIZER;
-
-unsigned int GetStoragePartitionCount(BrowserContext* browser_context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(browser_context);
-
-  int num_partitions = 0;
-  BrowserContext::ForEachStoragePartition(
-      browser_context,
-      base::BindRepeating(
-          [](int* num_partitions, StoragePartition* storage_partition) {
-            (*num_partitions)++;
-          },
-          &num_partitions));
-
-  // It's valid for a profile to not have any storage partitions. This DCHECK
-  // is to ensure that we're not waking up Chrome for no reason, because that's
-  // expensive and unnecessary.
-  DCHECK(num_partitions);
-
-  return num_partitions;
-}
-
-}  // namespace
-
-// static
-BackgroundSyncLauncher* BackgroundSyncLauncher::Get() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  return g_background_sync_launcher.Pointer();
-}
-
-// static
-void BackgroundSyncLauncher::GetSoonestWakeupDelta(
-    BrowserContext* browser_context,
-    base::OnceCallback<void(base::TimeDelta)> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  Get()->GetSoonestWakeupDeltaImpl(browser_context, std::move(callback));
-}
-
-// static
-#if defined(OS_ANDROID)
-void BackgroundSyncLauncher::FireBackgroundSyncEvents(
-    BrowserContext* browser_context,
-    const base::android::JavaParamRef<jobject>& j_runnable) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(browser_context);
-
-  base::RepeatingClosure done_closure = base::BarrierClosure(
-      GetStoragePartitionCount(browser_context),
-      base::BindOnce(base::android::RunRunnableAndroid,
-                     base::android::ScopedJavaGlobalRef<jobject>(j_runnable)));
-
-  BrowserContext::ForEachStoragePartition(
-      browser_context,
-      base::BindRepeating(
-          [](base::OnceClosure done_closure,
-             StoragePartition* storage_partition) {
-            BackgroundSyncContext* sync_context =
-                storage_partition->GetBackgroundSyncContext();
-            DCHECK(sync_context);
-            sync_context->FireBackgroundSyncEvents(std::move(done_closure));
-          },
-          std::move(done_closure)));
-}
-#endif
-
-BackgroundSyncLauncher::BackgroundSyncLauncher() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-BackgroundSyncLauncher::~BackgroundSyncLauncher() = default;
-
-void BackgroundSyncLauncher::GetSoonestWakeupDeltaImpl(
-    BrowserContext* browser_context,
-    base::OnceCallback<void(base::TimeDelta)> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  base::RepeatingClosure done_closure = base::BarrierClosure(
-      GetStoragePartitionCount(browser_context),
-      base::BindOnce(&BackgroundSyncLauncher::SendSoonestWakeupDelta,
-                     base::Unretained(this), std::move(callback)));
-
-  soonest_wakeup_delta_ = base::TimeDelta::Max();
-  BrowserContext::ForEachStoragePartition(
-      browser_context,
-      base::BindRepeating(
-          &BackgroundSyncLauncher::GetSoonestWakeupDeltaForStoragePartition,
-          base::Unretained(this), std::move(done_closure)));
-}
-
-void BackgroundSyncLauncher::GetSoonestWakeupDeltaForStoragePartition(
-    base::OnceClosure done_closure,
-    StoragePartition* storage_partition) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  BackgroundSyncContext* sync_context =
-      storage_partition->GetBackgroundSyncContext();
-  DCHECK(sync_context);
-
-  sync_context->GetSoonestWakeupDelta(base::BindOnce(
-      [](base::OnceClosure done_closure, base::TimeDelta* soonest_wakeup_delta,
-         base::TimeDelta wakeup_delta) {
-        DCHECK_CURRENTLY_ON(BrowserThread::UI);
-        *soonest_wakeup_delta = std::min(*soonest_wakeup_delta, wakeup_delta);
-        std::move(done_closure).Run();
-      },
-      std::move(done_closure), &soonest_wakeup_delta_));
-}
-
-void BackgroundSyncLauncher::SendSoonestWakeupDelta(
-    base::OnceCallback<void(base::TimeDelta)> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::move(callback).Run(soonest_wakeup_delta_);
-}
-
-}  // namespace content
\ No newline at end of file
diff --git a/content/browser/background_sync/background_sync_launcher.h b/content/browser/background_sync/background_sync_launcher.h
deleted file mode 100644
index 97d1a86..0000000
--- a/content/browser/background_sync/background_sync_launcher.h
+++ /dev/null
@@ -1,59 +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.
-
-#ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_LAUNCHER_H_
-#define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_LAUNCHER_H_
-
-#include "base/callback_forward.h"
-#include "base/lazy_instance.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "content/common/content_export.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "base/android/scoped_java_ref.h"
-#endif
-
-namespace content {
-
-class BrowserContext;
-class StoragePartition;
-
-class CONTENT_EXPORT BackgroundSyncLauncher {
- public:
-  static BackgroundSyncLauncher* Get();
-  static void GetSoonestWakeupDelta(
-      BrowserContext* browser_context,
-      base::OnceCallback<void(base::TimeDelta)> callback);
-#if defined(OS_ANDROID)
-  static void FireBackgroundSyncEvents(
-      BrowserContext* browser_context,
-      const base::android::JavaParamRef<jobject>& j_runnable);
-#endif
-
- private:
-  friend struct base::LazyInstanceTraitsBase<BackgroundSyncLauncher>;
-  friend class BackgroundSyncLauncherTest;
-
-  // Constructor and destructor marked private to enforce singleton.
-  BackgroundSyncLauncher();
-  ~BackgroundSyncLauncher();
-
-  void GetSoonestWakeupDeltaImpl(
-      BrowserContext* browser_context,
-      base::OnceCallback<void(base::TimeDelta)> callback);
-  void GetSoonestWakeupDeltaForStoragePartition(
-      base::OnceClosure done_closure,
-      StoragePartition* storage_partition);
-  void SendSoonestWakeupDelta(
-      base::OnceCallback<void(base::TimeDelta)> callback);
-
-  base::TimeDelta soonest_wakeup_delta_ = base::TimeDelta::Max();
-  DISALLOW_COPY_AND_ASSIGN(BackgroundSyncLauncher);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_LAUNCHER_H_
\ No newline at end of file
diff --git a/content/browser/background_sync/background_sync_launcher_unittest.cc b/content/browser/background_sync/background_sync_launcher_unittest.cc
deleted file mode 100644
index ec3566d..0000000
--- a/content/browser/background_sync/background_sync_launcher_unittest.cc
+++ /dev/null
@@ -1,129 +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.
-
-#include "content/browser/background_sync/background_sync_launcher.h"
-
-#include <map>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/test/bind_test_util.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/time/time.h"
-#include "content/browser/storage_partition_impl.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/background_sync_context.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/common/content_client.h"
-#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace content {
-
-namespace {
-
-const char kUrl_1[] = "https://example.com";
-const char kUrl_2[] = "https://whereswaldo.com";
-
-class TestBrowserClient : public ContentBrowserClient {
- public:
-  TestBrowserClient() = default;
-  ~TestBrowserClient() override = default;
-
-  void GetStoragePartitionConfigForSite(BrowserContext* browser_context,
-                                        const GURL& site,
-                                        bool can_be_default,
-                                        std::string* partition_domain,
-                                        std::string* partition_name,
-                                        bool* in_memory) override {
-    DCHECK(browser_context);
-    DCHECK(partition_domain);
-    DCHECK(partition_name);
-
-    auto partition_num = std::to_string(++partition_count_);
-    *partition_domain = std::string("PartitionDomain") + partition_num;
-    *partition_name = std::string("Partition") + partition_num;
-    *in_memory = false;
-  }
-
- private:
-  int partition_count_ = 0;
-};
-
-}  // namespace
-
-class BackgroundSyncLauncherTest : public testing::Test {
- public:
-  BackgroundSyncLauncherTest()
-      : browser_thread_bundle_(TestBrowserThreadBundle::MainThreadType::UI) {}
-
-  void SetUpBrowserContext(const std::vector<GURL>& urls,
-                           const std::map<GURL, int>& wakeup_deltas = {}) {
-    DCHECK(!urls.empty());
-
-    for (const auto& url : urls) {
-      auto* storage_partition = BrowserContext::GetStoragePartitionForSite(
-          &test_browser_context_, url);
-
-      auto iter = wakeup_deltas.find(url);
-      if (iter == wakeup_deltas.end())
-        continue;
-
-      static_cast<StoragePartitionImpl*>(storage_partition)
-          ->GetBackgroundSyncContext()
-          ->set_wakeup_delta_for_testing(
-              base::TimeDelta::FromMilliseconds(iter->second));
-    }
-  }
-
-  void SetUp() override {
-    original_client_ = SetBrowserClientForTesting(&browser_client_);
-  }
-
-  void TearDown() override { SetBrowserClientForTesting(original_client_); }
-
-  base::TimeDelta GetSoonestWakeupDelta() {
-    base::TimeDelta to_return;
-    BackgroundSyncLauncher::GetSoonestWakeupDelta(
-        &test_browser_context_,
-        base::BindLambdaForTesting(
-            [&to_return](base::TimeDelta soonest_wakeup_delta) {
-              to_return = soonest_wakeup_delta;
-            }));
-    browser_thread_bundle_.RunUntilIdle();
-    return to_return;
-  }
-
- protected:
-  TestBrowserThreadBundle browser_thread_bundle_;
-  TestBrowserClient browser_client_;
-  ContentBrowserClient* original_client_;
-  TestBrowserContext test_browser_context_;
-};
-
-// Tests that we pick the correct wake up delta for the one-shot Background
-// Sync wake up task, across all storage partitions.
-TEST_F(BackgroundSyncLauncherTest, CorrectSoonestWakeupDeltaIsPicked) {
-  std::vector<GURL> urls = {GURL(kUrl_1), GURL(kUrl_2)};
-
-  // Add two storage partitions. Verify that we set the soonest wake up delta
-  // to base::TimeDelta::Max(). This will cause cancellation of the wakeup
-  // task.
-  SetUpBrowserContext(urls);
-  EXPECT_TRUE(GetSoonestWakeupDelta().is_max());
-
-  // Add two more storage partitions, this time with wakeup_deltas.
-  // Verify that we pick the smaller of the two.
-  int delta_ms = 0;
-  std::map<GURL, int> wakeup_deltas;
-  for (const auto& url : urls)
-    wakeup_deltas[url] = delta_ms += 1000;
-  SetUpBrowserContext(urls, wakeup_deltas);
-
-  EXPECT_EQ(GetSoonestWakeupDelta().InMilliseconds(), 1000);
-}
-
-}  // namespace content
\ No newline at end of file
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index de713b19..4a2803b 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -122,13 +122,15 @@
 }
 
 void RunInBackgroundOnUIThread(
-    scoped_refptr<ServiceWorkerContextWrapper> sw_context_wrapper) {
+    scoped_refptr<ServiceWorkerContextWrapper> sw_context_wrapper,
+    bool enabled,
+    int64_t min_ms) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   BackgroundSyncController* background_sync_controller =
       GetBackgroundSyncControllerOnUIThread(sw_context_wrapper);
   if (background_sync_controller) {
-    background_sync_controller->RunInBackground();
+    background_sync_controller->RunInBackground(enabled, min_ms);
   }
 }
 
@@ -960,10 +962,10 @@
   return AreOptionConditionsMet();
 }
 
-base::TimeDelta BackgroundSyncManager::GetSoonestWakeupDelta() {
+void BackgroundSyncManager::RunInBackgroundIfNecessary() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
   base::TimeDelta soonest_wakeup_delta = base::TimeDelta::Max();
+
   for (const auto& sw_id_and_registrations : active_registrations_) {
     for (const auto& key_and_registration :
          sw_id_and_registrations.second.registration_map) {
@@ -990,14 +992,6 @@
     soonest_wakeup_delta = parameters_->min_sync_recovery_time;
   }
 
-  return soonest_wakeup_delta;
-}
-
-void BackgroundSyncManager::RunInBackgroundIfNecessary() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  base::TimeDelta soonest_wakeup_delta = GetSoonestWakeupDelta();
-
   // Try firing again after the wakeup delta.
   if (!soonest_wakeup_delta.is_max() && !soonest_wakeup_delta.is_zero()) {
     delayed_sync_task_.Reset(base::Bind(&BackgroundSyncManager::FireReadyEvents,
@@ -1006,11 +1000,14 @@
   }
 
   // In case the browser closes (or to prevent it from closing), call
-  // RunInBackground to wake up the browser at the soonest wakeup delta across
-  // all the storage partitions.
+  // RunInBackground to either wake up the browser at the wakeup delta or to
+  // keep the browser running.
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(RunInBackgroundOnUIThread, service_worker_context_));
+      base::BindOnce(
+          RunInBackgroundOnUIThread, service_worker_context_,
+          !soonest_wakeup_delta.is_max() /* should run in background */,
+          soonest_wakeup_delta.InMilliseconds()));
 }
 
 void BackgroundSyncManager::FireReadyEvents() {
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index 3eba58fd..299b17d 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -124,11 +124,6 @@
   // Once all of this is done, invokes |callback|.
   void FireReadyEventsThenRunCallback(base::OnceClosure callback);
 
-  // Gets the soonest delta after which the browser should be woken up to send
-  // a Background Sync event. If set to max, the browser won't be woken up.
-  // This is virtual so that tests can override it.
-  virtual base::TimeDelta GetSoonestWakeupDelta();
-
  protected:
   BackgroundSyncManager(
       scoped_refptr<ServiceWorkerContextWrapper> context,
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index b6c3d96..902679c4 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -1254,29 +1254,30 @@
   // The BackgroundSyncManager should declare in initialization
   // that it doesn't need to be woken up since it has no registrations.
   EXPECT_LT(0, GetController()->run_in_background_count());
-  EXPECT_FALSE(test_background_sync_manager_->IsBrowserWakeupScheduled());
+  EXPECT_FALSE(GetController()->run_in_background_enabled());
 
   SetNetwork(network::mojom::ConnectionType::CONNECTION_NONE);
-  EXPECT_FALSE(test_background_sync_manager_->IsBrowserWakeupScheduled());
+  EXPECT_FALSE(GetController()->run_in_background_enabled());
 
   // Register a one-shot but it can't fire due to lack of network, wake up is
   // required.
   Register(sync_options_1_);
-  EXPECT_TRUE(test_background_sync_manager_->IsBrowserWakeupScheduled());
+  EXPECT_TRUE(GetController()->run_in_background_enabled());
 
   // Start the event but it will pause mid-sync due to
   // InitDelayedSyncEventTest() above.
   SetNetwork(network::mojom::ConnectionType::CONNECTION_WIFI);
-  EXPECT_TRUE(test_background_sync_manager_->IsBrowserWakeupScheduled());
-  EXPECT_TRUE(test_background_sync_manager_->EqualsSoonestWakeupDelta(
-      test_background_sync_manager_->background_sync_parameters()
-          ->min_sync_recovery_time));
+  EXPECT_TRUE(GetController()->run_in_background_enabled());
+  EXPECT_EQ(test_background_sync_manager_->background_sync_parameters()
+                ->min_sync_recovery_time,
+            base::TimeDelta::FromMilliseconds(
+                GetController()->run_in_background_min_ms()));
 
   // Finish the sync.
   ASSERT_TRUE(sync_fired_callback_);
   std::move(sync_fired_callback_).Run(blink::ServiceWorkerStatusCode::kOk);
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(test_background_sync_manager_->IsBrowserWakeupScheduled());
+  EXPECT_FALSE(GetController()->run_in_background_enabled());
 }
 
 TEST_F(BackgroundSyncManagerTest, OneAttempt) {
diff --git a/content/browser/background_sync/background_sync_service_impl_unittest.cc b/content/browser/background_sync/background_sync_service_impl_unittest.cc
index 958037c..73254d2 100644
--- a/content/browser/background_sync/background_sync_service_impl_unittest.cc
+++ b/content/browser/background_sync/background_sync_service_impl_unittest.cc
@@ -88,8 +88,7 @@
 class BackgroundSyncServiceImplTest : public testing::Test {
  public:
   BackgroundSyncServiceImplTest()
-      : thread_bundle_(
-            new TestBrowserThreadBundle(TestBrowserThreadBundle::IO_MAINLOOP)) {
+      : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {
     default_sync_registration_ = blink::mojom::SyncRegistrationOptions::New();
   }
 
@@ -118,10 +117,10 @@
 
   // SetUp helper methods
   void CreateTestHelper() {
-    embedded_worker_helper_.reset(
-        new EmbeddedWorkerTestHelper(base::FilePath()));
-    std::unique_ptr<MockPermissionManager> mock_permission_manager(
-        new testing::NiceMock<MockPermissionManager>());
+    embedded_worker_helper_ =
+        std::make_unique<EmbeddedWorkerTestHelper>((base::FilePath()));
+    std::unique_ptr<MockPermissionManager> mock_permission_manager =
+        std::make_unique<testing::NiceMock<MockPermissionManager>>();
     ON_CALL(*mock_permission_manager,
             GetPermissionStatus(PermissionType::BACKGROUND_SYNC, _, _))
         .WillByDefault(
@@ -211,7 +210,7 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  std::unique_ptr<TestBrowserThreadBundle> thread_bundle_;
+  TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<EmbeddedWorkerTestHelper> embedded_worker_helper_;
   std::unique_ptr<StoragePartitionImpl> storage_partition_impl_;
   scoped_refptr<BackgroundSyncContextImpl> background_sync_context_;
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index 763f5e8..6cfbe9a9 100644
--- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -223,12 +223,13 @@
     network::mojom::CookieManager* cookie_manager =
         storage_partition()->GetCookieManagerForBrowserProcess();
 
-    std::unique_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
-        url, "A=1", base::Time::Now(), net::CookieOptions()));
+    net::CookieOptions options;
+    std::unique_ptr<net::CanonicalCookie> cookie(
+        net::CanonicalCookie::Create(url, "A=1", base::Time::Now(), options));
 
     base::RunLoop run_loop;
     cookie_manager->SetCanonicalCookie(
-        *cookie, url.scheme(), false /* modify_http_only */,
+        *cookie, url.scheme(), options,
         base::BindOnce(&ClearSiteDataHandlerBrowserTest::AddCookieCallback,
                        run_loop.QuitClosure()));
     run_loop.Run();
diff --git a/content/browser/cookie_store/cookie_store_manager_unittest.cc b/content/browser/cookie_store/cookie_store_manager_unittest.cc
index 24c6725..fdbaf446 100644
--- a/content/browser/cookie_store/cookie_store_manager_unittest.cc
+++ b/content/browser/cookie_store/cookie_store_manager_unittest.cc
@@ -318,8 +318,10 @@
   bool SetCanonicalCookie(const net::CanonicalCookie& cookie) {
     base::RunLoop run_loop;
     bool success = false;
+    net::CookieOptions options;
+    options.set_include_httponly();
     cookie_manager_->SetCanonicalCookie(
-        cookie, "https", /* can_modify_httponly = */ true,
+        cookie, "https", options,
         base::BindOnce(
             [](base::RunLoop* run_loop, bool* success, bool service_success) {
               *success = success;
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
index 47fa1749..6ce7f431 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -1043,9 +1043,9 @@
         continue;
 
       auto* store = request_details_.url_request_context->cookie_store();
-      store->SetCanonicalCookieAsync(
-          std::move(cookie), request_details_.url.scheme(),
-          !options.exclude_httponly(), net::CookieStore::SetCookiesCallback());
+      store->SetCanonicalCookieAsync(std::move(cookie),
+                                     request_details_.url.scheme(), options,
+                                     net::CookieStore::SetCookiesCallback());
     }
 
     if (sub_request_) {
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index b9c8638..79b944f 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -1061,7 +1061,7 @@
       base::BarrierClosure(cookies.size(), std::move(callback)));
   for (auto& cookie : cookies) {
     cookie_manager_->SetCanonicalCookie(
-        *cookie, create_loader_params_->request.url.scheme(), true,
+        *cookie, create_loader_params_->request.url.scheme(), options,
         on_cookie_set);
   }
 }
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index cfef102..acf5eb9 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -458,8 +458,13 @@
   net::URLRequestContext* request_context =
       context_getter->GetURLRequestContext();
 
+  net::CookieOptions options;
+  options.set_include_httponly();
+  // Permit it to set a SameSite cookie if it wants to.
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   request_context->cookie_store()->SetCanonicalCookieAsync(
-      std::move(cookie), "https" /* source_scheme */, true /*modify_http_only*/,
+      std::move(cookie), "https" /* source_scheme */, options,
       std::move(callback));
 }
 
@@ -1250,8 +1255,13 @@
     return;
   }
 
+  net::CookieOptions options;
+  // Permit it to set a SameSite cookie if it wants to.
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
+  options.set_include_httponly();
   storage_partition_->GetCookieManagerForBrowserProcess()->SetCanonicalCookie(
-      *cookie, "https", true /* modify_http_only */,
+      *cookie, "https", options,
       base::BindOnce(&SetCookieCallback::sendSuccess, std::move(callback)));
 }
 
@@ -1296,9 +1306,14 @@
 
   auto* cookie_manager =
       storage_partition_->GetCookieManagerForBrowserProcess();
+  net::CookieOptions options;
+  options.set_include_httponly();
+  // Permit it to set a SameSite cookie if it wants to.
+  options.set_same_site_cookie_context(
+      net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
   for (const auto& cookie : net_cookies) {
     cookie_manager->SetCanonicalCookie(
-        *cookie, "https", true,
+        *cookie, "https", options,
         base::BindOnce(
             [](base::RepeatingClosure callback, bool) { callback.Run(); },
             barrier_closure));
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 75bc188e..6036fde 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -661,6 +661,13 @@
     render_manager()->OnDidSetFramePolicyHeaders();
 }
 
+// TODO(lanwei): Also transfer user activation in the frame trees in other
+// (i.e non-source non-destination) renderer processes. crbug.com/928838.
+void FrameTreeNode::TransferActivationFrom(FrameTreeNode* source) {
+  if (source)
+    user_activation_state_.TransferFrom(source->user_activation_state_);
+}
+
 void FrameTreeNode::PruneChildFrameNavigationEntries(
     NavigationEntryImpl* entry) {
   for (size_t i = 0; i < current_frame_host()->child_count(); ++i) {
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index 732a18d4..ca60b43b 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -403,6 +403,9 @@
     return user_activation_state_.IsActive();
   }
 
+  // Transfers user activation state from |source| frame into |this|.
+  void TransferActivationFrom(FrameTreeNode* source);
+
   // Remove history entries for all frames created by script in this frame's
   // subtree. If a frame created by a script is removed, then its history entry
   // will never be reused - this saves memory.
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 007942c..369c219 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -5,7 +5,6 @@
 #include "content/browser/frame_host/navigation_handle_impl.h"
 
 #include "base/bind.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
@@ -876,15 +875,8 @@
     // If the navigation is done processing the response, then it's ready to
     // commit. Inform observers that the navigation is now ready to commit,
     // unless it is not set to commit (204/205s/downloads).
-    if (GetRenderFrameHost()) {
-      base::WeakPtr<NavigationHandleImpl> weak_ptr = weak_factory_.GetWeakPtr();
+    if (GetRenderFrameHost())
       ReadyToCommitNavigation(false);
-      // TODO(https://crbug.com/880741): Remove this once the bug is fixed.
-      if (!weak_ptr) {
-        base::debug::DumpWithoutCrashing();
-        return;
-      }
-    }
   } else {
     state_ = CANCELING;
   }
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index a61bff6..4d43fd1 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1087,11 +1087,6 @@
         rfh, blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOrigin);
   }
 
-  // TODO(https://crbug.com/880741): Remove this once the bug is fixed.
-  if (state_ != STARTED) {
-    DEBUG_ALIAS_FOR_GURL(url, navigation_handle_->GetURL());
-    base::debug::DumpWithoutCrashing();
-  }
   DCHECK_EQ(state_, STARTED);
   DCHECK(response);
   TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this,
@@ -1852,11 +1847,6 @@
          render_frame_host_ ==
              frame_tree_node_->render_manager()->speculative_frame_host());
 
-  // TODO(https://crbug.com/880741): Remove this once the bug is fixed.
-  if (!frame_tree_node_->navigation_request()) {
-    DEBUG_ALIAS_FOR_GURL(url, navigation_handle_->GetURL());
-    base::debug::DumpWithoutCrashing();
-  }
 
   frame_tree_node_->TransferNavigationRequestOwnership(render_frame_host_);
   if (IsPerNavigationMojoInterfaceEnabled() && request_navigation_client_ &&
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index 09095ba..23470d05 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -585,6 +585,9 @@
   }
 
   net::CookieOptions options;
+  // TODO(https://crbug.com/925311): Wire initiator in here properly.
+  options.set_same_site_cookie_context(net::cookie_util::ComputeSameSiteContext(
+      url, site_for_cookies, base::nullopt));
   std::unique_ptr<net::CanonicalCookie> cookie = net::CanonicalCookie::Create(
       url, cookie_line, base::Time::Now(), options);
   if (!cookie) {
@@ -613,7 +616,7 @@
 
     // Pass a null callback since we don't care about when the 'set' completes.
     cookie_store->SetCanonicalCookieAsync(
-        std::move(cookie), url.scheme(), !options.exclude_httponly(),
+        std::move(cookie), url.scheme(), options,
         net::CookieStore::SetCookiesCallback());
     return;
   }
@@ -627,7 +630,7 @@
                          std::move(callback)),
           false);
   (*GetCookieManager())
-      ->SetCanonicalCookie(*cookie, url.scheme(), !options.exclude_httponly(),
+      ->SetCanonicalCookie(*cookie, url.scheme(), options,
                            std::move(net_callback));
 }
 
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index f8b6da4..3260ea6 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -426,6 +426,16 @@
       // to the target page.
       target_rfh->delegate()->EnsureOpenerProxiesExist(source_rfh);
 
+      // Transfer user activation state in the frame tree in browser when
+      // |transfer_user_activation| is true.
+      if (base::FeatureList::IsEnabled(
+              features::kUserActivationPostMessageTransfer) &&
+          message.transfer_user_activation &&
+          source_rfh->frame_tree_node()->HasTransientUserActivation()) {
+        target_rfh->frame_tree_node()->TransferActivationFrom(
+            source_rfh->frame_tree_node());
+      }
+
       // If the message source is a cross-process subframe, its proxy will only
       // be created in --site-per-process mode.  If the proxy wasn't created,
       // set the source routing ID to MSG_ROUTING_NONE (see
diff --git a/content/browser/scheduler/browser_ui_thread_scheduler.cc b/content/browser/scheduler/browser_ui_thread_scheduler.cc
index 9fec0c58..72810d7 100644
--- a/content/browser/scheduler/browser_ui_thread_scheduler.cc
+++ b/content/browser/scheduler/browser_ui_thread_scheduler.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/process/process.h"
@@ -14,6 +15,7 @@
 #include "base/task/sequence_manager/time_domain.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
+#include "content/public/common/content_features.h"
 
 namespace content {
 
@@ -29,7 +31,15 @@
 }
 
 void BrowserUIThreadScheduler::PostFeatureListSetup() {
-  // TODO(scheduler-dev): Initialize experiments here.
+  if (base::FeatureList::IsEnabled(features::kPrioritizeBootstrapTasks)) {
+    task_queues_[QueueType::kBootstrap]->SetQueuePriority(
+        base::sequence_manager::TaskQueue::kHighestPriority);
+
+    // Navigation tasks are also important during startup so prioritize them
+    // too.
+    task_queues_[QueueType::kNavigation]->SetQueuePriority(
+        base::sequence_manager::TaskQueue::kHighPriority);
+  }
 }
 
 void BrowserUIThreadScheduler::Shutdown() {
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 10b9330..b6d8289f 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -773,13 +773,7 @@
 }
 
 net::URLRequestContextGetter* StoragePartitionImpl::GetURLRequestContext() {
-  // TODO(jam): enable for all, still used on WebView.
-  // See copy of this ifdef in:
-  //   StoragePartitionImplMap::Get
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    NOTREACHED();
-#endif
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
   return url_request_context_.get();
 }
 
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index 4d42ad98..27a2400 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -420,18 +420,7 @@
     request_interceptors.push_back(std::move(devtools_interceptor));
   request_interceptors.push_back(std::make_unique<AppCacheInterceptor>());
 
-  bool create_request_context = true;
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    // These ifdefs should match StoragePartitionImpl::GetURLRequestContext.
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-    create_request_context = false;
-#elif defined(OS_ANDROID)
-    create_request_context =
-        GetContentClient()->browser()->NeedURLRequestContext();
-#endif
-  }
-
-  if (create_request_context) {
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
     // These calls must happen after StoragePartitionImpl::Create().
     if (partition_domain.empty()) {
       partition->SetURLRequestContext(browser_context_->CreateRequestContext(
diff --git a/content/public/browser/background_sync_context.h b/content/public/browser/background_sync_context.h
index 67a7fa2..f4ec66a 100644
--- a/content/public/browser/background_sync_context.h
+++ b/content/public/browser/background_sync_context.h
@@ -7,17 +7,9 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "base/android/scoped_java_ref.h"
-#endif
 
 namespace content {
 
-class BrowserContext;
 class StoragePartition;
 
 // One instance of this exists per StoragePartition, and services multiple child
@@ -26,33 +18,15 @@
 // other components.
 class CONTENT_EXPORT BackgroundSyncContext {
  public:
-  // Gets the soonest time delta from now, when the browser should be woken up
-  // to fire any Background Sync events, across all storage partitions in
-  // |browser_context|, and invokes |callback| with it.
-  static void GetSoonestWakeupDeltaAcrossPartitions(
-      BrowserContext* browser_context,
-      base::OnceCallback<void(base::TimeDelta)> callback);
-
-#if defined(OS_ANDROID)
-  // Processes pending Background Sync registrations for all storage partitions
-  // in |browser_context|, and then runs  the |j_runnable| when done.
-  static void FireBackgroundSyncEventsAcrossPartitions(
-      BrowserContext* browser_context,
-      const base::android::JavaParamRef<jobject>& j_runnable);
-#endif
-
   BackgroundSyncContext() = default;
 
-  // Process any pending Background Sync registrations.
+  // Process any pending Background Sync registrations for |storage_partition|.
   // This involves firing any sync events ready to be fired, and optionally
   // scheduling a job to wake up the browser when the next event needs to be
   // fired.
-  virtual void FireBackgroundSyncEvents(base::OnceClosure done_closure) = 0;
-
-  // Gets the soonest time delta from now, when the browser should be woken up
-  // to fire any Background Sync events. Calls |callback| with this value.
-  virtual void GetSoonestWakeupDelta(
-      base::OnceCallback<void(base::TimeDelta)> callback) = 0;
+  virtual void FireBackgroundSyncEventsForStoragePartition(
+      StoragePartition* storage_partition,
+      base::OnceClosure done_closure) = 0;
 
  protected:
   virtual ~BackgroundSyncContext() = default;
diff --git a/content/public/browser/background_sync_controller.h b/content/public/browser/background_sync_controller.h
index 50e6c4064..33ad82d 100644
--- a/content/public/browser/background_sync_controller.h
+++ b/content/public/browser/background_sync_controller.h
@@ -33,9 +33,16 @@
   // registered a background sync event.
   virtual void NotifyBackgroundSyncRegistered(const url::Origin& origin) {}
 
-  // Calculates the soonest wakeup delta across all storage partitions and
-  // schedules a background task to wake up the browser.
-  virtual void RunInBackground() {}
+  // If |enabled|, ensures that the browser is running when the device next goes
+  // online after |min_ms| has passed. The behavior is platform dependent:
+  // * Android: Registers a GCM task which verifies that the browser is running
+  // the next time the device goes online after |min_ms| has passed. If it's
+  // not, it starts it.
+  //
+  // * Other Platforms: (UNIMPLEMENTED) Keeps the browser alive via
+  // BackgroundModeManager until called with |enabled| = false. |min_ms| is
+  // ignored.
+  virtual void RunInBackground(bool enabled, int64_t min_ms) {}
 };
 
 }  // namespace content
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index b3c348a1..6a952d2 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -807,10 +807,6 @@
 }
 
 #if defined(OS_ANDROID)
-bool ContentBrowserClient::NeedURLRequestContext() {
-  return true;
-}
-
 bool ContentBrowserClient::ShouldOverrideUrlLoading(
     int frame_tree_node_id,
     bool browser_initiated,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index f99a98af..00902fa 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1303,10 +1303,6 @@
   virtual std::vector<base::FilePath> GetNetworkContextsParentDirectory();
 
 #if defined(OS_ANDROID)
-  // Configures whether StoragePartition needs to create a
-  // net::URLRequestContext in the browser when the network service is enabled.
-  virtual bool NeedURLRequestContext();
-
   // Only used by Android WebView.
   // Returns:
   //   true  - The check was successfully performed without throwing a
diff --git a/content/public/browser/web_contents_user_data.h b/content/public/browser/web_contents_user_data.h
index 74a657f..28996e5 100644
--- a/content/public/browser/web_contents_user_data.h
+++ b/content/public/browser/web_contents_user_data.h
@@ -10,10 +10,6 @@
 #include "base/supports_user_data.h"
 #include "content/public/browser/web_contents.h"
 
-#define WEB_CONTENTS_USER_DATA_KEY_DECL() static constexpr int kUserDataKey = 0
-
-#define WEB_CONTENTS_USER_DATA_KEY_IMPL(Type) const int Type::kUserDataKey;
-
 namespace content {
 
 // A base class for classes attached to, and scoped to, the lifetime of a
@@ -59,6 +55,23 @@
   static const void* UserDataKey() { return &T::kUserDataKey; }
 };
 
+// This macro declares a static variable inside the class that inherits from
+// WebContentsUserData The address of this static variable is used as the key to
+// store/retrieve an instance of the class on/from a WebState.
+#define WEB_CONTENTS_USER_DATA_KEY_DECL() static constexpr int kUserDataKey = 0
+
+// This macro instantiates the static variable declared by the previous macro.
+// It must live in a .cc file to ensure that there is only one instantiation
+// of the static variable.
+#define WEB_CONTENTS_USER_DATA_KEY_IMPL(Type) const int Type::kUserDataKey;
+
+// We tried using the address of a static local variable in UserDataKey() as a
+// key instead of the address of a member variable. That solution allowed us to
+// get rid of the macros above. Unfortately, each dynamic library that accessed
+// UserDataKey() had its own instantiation of the method, resulting in different
+// keys for the same WebContentsUserData type. Because of that, the solution was
+// reverted. https://crbug.com/589840#c16
+
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_BROWSER_WEB_CONTENTS_USER_DATA_H_
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index ccd59da..b946a64c 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1791,12 +1791,14 @@
   BrowserContext::GetDefaultStoragePartition(browser_context)
       ->GetNetworkContext()
       ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
-  std::unique_ptr<net::CanonicalCookie> cc(net::CanonicalCookie::Create(
-      url, value, base::Time::Now(), net::CookieOptions()));
+  net::CookieOptions options;
+  options.set_include_httponly();
+  std::unique_ptr<net::CanonicalCookie> cc(
+      net::CanonicalCookie::Create(url, value, base::Time::Now(), options));
   DCHECK(cc.get());
 
   cookie_manager->SetCanonicalCookie(
-      *cc.get(), url.scheme(), true /* modify_http_only */,
+      *cc.get(), url.scheme(), options,
       base::BindOnce(
           [](bool* result, base::RunLoop* run_loop, bool success) {
             *result = success;
diff --git a/content/renderer/compositor/layer_tree_view.cc b/content/renderer/compositor/layer_tree_view.cc
index 7f58de72..b35a466 100644
--- a/content/renderer/compositor/layer_tree_view.cc
+++ b/content/renderer/compositor/layer_tree_view.cc
@@ -258,10 +258,6 @@
   return layer_tree_host_->SourceFrameNumber();
 }
 
-void LayerTreeView::NotifyInputThrottledUntilCommit() {
-  layer_tree_host_->NotifyInputThrottledUntilCommit();
-}
-
 const cc::Layer* LayerTreeView::GetRootLayer() const {
   return layer_tree_host_->root_layer();
 }
diff --git a/content/renderer/compositor/layer_tree_view.h b/content/renderer/compositor/layer_tree_view.h
index 0800bce..fab9877 100644
--- a/content/renderer/compositor/layer_tree_view.h
+++ b/content/renderer/compositor/layer_tree_view.h
@@ -103,7 +103,6 @@
   // LayerTreeHost.
   void QueueSwapPromise(std::unique_ptr<cc::SwapPromise> swap_promise);
   int GetSourceFrameNumber() const;
-  void NotifyInputThrottledUntilCommit();
   const cc::Layer* GetRootLayer() const;
   int ScheduleMicroBenchmark(
       const std::string& name,
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 393926e..454098b 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -16,6 +16,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -46,6 +47,7 @@
 #include "content/renderer/render_view_impl.h"
 #include "crypto/openssl_util.h"
 #include "jingle/glue/thread_wrapper.h"
+#include "media/base/bind_to_current_loop.h"
 #include "media/base/media_permission.h"
 #include "media/media_buildflags.h"
 #include "media/video/gpu_video_accelerator_factories.h"
@@ -122,7 +124,8 @@
       signaling_thread_(nullptr),
       worker_thread_(nullptr),
       chrome_signaling_thread_("Chrome_libJingle_Signaling"),
-      chrome_worker_thread_("Chrome_libJingle_WorkerThread") {
+      chrome_worker_thread_("Chrome_libJingle_WorkerThread"),
+      weak_factory_(this) {
   TryScheduleStunProbeTrial();
 }
 
@@ -199,20 +202,11 @@
   base::WaitableEvent create_network_manager_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
-  std::unique_ptr<MdnsResponderAdapter> mdns_responder;
-#if BUILDFLAG(ENABLE_MDNS)
-  if (base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
-    // Note that MdnsResponderAdapter is created on the main thread to have
-    // access to the connector to the service manager.
-    mdns_responder = std::make_unique<MdnsResponderAdapter>();
-  }
-#endif  // BUILDFLAG(ENABLE_MDNS)
   chrome_worker_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&PeerConnectionDependencyFactory::
                          CreateIpcNetworkManagerOnWorkerThread,
-                     base::Unretained(this), &create_network_manager_event,
-                     std::move(mdns_responder)));
+                     base::Unretained(this), &create_network_manager_event));
 
   start_worker_event.Wait();
   create_network_manager_event.Wait();
@@ -454,8 +448,12 @@
 
   std::unique_ptr<rtc::NetworkManager> network_manager;
   if (port_config.enable_multiple_routes) {
+    auto callback = media::BindToCurrentLoop(base::BindRepeating(
+        &PeerConnectionDependencyFactory::OnEnumeratePermissionChanged,
+        weak_factory_.GetWeakPtr()));
     network_manager = std::make_unique<FilteringNetworkManager>(
-        network_manager_.get(), requesting_origin, media_permission);
+        network_manager_.get(), requesting_origin, media_permission,
+        std::move(callback));
   } else {
     network_manager =
         std::make_unique<EmptyNetworkManager>(network_manager_.get());
@@ -560,11 +558,10 @@
 }
 
 void PeerConnectionDependencyFactory::CreateIpcNetworkManagerOnWorkerThread(
-    base::WaitableEvent* event,
-    std::unique_ptr<MdnsResponderAdapter> mdns_responder) {
+    base::WaitableEvent* event) {
   DCHECK(chrome_worker_thread_.task_runner()->BelongsToCurrentThread());
-  network_manager_ = std::make_unique<IpcNetworkManager>(
-      p2p_socket_dispatcher_.get(), std::move(mdns_responder));
+  network_manager_ =
+      std::make_unique<IpcNetworkManager>(p2p_socket_dispatcher_.get());
   event->Signal();
 }
 
@@ -655,4 +652,24 @@
   return nullptr;
 }
 
+void PeerConnectionDependencyFactory::OnEnumeratePermissionChanged(
+    rtc::NetworkManager::EnumerationPermission new_state) {
+#if BUILDFLAG(ENABLE_MDNS)
+  std::unique_ptr<MdnsResponderAdapter> mdns_responder;
+  if (new_state == rtc::NetworkManager::ENUMERATION_BLOCKED &&
+      base::FeatureList::IsEnabled(features::kWebRtcHideLocalIpsWithMdns)) {
+    // Note that MdnsResponderAdapter is created on the main thread to have
+    // access to the connector to the service manager.
+    mdns_responder = std::make_unique<MdnsResponderAdapter>();
+  }
+  // base::Unretained is safe below because |network_manager_| will be destroyed
+  // only after |chrome_work_thread_| stops, which flushes all tasks. See
+  // PeerConnectionDependencyFactory::CleanupPeerConnectionFactory.
+  chrome_worker_thread_.task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&IpcNetworkManager::SetMdnsResponder,
+                                base::Unretained(network_manager_.get()),
+                                base::Passed(&mdns_responder)));
+#endif  // BUILDFLAG(ENABLE_MDNS)
+}
+
 }  // namespace content
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index 137b36ac..5182cab 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -9,6 +9,7 @@
 
 #include "base/files/file.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop_current.h"
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
@@ -42,7 +43,6 @@
 
 class IpcNetworkManager;
 class IpcPacketSocketFactory;
-class MdnsResponderAdapter;
 class P2PPortAllocator;
 class WebRtcAudioDeviceImpl;
 
@@ -150,12 +150,13 @@
   void InitializeWorkerThread(rtc::Thread** thread,
                               base::WaitableEvent* event);
 
-  void CreateIpcNetworkManagerOnWorkerThread(
-      base::WaitableEvent* event,
-      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
+  void CreateIpcNetworkManagerOnWorkerThread(base::WaitableEvent* event);
   void DeleteIpcNetworkManager();
   void CleanupPeerConnectionFactory();
 
+  void OnEnumeratePermissionChanged(
+      rtc::NetworkManager::EnumerationPermission new_state);
+
   // network_manager_ must be deleted on the worker thread. The network manager
   // uses |p2p_socket_dispatcher_|.
   std::unique_ptr<IpcNetworkManager> network_manager_;
@@ -177,6 +178,9 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
+  // The weak pointer MUST only be dereferenced on the main thread.
+  base::WeakPtrFactory<PeerConnectionDependencyFactory> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PeerConnectionDependencyFactory);
 };
 
diff --git a/content/renderer/p2p/filtering_network_manager.cc b/content/renderer/p2p/filtering_network_manager.cc
index 0ecd2ed..d09315d 100644
--- a/content/renderer/p2p/filtering_network_manager.cc
+++ b/content/renderer/p2p/filtering_network_manager.cc
@@ -17,18 +17,20 @@
 FilteringNetworkManager::FilteringNetworkManager(
     rtc::NetworkManager* network_manager,
     const GURL& requesting_origin,
-    media::MediaPermission* media_permission)
+    media::MediaPermission* media_permission,
+    OnEnumerationPermissionCallback callback)
     : network_manager_(network_manager),
       media_permission_(media_permission),
       requesting_origin_(requesting_origin),
+      on_enumeration_permission_cb_(std::move(callback)),
       weak_ptr_factory_(this) {
   thread_checker_.DetachFromThread();
-  set_enumeration_permission(ENUMERATION_BLOCKED);
+  SetEnumerationPermissionAndNotify(ENUMERATION_BLOCKED);
 
   // If the feature is not enabled, just return ALLOWED as it's requested.
   if (!media_permission_) {
     started_permission_check_ = true;
-    set_enumeration_permission(ENUMERATION_ALLOWED);
+    SetEnumerationPermissionAndNotify(ENUMERATION_ALLOWED);
     VLOG(3) << "media_permission is not passed, granting permission";
     return;
   }
@@ -82,9 +84,6 @@
   if (enumeration_permission() == ENUMERATION_ALLOWED)
     network_manager_->GetNetworks(networks);
 
-  for (rtc::Network* network : *networks)
-    network->set_mdns_responder_provider(this);
-
   VLOG(3) << "GetNetworks() returns " << networks->size() << " networks.";
 }
 
@@ -96,13 +95,6 @@
 
 webrtc::MdnsResponderInterface* FilteringNetworkManager::GetMdnsResponder()
     const {
-  if (enumeration_permission() == ENUMERATION_ALLOWED) {
-    // We do not try to destroy the binding to the mDNS responder service host
-    // so that we can still resolve the names created when no permission was
-    // granted. The mDNS responder service just becomes unavailable.
-    return nullptr;
-  }
-
   return network_manager_->GetMdnsResponder();
 }
 
@@ -133,7 +125,7 @@
   --pending_permission_checks_;
 
   if (granted)
-    set_enumeration_permission(ENUMERATION_ALLOWED);
+    SetEnumerationPermissionAndNotify(ENUMERATION_ALLOWED);
 
   // If the IP permission status changed *and* we have an up-to-date network
   // list, fire a network change event.
@@ -141,6 +133,16 @@
     FireEventIfStarted();
 }
 
+void FilteringNetworkManager::SetEnumerationPermissionAndNotify(
+    EnumerationPermission state) {
+  EnumerationPermission old_state = enumeration_permission();
+  if (state != old_state) {
+    set_enumeration_permission(state);
+    if (on_enumeration_permission_cb_)
+      on_enumeration_permission_cb_.Run(state);
+  }
+}
+
 void FilteringNetworkManager::OnNetworksChanged() {
   DCHECK(thread_checker_.CalledOnValidThread());
   pending_network_update_ = false;
diff --git a/content/renderer/p2p/filtering_network_manager.h b/content/renderer/p2p/filtering_network_manager.h
index 7d3b292..47a9f6a 100644
--- a/content/renderer/p2p/filtering_network_manager.h
+++ b/content/renderer/p2p/filtering_network_manager.h
@@ -5,8 +5,10 @@
 #ifndef CONTENT_RENDERER_P2P_FILTERING_NETWORK_MANAGER_H_
 #define CONTENT_RENDERER_P2P_FILTERING_NETWORK_MANAGER_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
@@ -37,12 +39,17 @@
 class FilteringNetworkManager : public rtc::NetworkManagerBase,
                                 public sigslot::has_slots<> {
  public:
+  // A callback that will be executed when |enumeration_permission_| changes.
+  using OnEnumerationPermissionCallback =
+      base::RepeatingCallback<void(EnumerationPermission)>;
+
   // This class is created by WebRTC's signaling thread but used by WebRTC's
   // worker thread |task_runner|.
   CONTENT_EXPORT FilteringNetworkManager(
       rtc::NetworkManager* network_manager,
       const GURL& requesting_origin,
-      media::MediaPermission* media_permission);
+      media::MediaPermission* media_permission,
+      OnEnumerationPermissionCallback callback);
 
   CONTENT_EXPORT ~FilteringNetworkManager() override;
 
@@ -64,6 +71,8 @@
   // available.
   void OnPermissionStatus(bool granted);
 
+  void SetEnumerationPermissionAndNotify(EnumerationPermission state);
+
   base::WeakPtr<FilteringNetworkManager> GetWeakPtr();
 
   // Receive callback from the wrapped NetworkManager when the underneath
@@ -117,6 +126,8 @@
 
   GURL requesting_origin_;
 
+  OnEnumerationPermissionCallback on_enumeration_permission_cb_;
+
   base::WeakPtrFactory<FilteringNetworkManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FilteringNetworkManager);
diff --git a/content/renderer/p2p/filtering_network_manager_unittest.cc b/content/renderer/p2p/filtering_network_manager_unittest.cc
index 87295ec0..1a4c424 100644
--- a/content/renderer/p2p/filtering_network_manager_unittest.cc
+++ b/content/renderer/p2p/filtering_network_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/stl_util.h"
@@ -137,7 +138,8 @@
     if (multiple_routes_requested) {
       FilteringNetworkManager* filtering_network_manager =
           new FilteringNetworkManager(mock_network_manager_.get(), GURL(),
-                                      media_permission_.get());
+                                      media_permission_.get(),
+                                      base::DoNothing());
       filtering_network_manager->Initialize();
       network_manager_.reset(filtering_network_manager);
     } else {
diff --git a/content/renderer/p2p/ipc_network_manager.cc b/content/renderer/p2p/ipc_network_manager.cc
index 9a847e9..987aa861 100644
--- a/content/renderer/p2p/ipc_network_manager.cc
+++ b/content/renderer/p2p/ipc_network_manager.cc
@@ -5,20 +5,21 @@
 #include "content/renderer/p2p/ipc_network_manager.h"
 
 #include <string>
-#include <utility>
-
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/sys_byteorder.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "jingle/glue/utils.h"
 #include "net/base/ip_address.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_interfaces.h"
+#include "net/net_buildflags.h"
 #include "third_party/webrtc/rtc_base/socket_address.h"
 
 namespace content {
@@ -45,12 +46,8 @@
 
 }  // namespace
 
-IpcNetworkManager::IpcNetworkManager(
-    NetworkListManager* network_list_manager,
-    std::unique_ptr<MdnsResponderAdapter> mdns_responder)
-    : network_list_manager_(network_list_manager),
-      mdns_responder_(std::move(mdns_responder)),
-      weak_factory_(this) {
+IpcNetworkManager::IpcNetworkManager(NetworkListManager* network_list_manager)
+    : network_list_manager_(network_list_manager), weak_factory_(this) {
   network_list_manager_->AddNetworkListObserver(this);
 }
 
@@ -190,6 +187,11 @@
                            stats.ipv6_network_count);
 }
 
+void IpcNetworkManager::SetMdnsResponder(
+    std::unique_ptr<MdnsResponderAdapter> mdns_responder) {
+  mdns_responder_ = std::move(mdns_responder);
+}
+
 webrtc::MdnsResponderInterface* IpcNetworkManager::GetMdnsResponder() const {
   return mdns_responder_.get();
 }
diff --git a/content/renderer/p2p/ipc_network_manager.h b/content/renderer/p2p/ipc_network_manager.h
index c0395753..3e1657b 100644
--- a/content/renderer/p2p/ipc_network_manager.h
+++ b/content/renderer/p2p/ipc_network_manager.h
@@ -29,9 +29,7 @@
                           public NetworkListObserver {
  public:
   // Constructor doesn't take ownership of the |network_list_manager|.
-  CONTENT_EXPORT IpcNetworkManager(
-      NetworkListManager* network_list_manager,
-      std::unique_ptr<MdnsResponderAdapter> mdns_responder);
+  CONTENT_EXPORT IpcNetworkManager(NetworkListManager* network_list_manager);
   ~IpcNetworkManager() override;
 
   // rtc:::NetworkManager:
@@ -45,6 +43,8 @@
       const net::IPAddress& default_ipv4_local_address,
       const net::IPAddress& default_ipv6_local_address) override;
 
+  void SetMdnsResponder(std::unique_ptr<MdnsResponderAdapter> mdns_responder);
+
  private:
   void SendNetworksChangedSignal();
 
diff --git a/content/renderer/p2p/ipc_network_manager_unittest.cc b/content/renderer/p2p/ipc_network_manager_unittest.cc
index 26b96cf..06bb29c 100644
--- a/content/renderer/p2p/ipc_network_manager_unittest.cc
+++ b/content/renderer/p2p/ipc_network_manager_unittest.cc
@@ -41,8 +41,7 @@
  public:
   IpcNetworkManagerTest()
       : network_list_manager_(new MockP2PSocketDispatcher()),
-        network_manager_(
-            new IpcNetworkManager(network_list_manager_.get(), nullptr)) {}
+        network_manager_(new IpcNetworkManager(network_list_manager_.get())) {}
 
  protected:
   std::unique_ptr<MockP2PSocketDispatcher> network_list_manager_;
diff --git a/content/renderer/web_database_observer_impl.cc b/content/renderer/web_database_observer_impl.cc
index 6156b01..c9dfc83 100644
--- a/content/renderer/web_database_observer_impl.cc
+++ b/content/renderer/web_database_observer_impl.cc
@@ -30,7 +30,7 @@
     const WebSecurityOrigin& origin,
     const WebString& database_name,
     const WebString& database_display_name,
-    unsigned long estimated_size) {
+    uint32_t estimated_size) {
   (*web_database_host_)
       ->Opened(origin, database_name.Utf16(), database_display_name.Utf16(),
                estimated_size);
diff --git a/content/renderer/web_database_observer_impl.h b/content/renderer/web_database_observer_impl.h
index 0ec094d..67515de 100644
--- a/content/renderer/web_database_observer_impl.h
+++ b/content/renderer/web_database_observer_impl.h
@@ -26,7 +26,7 @@
   void DatabaseOpened(const blink::WebSecurityOrigin& origin,
                       const blink::WebString& database_name,
                       const blink::WebString& database_display_name,
-                      unsigned long estimated_size) override;
+                      uint32_t estimated_size) override;
   void DatabaseModified(const blink::WebSecurityOrigin& origin,
                         const blink::WebString& database_name) override;
   void DatabaseClosed(const blink::WebSecurityOrigin& origin,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 6022433..578fe1dd 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1387,7 +1387,6 @@
     "../browser/background_fetch/background_fetch_service_unittest.cc",
     "../browser/background_fetch/storage/database_helpers_unittest.cc",
     "../browser/background_fetch/storage/image_helpers_unittest.cc",
-    "../browser/background_sync/background_sync_launcher_unittest.cc",
     "../browser/background_sync/background_sync_manager_unittest.cc",
     "../browser/background_sync/background_sync_network_observer_unittest.cc",
     "../browser/background_sync/background_sync_service_impl_unittest.cc",
diff --git a/content/test/gpu/gpu_tests/depth_capture_expectations.py b/content/test/gpu/gpu_tests/depth_capture_expectations.py
index f2a229e..b119de6 100644
--- a/content/test/gpu/gpu_tests/depth_capture_expectations.py
+++ b/content/test/gpu/gpu_tests/depth_capture_expectations.py
@@ -19,5 +19,3 @@
                ['linux', ('nvidia', 0x104a)], bug=737410)
     self.Fail('DepthCapture_depthStreamToR32FloatTexture',
               ['android', ('qualcomm', 'Adreno (TM) 330')], bug=765913)
-    self.Flaky('DepthCapture_depthStreamToR32FloatTexture',
-              ['win7'], bug=937134)
diff --git a/content/test/mock_background_sync_controller.cc b/content/test/mock_background_sync_controller.cc
index b671965..13b94930 100644
--- a/content/test/mock_background_sync_controller.cc
+++ b/content/test/mock_background_sync_controller.cc
@@ -12,8 +12,11 @@
   registration_origin_ = origin;
 }
 
-void MockBackgroundSyncController::RunInBackground() {
+void MockBackgroundSyncController::RunInBackground(bool enabled,
+                                                   int64_t min_ms) {
   run_in_background_count_ += 1;
+  run_in_background_enabled_ = enabled;
+  run_in_background_min_ms_ = min_ms;
 }
 
 void MockBackgroundSyncController::GetParameterOverrides(
diff --git a/content/test/mock_background_sync_controller.h b/content/test/mock_background_sync_controller.h
index 3f97681..0a854ea 100644
--- a/content/test/mock_background_sync_controller.h
+++ b/content/test/mock_background_sync_controller.h
@@ -9,7 +9,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/time/time.h"
 #include "content/public/browser/background_sync_controller.h"
 #include "content/public/browser/background_sync_parameters.h"
 #include "url/gurl.h"
@@ -25,7 +24,7 @@
 
   // BackgroundSyncController:
   void NotifyBackgroundSyncRegistered(const url::Origin& origin) override;
-  void RunInBackground() override;
+  void RunInBackground(bool enabled, int64_t min_ms) override;
   void GetParameterOverrides(
       BackgroundSyncParameters* parameters) const override;
 
@@ -34,6 +33,8 @@
     return registration_origin_;
   }
   int run_in_background_count() const { return run_in_background_count_; }
+  bool run_in_background_enabled() const { return run_in_background_enabled_; }
+  int64_t run_in_background_min_ms() const { return run_in_background_min_ms_; }
   BackgroundSyncParameters* background_sync_parameters() {
     return &background_sync_parameters_;
   }
@@ -43,6 +44,8 @@
   url::Origin registration_origin_;
 
   int run_in_background_count_ = 0;
+  bool run_in_background_enabled_ = true;
+  int64_t run_in_background_min_ms_ = 0;
   BackgroundSyncParameters background_sync_parameters_;
 
   DISALLOW_COPY_AND_ASSIGN(MockBackgroundSyncController);
diff --git a/content/test/test_background_sync_manager.cc b/content/test/test_background_sync_manager.cc
index 0635711..3e95d08 100644
--- a/content/test/test_background_sync_manager.cc
+++ b/content/test/test_background_sync_manager.cc
@@ -118,9 +118,4 @@
   BackgroundSyncManager::GetDataFromBackend(key, std::move(callback));
 }
 
-base::TimeDelta TestBackgroundSyncManager::GetSoonestWakeupDelta() {
-  soonest_wakeup_delta_ = BackgroundSyncManager::GetSoonestWakeupDelta();
-  return soonest_wakeup_delta_;
-}
-
 }  // namespace content
diff --git a/content/test/test_background_sync_manager.h b/content/test/test_background_sync_manager.h
index 4fd6508..a4566e0c 100644
--- a/content/test/test_background_sync_manager.h
+++ b/content/test/test_background_sync_manager.h
@@ -86,13 +86,6 @@
     return parameters_.get();
   }
 
-  bool IsBrowserWakeupScheduled() const {
-    return !soonest_wakeup_delta_.is_max();
-  }
-  bool EqualsSoonestWakeupDelta(base::TimeDelta compare_to) const {
-    return soonest_wakeup_delta_ == compare_to;
-  }
-
  protected:
   // Override to allow delays to be injected by tests.
   void StoreDataInBackend(
@@ -126,8 +119,6 @@
   void HasMainFrameProviderHost(const url::Origin& origin,
                                 BoolCallback callback) override;
 
-  base::TimeDelta GetSoonestWakeupDelta() override;
-
  private:
   // Callback to resume the StoreDataInBackend operation, after explicit
   // delays injected by tests.
@@ -152,7 +143,6 @@
   DispatchSyncCallback dispatch_sync_callback_;
   base::OnceClosure delayed_task_;
   base::TimeDelta delayed_task_delta_;
-  base::TimeDelta soonest_wakeup_delta_;
 
   DISALLOW_COPY_AND_ASSIGN(TestBackgroundSyncManager);
 };
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md
index 702d2c9..06332143e 100644
--- a/docs/android_build_instructions.md
+++ b/docs/android_build_instructions.md
@@ -247,7 +247,7 @@
 You can check if the device is connected by running:
 
 ```shell
-third_party/android_tools/sdk/platform-tools/adb devices
+third_party/android_sdk/public/platform-tools/adb devices
 ```
 
 Which prints a list of connected devices. If not connected, try
@@ -263,7 +263,7 @@
 `adb shell` instead:
 
 ```shell
-third_party/android_tools/sdk/platform-tools/adb shell settings put global verifier_verify_adb_installs 0
+third_party/android_sdk/public/platform-tools/adb shell settings put global verifier_verify_adb_installs 0
 ```
 
 ### Build the full browser
diff --git a/docs/android_cast_build_instructions.md b/docs/android_cast_build_instructions.md
index 4e4b693..b3be8ae 100644
--- a/docs/android_cast_build_instructions.md
+++ b/docs/android_cast_build_instructions.md
@@ -170,7 +170,7 @@
 You can check if the device is connected by running:
 
 ```shell
-third_party/android_tools/sdk/platform-tools/adb devices
+third_party/android_sdk/public/platform-tools/adb devices
 ```
 
 Which prints a list of connected devices. If not connected, try
diff --git a/docs/android_debugging_instructions.md b/docs/android_debugging_instructions.md
index ad8c34a..3c69e40 100644
--- a/docs/android_debugging_instructions.md
+++ b/docs/android_debugging_instructions.md
@@ -80,7 +80,7 @@
 *   Run Android Device Monitor:
 
     ```shell
-    third_party/android_tools/sdk/tools/monitor
+    third_party/android_sdk/public/tools/monitor
     ```
 
 *   Now select the process you want to debug in Device Monitor (the port column
diff --git a/docs/android_test_instructions.md b/docs/android_test_instructions.md
index 6d4a8fe..1f61ba4 100644
--- a/docs/android_test_instructions.md
+++ b/docs/android_test_instructions.md
@@ -24,7 +24,7 @@
 The adb executable exists within the Android SDK:
 
 ```shell
-third_party/android_tools/sdk/platform-tools/adb
+third_party/android_sdk/public/platform-tools/adb
 ```
 
 In order to allow the ADB to connect to the device, you must enable USB
diff --git a/docs/chromoting_android_hacking.md b/docs/chromoting_android_hacking.md
index 834b5e2..cfcb714 100644
--- a/docs/chromoting_android_hacking.md
+++ b/docs/chromoting_android_hacking.md
@@ -13,7 +13,7 @@
 ## Viewing logging output
 
 In order to access LogCat and view the app's logging output, we need to launch
-the Android Device Monitor. Run `third_party/android_tools/sdk/tools/monitor`
+the Android Device Monitor. Run `third_party/android_sdk/public/tools/monitor`
 and select the desired device under `Devices`. Using the app as normal will
 display log messages to the `LogCat` pane.
 
@@ -105,8 +105,8 @@
 <classpathentry kind="src" path="content/shell/android/shell_apk/src"/>
 <classpathentry kind="src" path="content/shell/android/javatests/src"/>
 <classpathentry kind="src" path="content/shell/android/linker_test_apk/src"/>
-<classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-19/data/layoutlib.jar"/>
-<classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-19/android.jar"/>
+<classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-27/data/layoutlib.jar"/>
+<classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-27/android.jar"/>
 <classpathentry kind="output" path="out/bin"/>
 </classpath>
 ```
diff --git a/docs/infra/cq_builders.md b/docs/infra/cq_builders.md
index 4077813..d3a6a7b 100644
--- a/docs/infra/cq_builders.md
+++ b/docs/infra/cq_builders.md
@@ -70,8 +70,6 @@
 
 * [win10_chromium_x64_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win10_chromium_x64_rel_ng) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win10_chromium_x64_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win10_chromium_x64_rel_ng))
 
-* [win7-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win7-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win7-rel))
-
 * [win_chromium_compile_dbg_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win_chromium_compile_dbg_ng) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win_chromium_compile_dbg_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win_chromium_compile_dbg_ng))
 
 
@@ -267,6 +265,10 @@
 
   * Experimental percentage: 40
 
+* [win7-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win7-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win7-rel))
+
+  * Experimental percentage: 10
+
 * [win7_chromium_rel_loc_exp](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7_chromium_rel_loc_exp) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win7_chromium_rel_loc_exp)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win7_chromium_rel_loc_exp))
 
   * Experimental percentage: 20
diff --git a/docs/profiling_content_shell_on_android.md b/docs/profiling_content_shell_on_android.md
index 73df8ff..8896505 100644
--- a/docs/profiling_content_shell_on_android.md
+++ b/docs/profiling_content_shell_on_android.md
@@ -24,7 +24,7 @@
 Plug in your device. Make sure you can talk to your device, try:
 
 ```shell
-third_party/android_tools/sdk/platform-tools/adb shell ls
+third_party/android_sdk/public/platform-tools/adb shell ls
 ```
 
 ## Root your device and install a userdebug build
diff --git a/docs/working_remotely_with_android.md b/docs/working_remotely_with_android.md
index f32817d..33fe5e3 100644
--- a/docs/working_remotely_with_android.md
+++ b/docs/working_remotely_with_android.md
@@ -29,7 +29,7 @@
 # Setup environment.
 
 laptop$ cd chrome_sshfs
-laptop$ third_party/android_tools/sdk/platform-tools/adb devices
+laptop$ third_party/android_sdk/public/platform-tools/adb devices
 
 # Run tests.
 
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index d98ea1d..a7f43659 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -144,8 +144,6 @@
     "guest_view/mime_handler_view/mime_handler_view_container_manager.h",
     "guest_view/mime_handler_view/mime_handler_view_frame_container.cc",
     "guest_view/mime_handler_view/mime_handler_view_frame_container.h",
-    "i18n_custom_bindings.cc",
-    "i18n_custom_bindings.h",
     "i18n_hooks_delegate.cc",
     "i18n_hooks_delegate.h",
     "i18n_hooks_util.cc",
@@ -266,8 +264,6 @@
     "script_injector.h",
     "scripts_run_info.cc",
     "scripts_run_info.h",
-    "send_request_natives.cc",
-    "send_request_natives.h",
     "service_worker_data.cc",
     "service_worker_data.h",
     "set_icon_natives.cc",
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index e837506..aa8495a 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -85,7 +85,6 @@
 #include "extensions/renderer/script_context_set.h"
 #include "extensions/renderer/script_injection.h"
 #include "extensions/renderer/script_injection_manager.h"
-#include "extensions/renderer/send_request_natives.h"
 #include "extensions/renderer/set_icon_natives.h"
 #include "extensions/renderer/static_v8_external_one_byte_string_resource.h"
 #include "extensions/renderer/test_features_native_handler.h"
@@ -760,12 +759,6 @@
       "apiDefinitions", std::unique_ptr<NativeHandler>(
                             new ApiDefinitionsNatives(dispatcher, context)));
   module_system->RegisterNativeHandler(
-      "sendRequest",
-      std::make_unique<SendRequestNatives>(
-          // Note: |bindings_system| can be null in unit tests.
-          bindings_system ? bindings_system->GetRequestSender() : nullptr,
-          context));
-  module_system->RegisterNativeHandler(
       "setIcon", std::unique_ptr<NativeHandler>(new SetIconNatives(context)));
   module_system->RegisterNativeHandler(
       "activityLogger", std::make_unique<APIActivityLogger>(context));
diff --git a/extensions/renderer/i18n_custom_bindings.cc b/extensions/renderer/i18n_custom_bindings.cc
deleted file mode 100644
index 12419758..0000000
--- a/extensions/renderer/i18n_custom_bindings.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/renderer/i18n_custom_bindings.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_thread.h"
-#include "extensions/renderer/i18n_hooks_util.h"
-#include "extensions/renderer/script_context.h"
-
-namespace extensions {
-
-I18NCustomBindings::I18NCustomBindings(ScriptContext* context)
-    : ObjectBackedNativeHandler(context) {}
-
-void I18NCustomBindings::AddRoutes() {
-  RouteHandlerFunction("GetL10nMessage", "i18n",
-                       base::BindRepeating(&I18NCustomBindings::GetL10nMessage,
-                                           base::Unretained(this)));
-  RouteHandlerFunction(
-      "GetL10nUILanguage", "i18n",
-      base::BindRepeating(&I18NCustomBindings::GetL10nUILanguage,
-                          base::Unretained(this)));
-  RouteHandlerFunction(
-      "DetectTextLanguage", "i18n",
-      base::BindRepeating(&I18NCustomBindings::DetectTextLanguage,
-                          base::Unretained(this)));
-}
-
-void I18NCustomBindings::GetL10nMessage(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  if (args.Length() != 3 || !args[0]->IsString()) {
-    NOTREACHED() << "Bad arguments";
-    return;
-  }
-
-  v8::Isolate* isolate = args.GetIsolate();
-  std::string extension_id;
-  if (args[2]->IsNull() || !args[2]->IsString()) {
-    return;
-  } else {
-    extension_id = *v8::String::Utf8Value(isolate, args[2]);
-    if (extension_id.empty())
-      return;
-  }
-
-  std::string message_name = *v8::String::Utf8Value(isolate, args[0]);
-  v8::Local<v8::Value> message = i18n_hooks::GetI18nMessage(
-      message_name, extension_id, args[1], context()->GetRenderFrame(),
-      context()->v8_context());
-  args.GetReturnValue().Set(message);
-}
-
-void I18NCustomBindings::GetL10nUILanguage(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args.GetReturnValue().Set(
-      v8::String::NewFromUtf8(args.GetIsolate(),
-                              content::RenderThread::Get()->GetLocale().c_str(),
-                              v8::NewStringType::kNormal)
-          .ToLocalChecked());
-}
-
-void I18NCustomBindings::DetectTextLanguage(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  CHECK(args.Length() == 1);
-  CHECK(args[0]->IsString());
-
-  std::string text = *v8::String::Utf8Value(args.GetIsolate(), args[0]);
-  v8::Local<v8::Value> detected_language =
-      i18n_hooks::DetectTextLanguage(context()->v8_context(), text);
-  args.GetReturnValue().Set(detected_language);
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/i18n_custom_bindings.h b/extensions/renderer/i18n_custom_bindings.h
deleted file mode 100644
index e2528cf..0000000
--- a/extensions/renderer/i18n_custom_bindings.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_RENDERER_I18N_CUSTOM_BINDINGS_H_
-#define EXTENSIONS_RENDERER_I18N_CUSTOM_BINDINGS_H_
-
-#include "extensions/renderer/object_backed_native_handler.h"
-
-namespace extensions {
-class ScriptContext;
-
-// Implements custom bindings for the i18n API.
-class I18NCustomBindings : public ObjectBackedNativeHandler {
- public:
-  explicit I18NCustomBindings(ScriptContext* context);
-
-  // ObjectBackedNativeHandler:
-  void AddRoutes() override;
-
- private:
-  void GetL10nMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
-  void GetL10nUILanguage(const v8::FunctionCallbackInfo<v8::Value>& args);
-  void DetectTextLanguage(const v8::FunctionCallbackInfo<v8::Value>& args);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_RENDERER_I18N_CUSTOM_BINDINGS_H_
diff --git a/extensions/renderer/runtime_custom_bindings.cc b/extensions/renderer/runtime_custom_bindings.cc
index 3c48477..780d63c 100644
--- a/extensions/renderer/runtime_custom_bindings.cc
+++ b/extensions/renderer/runtime_custom_bindings.cc
@@ -9,12 +9,7 @@
 #include <memory>
 
 #include "base/bind.h"
-#include "base/values.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/v8_value_converter.h"
 #include "extensions/common/extension.h"
-#include "extensions/common/extension_messages.h"
-#include "extensions/common/manifest.h"
 #include "extensions/renderer/extension_frame_helper.h"
 #include "extensions/renderer/script_context.h"
 
@@ -26,23 +21,12 @@
 RuntimeCustomBindings::~RuntimeCustomBindings() {}
 
 void RuntimeCustomBindings::AddRoutes() {
-  RouteHandlerFunction("GetManifest",
-                       base::BindRepeating(&RuntimeCustomBindings::GetManifest,
-                                           base::Unretained(this)));
   RouteHandlerFunction(
       "GetExtensionViews",
       base::BindRepeating(&RuntimeCustomBindings::GetExtensionViews,
                           base::Unretained(this)));
 }
 
-void RuntimeCustomBindings::GetManifest(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  CHECK(context()->extension());
-
-  args.GetReturnValue().Set(content::V8ValueConverter::Create()->ToV8Value(
-      context()->extension()->manifest()->value(), context()->v8_context()));
-}
-
 void RuntimeCustomBindings::GetExtensionViews(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   CHECK_EQ(args.Length(), 3);
diff --git a/extensions/renderer/runtime_custom_bindings.h b/extensions/renderer/runtime_custom_bindings.h
index 426e8c2..f1ecd0b 100644
--- a/extensions/renderer/runtime_custom_bindings.h
+++ b/extensions/renderer/runtime_custom_bindings.h
@@ -21,7 +21,6 @@
   void AddRoutes() override;
 
  private:
-  void GetManifest(const v8::FunctionCallbackInfo<v8::Value>& args);
   void GetExtensionViews(const v8::FunctionCallbackInfo<v8::Value>& args);
 };
 
diff --git a/extensions/renderer/send_request_natives.cc b/extensions/renderer/send_request_natives.cc
deleted file mode 100644
index 008811f2..0000000
--- a/extensions/renderer/send_request_natives.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/renderer/send_request_natives.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/json/json_reader.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/timer/elapsed_timer.h"
-#include "content/public/renderer/v8_value_converter.h"
-#include "extensions/renderer/request_sender.h"
-#include "extensions/renderer/script_context.h"
-
-namespace extensions {
-
-SendRequestNatives::SendRequestNatives(RequestSender* request_sender,
-                                       ScriptContext* context)
-    : ObjectBackedNativeHandler(context), request_sender_(request_sender) {}
-
-void SendRequestNatives::AddRoutes() {
-  RouteHandlerFunction("StartRequest",
-                       base::BindRepeating(&SendRequestNatives::StartRequest,
-                                           base::Unretained(this)));
-  RouteHandlerFunction("GetGlobal",
-                       base::BindRepeating(&SendRequestNatives::GetGlobal,
-                                           base::Unretained(this)));
-}
-
-// Starts an API request to the browser, with an optional callback.  The
-// callback will be dispatched to EventBindings::HandleResponse.
-void SendRequestNatives::StartRequest(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  base::ElapsedTimer timer;
-  CHECK_EQ(5, args.Length());
-  std::string name = *v8::String::Utf8Value(args.GetIsolate(), args[0]);
-  bool has_callback = args[2]->BooleanValue(context()->isolate());
-  bool for_io_thread = args[3]->BooleanValue(context()->isolate());
-  bool preserve_null_in_objects = args[4]->BooleanValue(context()->isolate());
-
-  int request_id = request_sender_->GetNextRequestId();
-  args.GetReturnValue().Set(static_cast<int32_t>(request_id));
-
-  std::unique_ptr<content::V8ValueConverter> converter =
-      content::V8ValueConverter::Create();
-
-  // See http://crbug.com/149880. The context menus APIs relies on this, but
-  // we shouldn't really be doing it (e.g. for the sake of the storage API).
-  converter->SetFunctionAllowed(true);
-
-  // See http://crbug.com/694248.
-  converter->SetConvertNegativeZeroToInt(true);
-
-  if (!preserve_null_in_objects)
-    converter->SetStripNullFromObjects(true);
-
-  std::unique_ptr<base::Value> value_args(
-      converter->FromV8Value(args[1], context()->v8_context()));
-  if (!value_args.get() || !value_args->is_list()) {
-    NOTREACHED() << "Unable to convert args passed to StartRequest";
-    return;
-  }
-
-  if (request_sender_->StartRequest(
-          context(),
-          name,
-          request_id,
-          has_callback,
-          for_io_thread,
-          static_cast<base::ListValue*>(value_args.get()))) {
-    // TODO(devlin): Would it be useful to partition this data based on
-    // extension function once we have a suitable baseline? crbug.com/608561.
-    UMA_HISTOGRAM_TIMES("Extensions.Functions.StartRequestElapsedTime",
-                        timer.Elapsed());
-  }
-}
-
-void SendRequestNatives::GetGlobal(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  CHECK_EQ(1, args.Length());
-  CHECK(args[0]->IsObject());
-  v8::Local<v8::Context> v8_context =
-      v8::Local<v8::Object>::Cast(args[0])->CreationContext();
-  if (ContextCanAccessObject(context()->v8_context(), v8_context->Global(),
-                             false)) {
-    args.GetReturnValue().Set(v8_context->Global());
-  }
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/send_request_natives.h b/extensions/renderer/send_request_natives.h
deleted file mode 100644
index 42909fe..0000000
--- a/extensions/renderer/send_request_natives.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_RENDERER_SEND_REQUEST_NATIVES_H_
-#define EXTENSIONS_RENDERER_SEND_REQUEST_NATIVES_H_
-
-#include "base/macros.h"
-#include "extensions/renderer/object_backed_native_handler.h"
-#include "v8/include/v8.h"
-
-namespace extensions {
-class RequestSender;
-class ScriptContext;
-
-// Native functions exposed to extensions via JS for calling API functions in
-// the browser.
-class SendRequestNatives : public ObjectBackedNativeHandler {
- public:
-  SendRequestNatives(RequestSender* request_sender, ScriptContext* context);
-
-  // ObjectBackedNativeHandler:
-  void AddRoutes() override;
-
- private:
-  // Starts an API request to the browser, with an optional callback.  The
-  // callback will be dispatched to EventBindings::HandleResponse.
-  void StartRequest(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // Gets a reference to an object's global object.
-  void GetGlobal(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  RequestSender* request_sender_;
-
-  DISALLOW_COPY_AND_ASSIGN(SendRequestNatives);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_RENDERER_SEND_REQUEST_NATIVES_H_
diff --git a/fuchsia/fidl/cast/application_config.fidl b/fuchsia/fidl/cast/application_config.fidl
index cc0b7dae..2bac3df4 100644
--- a/fuchsia/fidl/cast/application_config.fidl
+++ b/fuchsia/fidl/cast/application_config.fidl
@@ -5,20 +5,21 @@
 library chromium.cast;
 
 /// Describes the configuration under which a Cast application should run.
-struct ApplicationConfig {
+table ApplicationConfig {
   /// Cast application Id.
-  string id;
+  1: string id;
 
   /// Name to display to the user when referring to this application.
-  string display_name;
+  2: string display_name;
 
-  /// Standard web URL from which to load the application.
-  string web_url;
+  /// URL from which the application should be loaded, if it has a web-based
+  /// implementation.
+  3: string web_url;
 };
 
 /// Service interface for working with application configurations.
 [Discoverable]
 protocol ApplicationConfigManager {
   /// Returns the ApplicationConfig for the specified application Id.
-  GetConfig(string id) -> (ApplicationConfig? config);
+  GetConfig(string id) -> (ApplicationConfig config);
 };
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc
index 5ec7a1c7..5ed5be8 100644
--- a/fuchsia/runners/cast/cast_runner.cc
+++ b/fuchsia/runners/cast/cast_runner.cc
@@ -66,13 +66,14 @@
   pending_component->app_config_manager.set_error_handler(
       [this, pending_component = pending_component.get()](zx_status_t status) {
         ZX_LOG(ERROR, status) << "ApplicationConfigManager disconnected.";
-        GetConfigCallback(pending_component, nullptr);
+        GetConfigCallback(pending_component,
+                          chromium::cast::ApplicationConfig());
       });
 
   const std::string cast_app_id(cast_url.GetContent());
   pending_component->app_config_manager->GetConfig(
       cast_app_id, [this, pending_component = pending_component.get()](
-                       chromium::cast::ApplicationConfigPtr app_config) {
+                       chromium::cast::ApplicationConfig app_config) {
         GetConfigCallback(pending_component, std::move(app_config));
       });
 
@@ -84,7 +85,7 @@
 
 void CastRunner::GetConfigCallback(
     PendingComponent* pending_component,
-    chromium::cast::ApplicationConfigPtr app_config) {
+    chromium::cast::ApplicationConfig app_config) {
   // Ideally the PendingComponent would be move()d out of |pending_components_|
   // here, but that requires extract(), which isn't available until C++17.
   // Instead find |pending_component| and move() the individual fields out
@@ -93,7 +94,7 @@
   DCHECK(it != pending_components_.end());
 
   // If no configuration was returned then ignore the request.
-  if (!app_config) {
+  if (!app_config.has_web_url()) {
     pending_components_.erase(it);
     DLOG(WARNING) << "No ApplicationConfig was found.";
     return;
@@ -101,7 +102,7 @@
 
   // Create a component based on the returned configuration, and pass it the
   // fields stashed in PendingComponent.
-  GURL cast_app_url(app_config->web_url);
+  GURL cast_app_url(*app_config.web_url());
   auto component = std::make_unique<CastComponent>(
       this, std::move(pending_component->startup_context),
       std::move(pending_component->controller_request),
diff --git a/fuchsia/runners/cast/cast_runner.h b/fuchsia/runners/cast/cast_runner.h
index 7f57212d..40f5fdaf 100644
--- a/fuchsia/runners/cast/cast_runner.h
+++ b/fuchsia/runners/cast/cast_runner.h
@@ -38,7 +38,7 @@
   struct PendingComponent;
 
   void GetConfigCallback(PendingComponent* pending_component,
-                         chromium::cast::ApplicationConfigPtr app_config);
+                         chromium::cast::ApplicationConfig app_config);
 
   // Holds StartComponent() requests while the ApplicationConfig is being
   // fetched from the ApplicationConfigManager.
diff --git a/fuchsia/runners/cast/fake_application_config_manager.cc b/fuchsia/runners/cast/fake_application_config_manager.cc
index 8172e78..fd69458 100644
--- a/fuchsia/runners/cast/fake_application_config_manager.cc
+++ b/fuchsia/runners/cast/fake_application_config_manager.cc
@@ -17,15 +17,14 @@
                                              GetConfigCallback callback) {
   if (id_to_url_.find(id) == id_to_url_.end()) {
     LOG(ERROR) << "Unknown Cast App ID: " << id;
-    callback(chromium::cast::ApplicationConfigPtr());
+    callback(chromium::cast::ApplicationConfig());
     return;
   }
 
-  chromium::cast::ApplicationConfigPtr app_config =
-      chromium::cast::ApplicationConfig::New();
-  app_config->id = id;
-  app_config->display_name = "Dummy test app";
-  app_config->web_url = id_to_url_[id].spec();
+  chromium::cast::ApplicationConfig app_config;
+  app_config.set_id(id);
+  app_config.set_display_name("Dummy test app");
+  app_config.set_web_url(id_to_url_[id].spec());
 
   callback(std::move(app_config));
 }
diff --git a/gpu/command_buffer/common/gpu_memory_buffer_support.cc b/gpu/command_buffer/common/gpu_memory_buffer_support.cc
index 1dd2072..cb44d0d 100644
--- a/gpu/command_buffer/common/gpu_memory_buffer_support.cc
+++ b/gpu/command_buffer/common/gpu_memory_buffer_support.cc
@@ -94,6 +94,7 @@
 #elif defined(OS_WIN)
   return GL_TEXTURE_2D;
 #else
+  NOTREACHED();
   return 0;
 #endif
 }
diff --git a/gpu/command_buffer/tests/webgpu_fence_unittest.cc b/gpu/command_buffer/tests/webgpu_fence_unittest.cc
index bc2e96f..bf58540 100644
--- a/gpu/command_buffer/tests/webgpu_fence_unittest.cc
+++ b/gpu/command_buffer/tests/webgpu_fence_unittest.cc
@@ -54,7 +54,8 @@
 // Test that getting the value of the fence is the initial value.
 TEST_F(WebGPUFenceTest, InitialValue) {
   if (!WebGPUSupported()) {
-    GTEST_SKIP();
+    LOG(ERROR) << "Test skipped";
+    return;
   }
   dawn::Device device = dawn::Device::Acquire(webgpu()->GetDefaultDevice());
   dawn::Queue queue = device.CreateQueue();
@@ -73,7 +74,8 @@
 // Test that after signaling a fence, its completed value gets updated.
 TEST_F(WebGPUFenceTest, GetCompletedValue) {
   if (!WebGPUSupported()) {
-    GTEST_SKIP();
+    LOG(ERROR) << "Test skipped";
+    return;
   }
   dawn::Device device = dawn::Device::Acquire(webgpu()->GetDefaultDevice());
   dawn::Queue queue = device.CreateQueue();
@@ -88,7 +90,8 @@
 // is completed.
 TEST_F(WebGPUFenceTest, OnCompletion) {
   if (!WebGPUSupported()) {
-    GTEST_SKIP();
+    LOG(ERROR) << "Test skipped";
+    return;
   }
   dawn::Device device = dawn::Device::Acquire(webgpu()->GetDefaultDevice());
   dawn::Queue queue = device.CreateQueue();
@@ -107,7 +110,8 @@
 // Test signaling a fence a million times.
 TEST_F(WebGPUFenceTest, SignalManyTimes) {
   if (!WebGPUSupported()) {
-    GTEST_SKIP();
+    LOG(ERROR) << "Test skipped";
+    return;
   }
   dawn::Device device = dawn::Device::Acquire(webgpu()->GetDefaultDevice());
   dawn::Queue queue = device.CreateQueue();
diff --git a/gpu/command_buffer/tests/webgpu_test.cc b/gpu/command_buffer/tests/webgpu_test.cc
index fb51ce6..eacdd134 100644
--- a/gpu/command_buffer/tests/webgpu_test.cc
+++ b/gpu/command_buffer/tests/webgpu_test.cc
@@ -69,7 +69,8 @@
 
 TEST_F(WebGPUTest, Dummy) {
   if (!WebGPUSupported()) {
-    GTEST_SKIP();
+    LOG(ERROR) << "Test skipped";
+    return;
   }
   Initialize(WebGPUTest::Options());
   webgpu()->Dummy();
diff --git a/gpu/ipc/gl_in_process_context.cc b/gpu/ipc/gl_in_process_context.cc
index e0113d0..af3fde4f 100644
--- a/gpu/ipc/gl_in_process_context.cc
+++ b/gpu/ipc/gl_in_process_context.cc
@@ -72,7 +72,8 @@
   DCHECK_GE(attribs.offscreen_framebuffer_size.width(), 0);
   DCHECK_GE(attribs.offscreen_framebuffer_size.height(), 0);
 
-  command_buffer_ = std::make_unique<InProcessCommandBuffer>(task_executor);
+  command_buffer_ = std::make_unique<InProcessCommandBuffer>(
+      task_executor, GURL("chrome://gpu/GLInProcessContext::Initialize"));
 
   auto result = command_buffer_->Initialize(
       surface, is_offscreen, window, attribs, /*share_command_buffer=*/nullptr,
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 31d002e..32aaa0f 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -261,8 +261,10 @@
 };
 
 InProcessCommandBuffer::InProcessCommandBuffer(
-    CommandBufferTaskExecutor* task_executor)
+    CommandBufferTaskExecutor* task_executor,
+    const GURL& active_url)
     : command_buffer_id_(NextCommandBufferId()),
+      active_url_(active_url),
       flush_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                    base::WaitableEvent::InitialState::NOT_SIGNALED),
       task_executor_(task_executor),
@@ -386,6 +388,7 @@
     const InitializeOnGpuThreadParams& params) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
   TRACE_EVENT0("gpu", "InProcessCommandBuffer::InitializeOnGpuThread")
+  UpdateActiveUrl();
 
   if (gpu_channel_manager_delegate_ &&
       gpu_channel_manager_delegate_->IsExiting()) {
@@ -701,6 +704,7 @@
 bool InProcessCommandBuffer::DestroyOnGpuThread() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
   TRACE_EVENT0("gpu", "InProcessCommandBuffer::DestroyOnGpuThread");
+  UpdateActiveUrl();
 
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
@@ -790,6 +794,7 @@
 
 void InProcessCommandBuffer::RunTaskOnGpuThread(base::OnceClosure task) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+  UpdateActiveUrl();
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
   std::move(task).Run();
@@ -1269,6 +1274,8 @@
     uint32_t gpu_fence_id,
     const gfx::GpuFenceHandle& handle) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+  UpdateActiveUrl();
+
   if (!GetFeatureInfo()->feature_flags().chromium_gpu_fence) {
     DLOG(ERROR) << "CHROMIUM_gpu_fence unavailable";
     command_buffer_->SetParseError(error::kLostContext);
@@ -1574,4 +1581,9 @@
   update_vsync_parameters_completion_callback_ = callback;
 }
 
+void InProcessCommandBuffer::UpdateActiveUrl() {
+  if (!active_url_.is_empty())
+    ContextUrl::SetActiveUrl(active_url_);
+}
+
 }  // namespace gpu
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index cf9bdd9..95d8e07 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -39,6 +39,7 @@
 #include "gpu/config/gpu_preferences.h"
 #include "gpu/ipc/command_buffer_task_executor.h"
 #include "gpu/ipc/gl_in_process_context_export.h"
+#include "gpu/ipc/service/context_url.h"
 #include "gpu/ipc/service/image_transport_surface_delegate.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
@@ -84,7 +85,8 @@
       public DecoderClient,
       public ImageTransportSurfaceDelegate {
  public:
-  explicit InProcessCommandBuffer(CommandBufferTaskExecutor* task_executor);
+  InProcessCommandBuffer(CommandBufferTaskExecutor* task_executor,
+                         const GURL& active_url);
   ~InProcessCommandBuffer() override;
 
   // If |surface| is not null, use it directly; in this case, the command
@@ -298,6 +300,10 @@
                                     const SyncToken& sync_token);
   void DestroySharedImageOnGpuThread(const Mailbox& mailbox);
 
+  // Sets |active_url_| as the active GPU process URL. Should be called on GPU
+  // thread only.
+  void UpdateActiveUrl();
+
   // Callbacks on the gpu thread.
   void PerformDelayedWorkOnGpuThread();
 
@@ -311,6 +317,7 @@
   void HandleReturnDataOnOriginThread(std::vector<uint8_t> data);
 
   const CommandBufferId command_buffer_id_;
+  const ContextUrl active_url_;
 
   // Members accessed on the gpu thread (possibly with the exception of
   // creation):
diff --git a/gpu/ipc/raster_in_process_context.cc b/gpu/ipc/raster_in_process_context.cc
index 9eb11bd7..7e5ff70 100644
--- a/gpu/ipc/raster_in_process_context.cc
+++ b/gpu/ipc/raster_in_process_context.cc
@@ -61,7 +61,8 @@
   }
 
   client_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
-  command_buffer_ = std::make_unique<InProcessCommandBuffer>(task_executor);
+  command_buffer_ =
+      std::make_unique<InProcessCommandBuffer>(task_executor, GURL());
   auto result = command_buffer_->Initialize(
       nullptr /* surface */, true /* is_offscreen */, kNullSurfaceHandle,
       attribs, nullptr /* share_command_buffer */, gpu_memory_buffer_manager,
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 9316a1e3..7d93f74 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -15,6 +15,8 @@
   sources = [
     "command_buffer_stub.cc",
     "command_buffer_stub.h",
+    "context_url.cc",
+    "context_url.h",
     "gles2_command_buffer_stub.cc",
     "gles2_command_buffer_stub.h",
     "gpu_channel.cc",
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index de98b83..64a4029 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -102,27 +102,6 @@
 
 }  // namespace
 
-// FastSetActiveURL will shortcut the expensive call to SetActiveURL when the
-// url_hash matches.
-//
-// static
-void CommandBufferStub::FastSetActiveURL(const GURL& url,
-                                         size_t url_hash,
-                                         GpuChannel* channel) {
-  // Leave the previously set URL in the empty case -- empty URLs are given by
-  // BlinkPlatformImpl::createOffscreenGraphicsContext3DProvider. Hopefully the
-  // onscreen context URL was set previously and will show up even when a crash
-  // occurs during offscreen command processing.
-  if (url.is_empty())
-    return;
-  static size_t g_last_url_hash = 0;
-  if (url_hash != g_last_url_hash) {
-    g_last_url_hash = url_hash;
-    DCHECK(channel && channel->gpu_channel_manager() &&
-           channel->gpu_channel_manager()->delegate());
-    channel->gpu_channel_manager()->delegate()->SetActiveURL(url);
-  }
-}
 
 CommandBufferStub::CommandBufferStub(
     GpuChannel* channel,
@@ -134,7 +113,6 @@
     : channel_(channel),
       context_type_(init_params.attribs.context_type),
       active_url_(init_params.active_url),
-      active_url_hash_(base::Hash(active_url_.possibly_invalid_spec())),
       initialized_(false),
       surface_handle_(init_params.surface_handle),
       use_virtualized_gl_context_(false),
@@ -153,7 +131,7 @@
 bool CommandBufferStub::OnMessageReceived(const IPC::Message& message) {
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "GPUTask",
                "data", DevToolsChannelData::CreateForChannel(channel()));
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
@@ -241,7 +219,7 @@
 
 void CommandBufferStub::PerformWork() {
   TRACE_EVENT0("gpu", "CommandBufferStub::PerformWork");
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
@@ -344,7 +322,7 @@
 }
 
 void CommandBufferStub::Destroy() {
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
@@ -366,7 +344,8 @@
     if ((surface_handle_ == gpu::kNullSurfaceHandle) &&
         !active_url_.is_empty() &&
         !gpu_channel_manager->delegate()->IsExiting()) {
-      gpu_channel_manager->delegate()->DidDestroyOffscreenContext(active_url_);
+      gpu_channel_manager->delegate()->DidDestroyOffscreenContext(
+          active_url_.url());
     }
   }
 
@@ -435,7 +414,7 @@
   GpuChannelManager* gpu_channel_manager = channel_->gpu_channel_manager();
   gpu_channel_manager->delegate()->DidLoseContext(
       (surface_handle_ == kNullSurfaceHandle), state.context_lost_reason,
-      active_url_);
+      active_url_.url());
 
   CheckContextLost();
 }
@@ -526,7 +505,7 @@
 
   last_flush_id_ = flush_id;
   CommandBuffer::State pre_state = command_buffer_->GetState();
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
 
   MailboxManager* mailbox_manager =
       channel_->gpu_channel_manager()->mailbox_manager();
@@ -719,6 +698,15 @@
   return was_lost;
 }
 
+void CommandBufferStub::UpdateActiveUrl() {
+  // Leave the previously set URL in the empty case -- empty URLs are given by
+  // BlinkPlatformImpl::createOffscreenGraphicsContext3DProvider. Hopefully the
+  // onscreen context URL was set previously and will show up even when a crash
+  // occurs during offscreen command processing.
+  if (!active_url_.is_empty())
+    ContextUrl::SetActiveUrl(active_url_);
+}
+
 void CommandBufferStub::MarkContextLost() {
   if (!command_buffer_ ||
       command_buffer_->GetState().error == error::kLostContext)
diff --git a/gpu/ipc/service/command_buffer_stub.h b/gpu/ipc/service/command_buffer_stub.h
index 983b1f5..428d921 100644
--- a/gpu/ipc/service/command_buffer_stub.h
+++ b/gpu/ipc/service/command_buffer_stub.h
@@ -27,6 +27,7 @@
 #include "gpu/command_buffer/service/program_cache.h"
 #include "gpu/command_buffer/service/sequence_id.h"
 #include "gpu/ipc/common/surface_handle.h"
+#include "gpu/ipc/service/context_url.h"
 #include "gpu/ipc/service/gpu_ipc_service_export.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
@@ -144,11 +145,6 @@
 
  protected:
   virtual bool HandleMessage(const IPC::Message& message) = 0;
-  // FastSetActiveURL will shortcut the expensive call to SetActiveURL when the
-  // url_hash matches.
-  static void FastSetActiveURL(const GURL& url,
-                               size_t url_hash,
-                               GpuChannel* channel);
 
   std::unique_ptr<MemoryTracker> CreateMemoryTracker(
       const GPUCreateCommandBufferConfig& init_params) const;
@@ -160,14 +156,16 @@
   }
   bool CheckContextLost();
 
+  // Sets |active_url_| as the active GPU process URL.
+  void UpdateActiveUrl();
+
   // The lifetime of objects of this class is managed by a GpuChannel. The
   // GpuChannels destroy all the CommandBufferStubs that they own when
   // they are destroyed. So a raw pointer is safe.
   GpuChannel* const channel_;
 
   ContextType context_type_;
-  GURL active_url_;
-  size_t active_url_hash_;
+  ContextUrl active_url_;
 
   bool initialized_;
   const SurfaceHandle surface_handle_;
diff --git a/gpu/ipc/service/context_url.cc b/gpu/ipc/service/context_url.cc
new file mode 100644
index 0000000..16b597b
--- /dev/null
+++ b/gpu/ipc/service/context_url.cc
@@ -0,0 +1,33 @@
+// 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 "gpu/ipc/service/context_url.h"
+
+#include <utility>
+
+#include "base/hash.h"
+#include "components/crash/core/common/crash_key.h"
+
+namespace gpu {
+
+// static
+void ContextUrl::SetActiveUrl(const gpu::ContextUrl& active_url) {
+  // Skip setting crash key when URL hash hasn't changed.
+  static size_t last_url_hash = 0;
+  if (active_url.hash() == last_url_hash)
+    return;
+
+  last_url_hash = active_url.hash();
+
+  // Note that the url is intentionally excluded from webview crash dumps
+  // using a whitelist for privacy reasons. See kWebViewCrashKeyWhiteList.
+  static crash_reporter::CrashKeyString<1024> crash_key("url-chunk");
+  crash_key.Set(active_url.url().possibly_invalid_spec());
+}
+
+ContextUrl::ContextUrl(GURL url)
+    : url_(std::move(url)),
+      url_hash_(base::Hash(url_.possibly_invalid_spec())) {}
+
+}  // namespace gpu
diff --git a/gpu/ipc/service/context_url.h b/gpu/ipc/service/context_url.h
new file mode 100644
index 0000000..5c90126
--- /dev/null
+++ b/gpu/ipc/service/context_url.h
@@ -0,0 +1,38 @@
+// 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 GPU_IPC_SERVICE_CONTEXT_URL_H_
+#define GPU_IPC_SERVICE_CONTEXT_URL_H_
+
+#include "gpu/ipc/service/gpu_ipc_service_export.h"
+#include "url/gurl.h"
+
+namespace gpu {
+
+// Wrapper for GURL identifying a context.
+class GPU_IPC_SERVICE_EXPORT ContextUrl {
+ public:
+  // Sets the active URL crash key. This should be called when a context start
+  // doing work so that GPU process crashes can be associated back to the active
+  // context. This function is *not* thread safe and should only be called from
+  // GPU main thread.
+  //
+  // Note this caches the hash of last URL used to set crash key and skips
+  // setting crash key if |active_url| has the same hash.
+  static void SetActiveUrl(const ContextUrl& active_url);
+
+  explicit ContextUrl(GURL url);
+
+  const GURL& url() const { return url_; }
+  size_t hash() const { return url_hash_; }
+  bool is_empty() const { return url_.is_empty(); }
+
+ private:
+  GURL url_;
+  size_t url_hash_;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_IPC_SERVICE_CONTEXT_URL_H_
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index 14b17b0..58f18ae66 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -85,7 +85,7 @@
     const GPUCreateCommandBufferConfig& init_params,
     base::UnsafeSharedMemoryRegion shared_state_shm) {
   TRACE_EVENT0("gpu", "GLES2CommandBufferStub::Initialize");
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
 
   GpuChannelManager* manager = channel_->gpu_channel_manager();
   DCHECK(manager);
@@ -364,7 +364,7 @@
       std::move(shared_state_shm), std::move(shared_state_mapping)));
 
   if (offscreen && !active_url_.is_empty())
-    manager->delegate()->DidCreateOffscreenContext(active_url_);
+    manager->delegate()->DidCreateOffscreenContext(active_url_.url());
 
   if (use_virtualized_gl_context_) {
     // If virtualized GL contexts are in use, then real GL context state
diff --git a/gpu/ipc/service/gpu_channel_manager_delegate.h b/gpu/ipc/service/gpu_channel_manager_delegate.h
index a129472..74c1ab1 100644
--- a/gpu/ipc/service/gpu_channel_manager_delegate.h
+++ b/gpu/ipc/service/gpu_channel_manager_delegate.h
@@ -59,9 +59,6 @@
                                       SurfaceHandle child_window) = 0;
 #endif
 
-  // Sets the currently active URL.  Use GURL() to clear the URL.
-  virtual void SetActiveURL(const GURL& url) = 0;
-
  protected:
   virtual ~GpuChannelManagerDelegate() = default;
 };
diff --git a/gpu/ipc/service/gpu_channel_test_common.cc b/gpu/ipc/service/gpu_channel_test_common.cc
index c9e8273..24eef20 100644
--- a/gpu/ipc/service/gpu_channel_test_common.cc
+++ b/gpu/ipc/service/gpu_channel_test_common.cc
@@ -11,6 +11,7 @@
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/shared_image_manager.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/ipc/service/context_url.h"
 #include "gpu/ipc/service/gpu_channel.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
 #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
@@ -26,7 +27,6 @@
   ~TestGpuChannelManagerDelegate() override = default;
 
   // GpuChannelManagerDelegate implementation:
-  void SetActiveURL(const GURL& url) override {}
   void DidCreateContextSuccessfully() override {}
   void DidCreateOffscreenContext(const GURL& active_url) override {}
   void DidDestroyChannel(int client_id) override {}
diff --git a/gpu/ipc/service/raster_command_buffer_stub.cc b/gpu/ipc/service/raster_command_buffer_stub.cc
index 7f24495..7fd2cd3 100644
--- a/gpu/ipc/service/raster_command_buffer_stub.cc
+++ b/gpu/ipc/service/raster_command_buffer_stub.cc
@@ -69,7 +69,7 @@
     const GPUCreateCommandBufferConfig& init_params,
     base::UnsafeSharedMemoryRegion shared_state_shm) {
   TRACE_EVENT0("gpu", "RasterBufferStub::Initialize");
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
 
   GpuChannelManager* manager = channel_->gpu_channel_manager();
   DCHECK(manager);
@@ -170,7 +170,7 @@
       std::move(shared_state_shm), std::move(shared_state_mapping)));
 
   if (!active_url_.is_empty())
-    manager->delegate()->DidCreateOffscreenContext(active_url_);
+    manager->delegate()->DidCreateOffscreenContext(active_url_.url());
 
   manager->delegate()->DidCreateContextSuccessfully();
   initialized_ = true;
@@ -188,9 +188,8 @@
 void RasterCommandBufferStub::OnSwapBuffers(uint64_t swap_id, uint32_t flags) {}
 
 void RasterCommandBufferStub::SetActiveURL(GURL url) {
-  active_url_ = std::move(url);
-  active_url_hash_ = base::Hash(active_url_.possibly_invalid_spec());
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  active_url_ = ContextUrl(std::move(url));
+  UpdateActiveUrl();
 }
 
 }  // namespace gpu
diff --git a/gpu/ipc/service/webgpu_command_buffer_stub.cc b/gpu/ipc/service/webgpu_command_buffer_stub.cc
index 79c1a660..2241e15 100644
--- a/gpu/ipc/service/webgpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/webgpu_command_buffer_stub.cc
@@ -76,7 +76,7 @@
   return gpu::ContextResult::kFatalFailure;
 #else
   TRACE_EVENT0("gpu", "WebGPUBufferStub::Initialize");
-  FastSetActiveURL(active_url_, active_url_hash_, channel_);
+  UpdateActiveUrl();
 
   GpuChannelManager* manager = channel_->gpu_channel_manager();
   DCHECK(manager);
@@ -138,7 +138,7 @@
       std::move(shared_state_shm), std::move(shared_state_mapping)));
 
   if (!active_url_.is_empty())
-    manager->delegate()->DidCreateOffscreenContext(active_url_);
+    manager->delegate()->DidCreateOffscreenContext(active_url_.url());
 
   manager->delegate()->DidCreateContextSuccessfully();
   initialized_ = true;
diff --git a/gpu/ipc/webgpu_in_process_context.cc b/gpu/ipc/webgpu_in_process_context.cc
index 4a799d94..b20308b 100644
--- a/gpu/ipc/webgpu_in_process_context.cc
+++ b/gpu/ipc/webgpu_in_process_context.cc
@@ -53,7 +53,8 @@
   }
 
   client_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
-  command_buffer_ = std::make_unique<InProcessCommandBuffer>(task_executor);
+  command_buffer_ =
+      std::make_unique<InProcessCommandBuffer>(task_executor, GURL());
 
   static const scoped_refptr<gl::GLSurface> surface = nullptr;
   static constexpr bool is_offscreen = true;
diff --git a/infra/config/commit-queue.cfg b/infra/config/commit-queue.cfg
index f141bf3..26ba17ac 100644
--- a/infra/config/commit-queue.cfg
+++ b/infra/config/commit-queue.cfg
@@ -141,9 +141,6 @@
         name: "chromium/try/win10_chromium_x64_rel_ng"
       }
       builders {
-        name: "chromium/try/win7-rel"
-      }
-      builders {
         name: "chromium/try/win_chromium_compile_dbg_ng"
       }
 
@@ -316,6 +313,11 @@
         experiment_percentage: 40
       }
       builders {
+        name: "chromium/try/win7-rel"
+        # https://crbug.com/943372
+        experiment_percentage: 10
+      }
+      builders {
         name: "chromium/try/win7_chromium_rel_loc_exp"
         experiment_percentage: 20
       }
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index d68a31c5..ed6df48 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -129,7 +129,6 @@
     "//ios/chrome/browser/passwords:feature_flags",
     "//ios/chrome/browser/payments:constants",
     "//ios/chrome/browser/reading_list:features",
-    "//ios/chrome/browser/search_engines:feature_flags",
     "//ios/chrome/browser/signin:feature_flags",
     "//ios/chrome/browser/ssl:feature_flags",
     "//ios/chrome/browser/sync/glue",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 5f25107..380c459 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -53,7 +53,6 @@
 #include "ios/chrome/browser/find_in_page/features.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
 #include "ios/chrome/browser/reading_list/features.h"
-#include "ios/chrome/browser/search_engines/feature_flags.h"
 #include "ios/chrome/browser/signin/feature_flags.h"
 #include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/dialogs/dialog_features.h"
@@ -408,9 +407,6 @@
      flag_descriptions::kOmniboxPopupShortcutIconsInZeroStateDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxPopupShortcutIconsInZeroState)},
-    {"custom-search-engines", flag_descriptions::kCustomSearchEnginesName,
-     flag_descriptions::kCustomSearchEnginesDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kCustomSearchEngines)},
     {"use-multilogin-endpoint", flag_descriptions::kUseMultiloginEndpointName,
      flag_descriptions::kUseMultiloginEndpointDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kUseMultiloginEndpoint)},
@@ -571,6 +567,10 @@
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillNoLocalSaveOnUploadSuccess)},
+    {"display-search-engine-favicon",
+     flag_descriptions::kDisplaySearchEngineFaviconName,
+     flag_descriptions::kDisplaySearchEngineFaviconDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kDisplaySearchEngineFavicon)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/find_in_page/resources/find_in_page.js b/ios/chrome/browser/find_in_page/resources/find_in_page.js
index 8d6b53c..9a817564 100644
--- a/ios/chrome/browser/find_in_page/resources/find_in_page.js
+++ b/ios/chrome/browser/find_in_page/resources/find_in_page.js
@@ -11,9 +11,13 @@
  * selected one in orange color;
  */
 
-// Requires __crWeb.findInPage provided by __crWeb.allFramesWebBundle.
-
 (function() {
+/**
+   * Namespace for this file.
+   * This overrides the ios/web find in page implementation to ensure there are
+   * no unintended collisions.
+   */
+__gCrWeb.findInPage = {};
 
 /**
  * A string made by concatenating textContent.toLowerCase() of all TEXT nodes
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.h b/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
index 165e803..811ef92 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
@@ -26,6 +26,8 @@
   static void CreateForWebState(web::WebState* web_state);
   // Sets the InfobarBadgeTabHelperDelegate to |delegate|.
   void SetDelegate(id<InfobarBadgeTabHelperDelegate> delegate);
+  // Updates Infobar badge for the case where an InfobarBanner was dismissed.
+  void UpdateBadgeForInfobarBannerDismissed();
   // Updates Infobar badge for the case where an InfobarModal was presented.
   void UpdateBadgeForInfobarModalPresented();
   // Updates Infobar badge for the case where an InfobarModal was dismissed.
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
index 8f7e4f4..7df1683 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
@@ -31,6 +31,10 @@
   delegate_ = delegate;
 }
 
+void InfobarBadgeTabHelper::UpdateBadgeForInfobarBannerDismissed() {
+  delegate_.badgeState &= ~InfobarBadgeStateSelected;
+}
+
 void InfobarBadgeTabHelper::UpdateBadgeForInfobarModalPresented() {
   delegate_.badgeState |= InfobarBadgeStateSelected;
 }
@@ -64,7 +68,9 @@
 
 void InfobarBadgeTabHelper::OnInfoBarAdded(infobars::InfoBar* infobar) {
   this->UpdateBadgeForInfobar(infobar, true);
-  delegate_.badgeState = InfobarBadgeStateNone;
+  // Set the badgeState to selected since the InfobarBanner has be presented on
+  // OnInfoBarAdded.
+  delegate_.badgeState = InfobarBadgeStateSelected;
 }
 
 void InfobarBadgeTabHelper::OnInfoBarRemoved(infobars::InfoBar* infobar,
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index 3e771ce..374999c 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -244,6 +244,11 @@
     "A crash report will be uploaded if the main thread is frozen more than "
     "the time specified by this flag.";
 
+const char kDisplaySearchEngineFaviconName[] =
+    "Display search engine favicons.";
+const char kDisplaySearchEngineFaviconDescription[] =
+    "When enabled, Settings will display search engine favicons";
+
 const char kDragAndDropName[] = "Drag and Drop";
 const char kDragAndDropDescription[] = "Enable support for drag and drop.";
 
@@ -446,10 +451,6 @@
 const char kWKHTTPSystemCookieStoreDescription[] =
     "Use WKHTTPCookieStore backed store for main context URL requests.";
 
-const char kCustomSearchEnginesName[] = "Custom Search Engines";
-const char kCustomSearchEnginesDescription[] =
-    "When enabled, user can add custom search engines in settings.";
-
 const char kFindInPageiFrameName[] = "Find in Page in iFrames.";
 const char kFindInPageiFrameDescription[] =
     "When enabled, Find In Page will search in iFrames.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index ee15099..bf52875 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -188,6 +188,11 @@
 extern const char kCopiedContentBehaviorName[];
 extern const char kCopiedContentBehaviorDescription[];
 
+// Title and description for the flag to enable displaying search engine
+// favicons in Settings.
+extern const char kDisplaySearchEngineFaviconName[];
+extern const char kDisplaySearchEngineFaviconDescription[];
+
 // Title and description for the flag to enable drag and drop.
 extern const char kDragAndDropName[];
 extern const char kDragAndDropDescription[];
@@ -372,10 +377,6 @@
 extern const char kWKHTTPSystemCookieStoreName[];
 extern const char kWKHTTPSystemCookieStoreDescription[];
 
-// Title and description for the flag to allow custom search engines.
-extern const char kCustomSearchEnginesName[];
-extern const char kCustomSearchEnginesDescription[];
-
 // Title and description for the flag to search in iFrames in Find In Page.
 extern const char kFindInPageiFrameName[];
 extern const char kFindInPageiFrameDescription[];
diff --git a/ios/chrome/browser/search_engines/BUILD.gn b/ios/chrome/browser/search_engines/BUILD.gn
index 6ca2c26..6f45520 100644
--- a/ios/chrome/browser/search_engines/BUILD.gn
+++ b/ios/chrome/browser/search_engines/BUILD.gn
@@ -2,21 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/features.gni")
 import("//ios/web/js_compile.gni")
 import("//rlz/buildflags/buildflags.gni")
 
-source_set("feature_flags") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "feature_flags.cc",
-    "feature_flags.h",
-  ]
-  deps = [
-    "//base",
-  ]
-}
-
 source_set("search_engines") {
   sources = [
     "search_engine_observer_bridge.h",
diff --git a/ios/chrome/browser/search_engines/feature_flags.cc b/ios/chrome/browser/search_engines/feature_flags.cc
deleted file mode 100644
index 37b6688..0000000
--- a/ios/chrome/browser/search_engines/feature_flags.cc
+++ /dev/null
@@ -1,8 +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 "ios/chrome/browser/search_engines/feature_flags.h"
-
-const base::Feature kCustomSearchEngines{"CustomSearchEngines",
-                                         base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/search_engines/feature_flags.h b/ios/chrome/browser/search_engines/feature_flags.h
deleted file mode 100644
index 9323536..0000000
--- a/ios/chrome/browser/search_engines/feature_flags.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_SEARCH_ENGINES_FEATURE_FLAGS_H_
-#define IOS_CHROME_BROWSER_SEARCH_ENGINES_FEATURE_FLAGS_H_
-
-#include "base/feature_list.h"
-
-// Feature to allow user to add custom search engines.
-extern const base::Feature kCustomSearchEngines;
-
-#endif  // IOS_CHROME_BROWSER_SEARCH_ENGINES_FEATURE_FLAGS_H_
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
index ce923608..8073514 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge.mm
@@ -116,9 +116,14 @@
   network::mojom::CookieManager* cookie_manager =
       GetBrowserState()->GetCookieManager();
   for (NSHTTPCookie* cookie : cookies) {
+    net::CookieOptions options;
+    options.set_include_httponly();
+    // Permit it to set a SameSite cookie if it wants to.
+    options.set_same_site_cookie_context(
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
     cookie_manager->SetCanonicalCookie(
         net::CanonicalCookieFromSystemCookie(cookie, base::Time::Now()),
-        base::SysNSStringToUTF8(response.URL.scheme), /*modify_http_only=*/true,
+        base::SysNSStringToUTF8(response.URL.scheme), options,
         base::DoNothing());
   }
 }
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm
index 2eba13c..b6c8d34 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm
@@ -259,9 +259,13 @@
   network::mojom::CookieManager* cookie_manager =
       browser_state_->GetCookieManager();
   for (NSHTTPCookie* cookie in cookies) {
+    net::CookieOptions options;
+    options.set_include_httponly();
+    options.set_same_site_cookie_context(
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
     cookie_manager->SetCanonicalCookie(
         net::CanonicalCookieFromSystemCookie(cookie, base::Time::Now()),
-        "https", /*modify_http_only=*/true, base::DoNothing());
+        "https", options, base::DoNothing());
   }
   WaitForBackgroundTasks();
 }
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 1ca033f..553adc7 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -111,7 +111,6 @@
     "//ios/chrome/browser/prerender",
     "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/search_engines",
-    "//ios/chrome/browser/search_engines:feature_flags",
     "//ios/chrome/browser/sessions",
     "//ios/chrome/browser/sessions:serialisation",
     "//ios/chrome/browser/snapshots",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index 2a73c7d..b873f57 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -33,7 +33,6 @@
 #include "ios/chrome/browser/reading_list/features.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #import "ios/chrome/browser/reading_list/reading_list_web_state_observer.h"
-#import "ios/chrome/browser/search_engines/feature_flags.h"
 #import "ios/chrome/browser/search_engines/search_engine_tab_helper.h"
 #import "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
@@ -128,9 +127,7 @@
       PasswordTabHelper::FromWebState(web_state)->GetPasswordManager());
 
   // Depends on favicon::WebFaviconDriver, must be created after it.
-  if (base::FeatureList::IsEnabled(kCustomSearchEngines)) {
     SearchEngineTabHelper::CreateForWebState(web_state);
-  }
 
   FormSuggestionTabHelper::CreateForWebState(web_state, @[
     PasswordTabHelper::FromWebState(web_state)->GetSuggestionProvider(),
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn
index d5d6217bb..112d99e 100644
--- a/ios/chrome/browser/translate/BUILD.gn
+++ b/ios/chrome/browser/translate/BUILD.gn
@@ -110,7 +110,9 @@
     "//components/translate/core/browser",
     "//components/translate/core/common",
     "//components/translate/ios/browser",
+    "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/ui/translate",
     "//ios/chrome/browser/ui/translate:translate_ui",
     "//ios/chrome/test/app:test_support",
     "//ios/chrome/test/earl_grey:test_support",
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index 23b44ae..aa20772 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -5,6 +5,7 @@
 #import <XCTest/XCTest.h>
 
 #include <memory>
+#include <string>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -12,11 +13,13 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/language/ios/browser/ios_language_detection_tab_helper.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/browser/translate_pref_names.h"
+#include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/language_detection_details.h"
 #include "components/translate/core/common/translate_constants.h"
 #include "components/translate/core/common/translate_switches.h"
@@ -25,6 +28,9 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #include "ios/chrome/browser/ui/translate/language_selection_view_controller.h"
+#import "ios/chrome/browser/ui/translate/translate_infobar_coordinator.h"
+#import "ios/chrome/browser/ui/translate/translate_infobar_view.h"
+#include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #include "ios/chrome/test/app/navigation_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
@@ -33,19 +39,34 @@
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/web/public/test/earl_grey/js_test_util.h"
+#import "ios/web/public/test/earl_grey/web_view_matchers.h"
 #include "ios/web/public/test/http_server/data_response_provider.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "ios/web/public/test/http_server/http_server_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/url_util.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+using base::test::ios::WaitUntilConditionOrTimeout;
+using base::test::ios::kWaitForJSCompletionTimeout;
+using base::test::ios::kWaitForPageLoadTimeout;
+using base::test::ios::kWaitForUIElementTimeout;
+using chrome_test_util::ButtonWithAccessibilityLabel;
+using chrome_test_util::ButtonWithAccessibilityLabelId;
+using chrome_test_util::CloseButton;
+using chrome_test_util::TapWebViewElementWithId;
+
 namespace {
 
+// Paragraph height height for test pages. This must be large enough to trigger
+// the fullscreen mode.
+const int kParagraphHeightEM = 200;
+
 // Some text in English language.
 const char kEnglishText[] =
     "After flying to an altitude of 39,045 meters (128,100 feet) in a "
@@ -108,7 +129,68 @@
 // tags.
 std::string GetFrenchPageHtml(const std::string& html_tag,
                               const std::string& meta_tags) {
-  return html_tag + meta_tags + "<body>" + kFrenchText + "</body></html>";
+  return html_tag + meta_tags + "<body>" +
+         base::StringPrintf("<p style='height:%dem'>%s</p>", kParagraphHeightEM,
+                            kFrenchText) +
+         "</body></html>";
+}
+
+// Returns a matcher for the translate infobar view.
+id<GREYMatcher> TranslateInfobar() {
+  return grey_accessibilityID(kTranslateInfobarViewId);
+}
+
+// Returns a matcher for the translate infobar's options button.
+id<GREYMatcher> OptionsButton() {
+  return ButtonWithAccessibilityLabelId(
+      IDS_IOS_TRANSLATE_INFOBAR_OPTIONS_ACCESSIBILITY_LABEL);
+}
+
+// Returns a matcher for the translate options menu.
+id<GREYMatcher> OptionsMenu() {
+  return grey_accessibilityID(kTranslateOptionsPopupMenuId);
+}
+
+// Returns a matcher for the language selection menu.
+id<GREYMatcher> LanguagesMenu() {
+  return grey_accessibilityID(kLanguageSelectorPopupMenuId);
+}
+
+// Returns a matcher for the "More Languages" entry in translate options menu.
+id<GREYMatcher> MoreLanguages() {
+  return ButtonWithAccessibilityLabelId(
+      IDS_TRANSLATE_INFOBAR_OPTIONS_MORE_LANGUAGE);
+}
+
+// Returns a matcher for the "Always translate ..." entry in translate options
+// menu.
+id<GREYMatcher> AlwaysTranslate(NSString* language) {
+  return ButtonWithAccessibilityLabel(
+      l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_OPTIONS_ALWAYS,
+                              base::SysNSStringToUTF16(language)));
+}
+
+// Returns a matcher for the "Page not in ..." entry in translate options menu.
+id<GREYMatcher> PageNotIn(NSString* language) {
+  return ButtonWithAccessibilityLabel(
+      l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_OPTIONS_NOT_SOURCE_LANGUAGE,
+                              base::SysNSStringToUTF16(language)));
+}
+
+// Returns a matcher for the notification snackbar's "UNDO" button.
+id<GREYMatcher> UndoButton() {
+  return ButtonWithAccessibilityLabelId(IDS_TRANSLATE_NOTIFICATION_UNDO);
+}
+
+// Returns a matcher for an element with or without the
+// UIAccessibilityTraitSelected accessibility trait depending on |selected|.
+id<GREYMatcher> ElementIsSelected(BOOL selected) {
+  return grey_allOf(
+      grey_sufficientlyVisible(),
+      selected
+          ? grey_accessibilityTrait(UIAccessibilityTraitSelected)
+          : grey_not(grey_accessibilityTrait(UIAccessibilityTraitSelected)),
+      nil);
 }
 
 // Assigns the testing callback for the current WebState's language detection
@@ -177,14 +259,13 @@
         url.spec().c_str());
     return;
   } else if (url.path() == kFrenchPagePath) {
-    *response_body =
-        base::StringPrintf("<html><body>%s</body></html>", kFrenchText);
+    *response_body = GetFrenchPageHtml(kHtmlAttribute, "");
     return;
   } else if (url.path() == kFrenchPageWithLinkPath) {
     GURL page_path_url = web::test::HttpServer::MakeUrl(
         base::StringPrintf("http://%s", kFrenchPagePath));
     *response_body = base::StringPrintf(
-        "<html><body>%s<br /><a href='%s' id='link'>link</a></body></html>",
+        "<html><body>%s<br/><a href='%s' id='link'>link</a></body></html>",
         kFrenchText, page_path_url.spec().c_str());
     return;
   } else if (url.path() == kTranslateScriptPath) {
@@ -244,9 +325,6 @@
 
 }  // namespace
 
-using chrome_test_util::TapWebViewElementWithId;
-using translate::LanguageDetectionController;
-
 #pragma mark - MockTranslateScriptManager
 
 // Mock javascript translate manager that does not use the translate servers.
@@ -278,8 +356,16 @@
   // The test can check it to determine if this method has been called.
   _webState->ExecuteJavaScript(base::UTF8ToUTF16(
       "myButton = document.createElement('button');"
+      "myButton.setAttribute('id', 'translated-button');"
       "myButton.appendChild(document.createTextNode('Translated'));"
-      "document.body.appendChild(myButton);"));
+      "document.body.prepend(myButton);"));
+}
+
+- (void)revertTranslation {
+  // Removes the button with 'translated-button' id from the web page, if any.
+  _webState->ExecuteJavaScript(base::UTF8ToUTF16(
+      "myButton = document.getElementById('translated-button');"
+      "myButton.remove();"));
 }
 
 - (void)inject {
@@ -310,13 +396,29 @@
   std::unique_ptr<net::NetworkChangeNotifier::DisableForTest>
       network_change_notifier_disabler_;
   std::unique_ptr<FakeNetworkChangeNotifier> network_change_notifier_;
+  base::test::ScopedFeatureList feature_list_;
 }
 @end
 
 @implementation TranslateTestCase
 
++ (void)setUp {
+  [super setUp];
+
+  if (!base::FeatureList::IsEnabled(translate::kCompactTranslateInfobarIOS)) {
+    // translate::kCompactTranslateInfobarIOS feature is not enabled. You need
+    // to pass --enable-features=CompactTranslateInfobarIOS command line
+    // argument in order to run this test.
+    DCHECK(false);
+  }
+}
+
 - (void)setUp {
   [super setUp];
+
+  // Allow offering translate in builds without an API key.
+  translate::TranslateManager::SetIgnoreMissingKeyForTesting(true);
+
   language::IOSLanguageDetectionTabHelper::Callback copyDetailsCallback =
       base::BindRepeating(^(
           const translate::LanguageDetectionDetails& details) {
@@ -325,6 +427,14 @@
       });
   SetTestingLanguageDetectionCallback(copyDetailsCallback);
 
+  // Reset translate prefs to default.
+  std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+      ChromeIOSTranslateClient::CreateTranslatePrefs(
+          chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+  translatePrefs->ResetToDefaults();
+
+  [self setUpMockScriptManager];
+
   // Disable the net::NetworkChangeNotifier singleton and replace it with a
   // FakeNetworkChangeNotifier to simulate a WIFI network connection.
   network_change_notifier_disabler_ =
@@ -337,20 +447,40 @@
   SetTestingLanguageDetectionCallback(
       language::IOSLanguageDetectionTabHelper::Callback());
   _language_detection_details.reset();
-  // TODO(crbug.com/642892): Investigate moving into test-specific teardown.
-  // Re-enable translate.
-  chrome_test_util::SetBooleanUserPref(
-      chrome_test_util::GetOriginalBrowserState(),
-      prefs::kOfferTranslateEnabled, YES);
+
   // Reset translate prefs to default.
   std::unique_ptr<translate::TranslatePrefs> translatePrefs(
       ChromeIOSTranslateClient::CreateTranslatePrefs(
           chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
   translatePrefs->ResetToDefaults();
+
+  // Do not allow offering translate in builds without an API key.
   translate::TranslateManager::SetIgnoreMissingKeyForTesting(false);
+
   [super tearDown];
 }
 
+// Sets up MockTranslateScriptManager that does not use the translate script.
+- (void)setUpMockScriptManager {
+  // Set up the mock translate script manager.
+  ChromeIOSTranslateClient* client = ChromeIOSTranslateClient::FromWebState(
+      chrome_test_util::GetCurrentWebState());
+  translate::IOSTranslateDriver* driver =
+      static_cast<translate::IOSTranslateDriver*>(client->GetTranslateDriver());
+  MockTranslateScriptManager* jsTranslateManager =
+      [[MockTranslateScriptManager alloc]
+          initWithWebState:chrome_test_util::GetCurrentWebState()];
+  driver->translate_controller()->SetJsTranslateManagerForTesting(
+      jsTranslateManager);
+
+  // Set up a fake URL for the translate script to hit the mock HTTP server.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  GURL translateScriptURL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kTranslateScriptPath));
+  command_line->AppendSwitchASCII(translate::switches::kTranslateScriptURL,
+                                  translateScriptURL.spec().c_str());
+}
+
 #pragma mark - Test Cases
 
 // Tests that different language signals are detected correcty.
@@ -486,12 +616,12 @@
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
-  translate::LanguageDetectionDetails expectedLanguageDetails;
 
   // The HTTP header is detected.
   GURL URL = web::test::HttpServer::MakeUrl(std::string("http://") +
                                             kLanguagePath + "?http=fr");
   [ChromeEarlGrey loadURL:URL];
+  translate::LanguageDetectionDetails expectedLanguageDetails;
   expectedLanguageDetails.content_language = "fr";
   expectedLanguageDetails.adopted_language = "fr";
   [self assertLanguageDetails:expectedLanguageDetails];
@@ -526,7 +656,6 @@
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
-  translate::LanguageDetectionDetails expectedLanguageDetails;
 
   // Detection works when clicking on a link.
   GURL URL = web::test::HttpServer::MakeUrl(std::string("http://") + kLinkPath);
@@ -537,6 +666,7 @@
   [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
                                           someLanguageURL.GetContent())]
       assertWithMatcher:grey_notNil()];
+  translate::LanguageDetectionDetails expectedLanguageDetails;
   expectedLanguageDetails.content_language = "es";
   expectedLanguageDetails.adopted_language = "es";
   [self assertLanguageDetails:expectedLanguageDetails];
@@ -562,14 +692,13 @@
 
   if (@available(iOS 12, *)) {
     // TODO(crbug.com/874452) iOS12 has a bug where long pages take forever to
-    // load.  Add a 20 seconds timeout here.
+    // load. Use a 20 second timeout here.
     chrome_test_util::LoadUrl(URL);
     web::WebState* webState = chrome_test_util::GetCurrentWebState();
-    GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
-                   20,
-                   ^{
-                     return !webState->IsLoading();
-                   }),
+    GREYAssert(WaitUntilConditionOrTimeout(20,
+                                           ^{
+                                             return !webState->IsLoading();
+                                           }),
                @"Failed to load large page on iOS 12.");
     if (webState->ContentIsHTML())
       web::WaitUntilWindowIdInjected(webState);
@@ -603,15 +732,432 @@
   // Check that no language has been detected.
   GREYAssert(_language_detection_details.get() == nullptr,
              @"A language has been detected");
+
+  // Enable translate.
+  chrome_test_util::SetBooleanUserPref(
+      chrome_test_util::GetOriginalBrowserState(),
+      prefs::kOfferTranslateEnabled, YES);
+}
+
+// Tests that the infobar hides/shows as the browser enters/exits the fullscreen
+// mode as well as it can be dimissed.
+- (void)testInfobarShowHideDismiss {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [ChromeEarlGrey loadURL:URL];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // Scroll down to enter the fullscreen mode.
+  [[EarlGrey
+      selectElementWithMatcher:web::WebViewScrollView(
+                                   chrome_test_util::GetCurrentWebState())]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
+
+  // Expect the translate infobar to be hidden.
+  [[EarlGrey selectElementWithMatcher:TranslateInfobar()]
+      assertWithMatcher:grey_notVisible()];
+
+  // Scroll up to exit the fullscreen mode.
+  [[EarlGrey
+      selectElementWithMatcher:web::WebViewScrollView(
+                                   chrome_test_util::GetCurrentWebState())]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // Dismiss the translate infobar.
+  [[EarlGrey selectElementWithMatcher:CloseButton()] performAction:grey_tap()];
+
+  // Wait until the translate infobar disappears.
+  ConditionBlock condition = ^{
+    NSError* error = nil;
+    [[EarlGrey selectElementWithMatcher:TranslateInfobar()]
+        assertWithMatcher:grey_nil()
+                    error:&error];
+    return error == nil;
+  };
+  GREYAssert(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition),
+             @"Translate infobar failed to disappear.");
+}
+
+// Tests that the infobar's popup menu can be dimissed.
+- (void)testInfobarDismissPopupMenu {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [ChromeEarlGrey loadURL:URL];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Expect the translate options menu to have appeared.
+  [[EarlGrey selectElementWithMatcher:OptionsMenu()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // When the popup menu is visible, a scrim covers the whole window and tapping
+  // it dismisses the popup menu. The options button is outside of the bounds of
+  // the popup menu and is a convenient place to tap to activate the scrim.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Expect the translate options menu to have disappeared.
+  [[EarlGrey selectElementWithMatcher:OptionsMenu()]
+      assertWithMatcher:grey_nil()];
+}
+
+// Tests that the page can be translated and that translation can be reverted
+// using the source and the target language tabs.
+- (void)testInfobarTranslateRevert {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [ChromeEarlGrey loadURL:URL];
+
+  [self translateThenRevert];
+}
+
+// Tests that the page can be translated and that translation can be reverted
+// using the source and the target language tabs in incognito mode.
+- (void)testInfobarTranslateRevertIncognito {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text in an incognito tab.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [ChromeEarlGrey openNewIncognitoTab];
+  [ChromeEarlGrey loadURL:URL];
+
+  // Needed for the incognito WebState.
+  [self setUpMockScriptManager];
+
+  [self translateThenRevert];
+}
+
+// Translates the page and reverts the translation using the language tabs.
+- (void)translateThenRevert {
+  [self assertTranslateInfobarIsVisible];
+
+  // Make sure the page is not translated.
+  [ChromeEarlGrey waitForWebViewNotContainingText:"Translated"];
+
+  // The source language tab must be selected and the target language tab must
+  // not. Translate the page by tapping the target language tab.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:ElementIsSelected(YES)];
+  [[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(NO)] performAction:grey_tap()];
+
+  // Make sure the page is translated.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+
+  // The target language tab must be selected and the source language tab must
+  // not. Revert the translation by tapping the source language tab.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(YES)];
+  [[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:ElementIsSelected(NO)] performAction:grey_tap()];
+
+  // Make sure the translation is reverted.
+  [ChromeEarlGrey waitForWebViewNotContainingText:"Translated"];
+
+  // The source language tab must be selected and the target language tab must
+  // not.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:ElementIsSelected(YES)];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(NO)];
+}
+
+// Tests that translation occurs automatically on second navigation to an
+// already translated page.
+- (void)testInfobarAutoTranslate {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text and a link.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPageWithLinkPath));
+  [ChromeEarlGrey loadURL:URL];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // Make sure the page is not translated.
+  [ChromeEarlGrey waitForWebViewNotContainingText:"Translated"];
+
+  // The target language tab must not be selected. Translate the page by
+  // tapping the target language tab.
+  [[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(NO)] performAction:grey_tap()];
+
+  // Make sure the page is translated.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+
+  // Click on the link.
+  [ChromeEarlGrey tapWebViewElementWithID:@"link"];
+
+  // Make sure the navigation is completed.
+  GURL frenchPagePathURL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
+                                          frenchPagePathURL.GetContent())]
+      assertWithMatcher:grey_notNil()];
+
+  // Make sure the page is automatically translated.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+}
+
+// Tests that the source and the target languages can be changed.
+- (void)testInfobarChangeLanguages {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [ChromeEarlGrey loadURL:URL];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // The source language tab must be selected and the target language tab must
+  // not.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:ElementIsSelected(YES)];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(NO)];
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Expect the translate options menu to have appeared.
+  [[EarlGrey selectElementWithMatcher:OptionsMenu()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Select the "More Languages" entry in the options popup menu.
+  [[EarlGrey selectElementWithMatcher:MoreLanguages()]
+      performAction:grey_tap()];
+
+  // Expect the translate options menu to have disappeared.
+  [[EarlGrey selectElementWithMatcher:OptionsMenu()]
+      assertWithMatcher:grey_nil()];
+
+  // Expect the language selection menu to have appeared.
+  [[EarlGrey selectElementWithMatcher:LanguagesMenu()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Select "Dutch" from the the popup menu.
+  [[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"Dutch")]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+      onElementWithMatcher:LanguagesMenu()] performAction:grey_tap()];
+
+  // Expect the language selection menu to have disappeared.
+  [[EarlGrey selectElementWithMatcher:LanguagesMenu()]
+      assertWithMatcher:grey_nil()];
+
+  // Make sure the page is translated.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+
+  // Make sure the target language changes to "Dutch". The target language
+  // tab must be selected and the source language tab must not. Revert the
+  // translation by tapping the source language tab.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"Dutch")]
+      assertWithMatcher:ElementIsSelected(YES)];
+  [[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:ElementIsSelected(NO)] performAction:grey_tap()];
+
+  // Make sure the translation is reverted.
+  [ChromeEarlGrey waitForWebViewNotContainingText:"Translated"];
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Select the "Page not in French" entry in the options popup menu.
+  [[EarlGrey selectElementWithMatcher:PageNotIn(@"French")]
+      performAction:grey_tap()];
+
+  // Expect the translate options menu to have disappeared.
+  [[EarlGrey selectElementWithMatcher:OptionsMenu()]
+      assertWithMatcher:grey_nil()];
+
+  // Expect the language selection menu to have appeared.
+  [[EarlGrey selectElementWithMatcher:LanguagesMenu()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Select "English" from the the popup menu.
+  [[[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+      onElementWithMatcher:LanguagesMenu()] performAction:grey_tap()];
+
+  // Make sure the page is translated.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+
+  // Make sure the source language changes to "English". The target language
+  // tab must be selected and the source language tab must not.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(NO)];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"Dutch")]
+      assertWithMatcher:ElementIsSelected(YES)];
+}
+
+// Tests that the "Always Translate" options can be toggled and the prefs are
+// updated accordingly.
+- (void)testInfobarAlwaysTranslate {
+  // Start the HTTP server.
+  std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
+  web::test::SetUpHttpServer(std::move(provider));
+
+  // Load a page with French text.
+  GURL URL = web::test::HttpServer::MakeUrl(
+      base::StringPrintf("http://%s", kFrenchPagePath));
+  [ChromeEarlGrey loadURL:URL];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // Make sure that French to English translation is not whitelisted.
+  std::unique_ptr<translate::TranslatePrefs> translatePrefs(
+      ChromeIOSTranslateClient::CreateTranslatePrefs(
+          chrome_test_util::GetOriginalBrowserState()->GetPrefs()));
+  GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("fr", "en"),
+             @"French to English translation is whitelisted");
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Make sure the "Always Translate French" entry is not selected and tap it.
+  [[[EarlGrey selectElementWithMatcher:AlwaysTranslate(@"French")]
+      assertWithMatcher:ElementIsSelected(NO)] performAction:grey_tap()];
+
+  // Expect the translate options menu to have disappeared.
+  [[EarlGrey selectElementWithMatcher:OptionsMenu()]
+      assertWithMatcher:grey_nil()];
+
+  // Make sure the page is not translated yet.
+  [ChromeEarlGrey waitForWebViewNotContainingText:"Translated"];
+
+  // Make sure that French to English translation is not whitelisted yet.
+  GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("fr", "en"),
+             @"French to English translation is whitelisted");
+
+  // Tap the notification snackbar to dismiss it.
+  NSString* snackbarTitle =
+      l10n_util::GetNSStringF(IDS_TRANSLATE_NOTIFICATION_ALWAYS_TRANSLATE,
+                              base::SysNSStringToUTF16(@"French"),
+                              base::SysNSStringToUTF16(@"English"));
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarTitle)]
+      performAction:grey_tap()];
+
+  // Make sure the page is translated after the snackbar is dismissed.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+
+  // Make sure that French to English translation is whitelisted after the
+  // snackbar is dismissed.
+  GREYAssert(translatePrefs->IsLanguagePairWhitelisted("fr", "en"),
+             @"French to English translation is not whitelisted");
+
+  // Reload the page.
+  [ChromeEarlGrey reload];
+
+  [self assertTranslateInfobarIsVisible];
+
+  // Make sure the page is translated.
+  [ChromeEarlGrey waitForWebViewContainingText:"Translated"];
+
+  // The target language tab must be selected and the source language tab must
+  // not.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:ElementIsSelected(NO)];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:ElementIsSelected(YES)];
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Make sure the "Always Translate French" entry is now selected and tap it.
+  [[[EarlGrey selectElementWithMatcher:AlwaysTranslate(@"French")]
+      assertWithMatcher:ElementIsSelected(YES)] performAction:grey_tap()];
+
+  // Make sure that French to English translation is no longer whitelisted.
+  GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("fr", "en"),
+             @"French to English translation is whitelisted");
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Make sure the "Always Translate French" entry is not selected and tap it.
+  [[[EarlGrey selectElementWithMatcher:AlwaysTranslate(@"French")]
+      assertWithMatcher:ElementIsSelected(NO)] performAction:grey_tap()];
+
+  // Tap the notification snackbar's "UNDO" button.
+  [[EarlGrey selectElementWithMatcher:UndoButton()] performAction:grey_tap()];
+
+  // Open the translate options menu.
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      performAction:grey_tap()];
+
+  // Make sure the "Always Translate French" entry is still not selected.
+  [[EarlGrey selectElementWithMatcher:AlwaysTranslate(@"French")]
+      assertWithMatcher:ElementIsSelected(NO)];
+
+  // Make sure that French to English translation is not whitelisted.
+  GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("fr", "en"),
+             @"French to English translation is whitelisted");
 }
 
 #pragma mark - Utility methods
 
+- (void)assertTranslateInfobarIsVisible {
+  // Wait until the translate infobar becomes visible.
+  ConditionBlock condition = ^{
+    NSError* error = nil;
+    [[EarlGrey selectElementWithMatcher:TranslateInfobar()]
+        assertWithMatcher:grey_notNil()
+                    error:&error];
+    return error == nil;
+  };
+  GREYAssert(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, condition),
+             @"Translate infobar failed to show.");
+
+  // Check that the translate infobar is fully visible.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"French")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabel(@"English")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:OptionsButton()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:CloseButton()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
 // Waits until a language has been detected and checks the language details.
 - (void)assertLanguageDetails:
     (const translate::LanguageDetectionDetails&)expectedDetails {
-  GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
-                 2.0,
+  GREYAssert(WaitUntilConditionOrTimeout(
+                 kWaitForJSCompletionTimeout,
                  ^{
                    return _language_detection_details.get() != nullptr;
                  }),
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
index 67ee499..d38080d 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
@@ -14,9 +14,9 @@
 namespace {
 // Banner View constants.
 const CGFloat kBannerViewCornerRadius = 13.0;
-const CGFloat kBannerViewYShadowOffset = 5.0;
-const CGFloat kBannerViewShadowRadius = 3.0;
-const CGFloat kBannerViewShadowOpactiy = 0.08;
+const CGFloat kBannerViewYShadowOffset = 4.0;
+const CGFloat kBannerViewShadowRadius = 6.0;
+const CGFloat kBannerViewShadowOpactiy = 0.2;
 
 // Bottom Grip constants.
 const CGFloat kBottomGripCornerRadius = 0.2;
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
index f989fc6..92e39a60 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
@@ -119,6 +119,7 @@
   [self.bannerViewController.presentingViewController
       dismissViewControllerAnimated:YES
                          completion:^{
+                           [self.badgeDelegate infobarBannerWasDismissed];
                            self.bannerTransitionDriver = nil;
                          }];
 }
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
index 4a03481..ccd91a4 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
@@ -128,6 +128,7 @@
   [self.bannerViewController.presentingViewController
       dismissViewControllerAnimated:YES
                          completion:^{
+                           [self.badgeDelegate infobarBannerWasDismissed];
                            self.bannerTransitionDriver = nil;
                          }];
 }
diff --git a/ios/chrome/browser/ui/infobars/infobar_badge_ui_delegate.h b/ios/chrome/browser/ui/infobars/infobar_badge_ui_delegate.h
index a6d3f88..fc24414b 100644
--- a/ios/chrome/browser/ui/infobars/infobar_badge_ui_delegate.h
+++ b/ios/chrome/browser/ui/infobars/infobar_badge_ui_delegate.h
@@ -10,6 +10,9 @@
 // Delegate that handles any followup actions to Infobar UI events.
 @protocol InfobarBadgeUIDelegate
 
+// Called whenever an InfobarBanner was dismissed.
+- (void)infobarBannerWasDismissed;
+
 // Called whenever an InfobarModal was presented.
 - (void)infobarModalWasPresented;
 
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm b/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm
index 20db11b..8002bdb 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm
@@ -137,6 +137,17 @@
 
 #pragma mark - InfobarBadgeUIDelegate
 
+- (void)infobarBannerWasDismissed {
+  if (IsInfobarUIRebootEnabled()) {
+    web::WebState* webState = self.webStateList->GetActiveWebState();
+    DCHECK(webState);
+    InfobarBadgeTabHelper* infobarBadgeTabHelper =
+        InfobarBadgeTabHelper::FromWebState(webState);
+    DCHECK(infobarBadgeTabHelper);
+    infobarBadgeTabHelper->UpdateBadgeForInfobarBannerDismissed();
+  }
+}
+
 - (void)infobarModalWasPresented {
   if (IsInfobarUIRebootEnabled()) {
     web::WebState* webState = self.webStateList->GetActiveWebState();
diff --git a/ios/chrome/browser/ui/infobars/presentation/infobar_banner_animator.mm b/ios/chrome/browser/ui/infobars/presentation/infobar_banner_animator.mm
index c49b7b9..820cc809 100644
--- a/ios/chrome/browser/ui/infobars/presentation/infobar_banner_animator.mm
+++ b/ios/chrome/browser/ui/infobars/presentation/infobar_banner_animator.mm
@@ -51,6 +51,7 @@
     CGRect presentedViewStartFrame = presentedViewFinalFrame;
     presentedViewStartFrame.origin.y = -CGRectGetWidth(containerView.bounds);
     presentedView.frame = presentedViewStartFrame;
+    presentedView.alpha = 0;
   } else {
     presentedViewFinalFrame = presentedView.frame;
     presentedViewFinalFrame.origin.y = -CGRectGetWidth(containerView.bounds);
@@ -64,6 +65,7 @@
       options:UIViewAnimationOptionTransitionNone
       animations:^{
         presentedView.frame = presentedViewFinalFrame;
+        presentedView.alpha = 1;
       }
       completion:^(BOOL finished) {
         BOOL success = ![transitionContext transitionWasCancelled];
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index 37ec6770..663d272 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -524,7 +524,7 @@
 // Tests that sharing a web page to the Reading List results in a snackbar
 // appearing, and that the Reading List entry is present in the Reading List.
 // Loads offline version via context menu.
-- (void)DISABLED_testSavingToReadingListAndLoadDistilled {
+- (void)testSavingToReadingListAndLoadDistilled {
   auto network_change_disabler =
       std::make_unique<net::NetworkChangeNotifier::DisableForTest>();
   auto wifi_network = std::make_unique<WifiNetworkChangeNotifier>();
@@ -606,7 +606,7 @@
 // Tests that sharing a web page to the Reading List results in a snackbar
 // appearing, and that the Reading List entry is present in the Reading List.
 // Loads offline version by tapping on entry without web server.
-- (void)DISABLED_testSavingToReadingListAndLoadNoNetwork {
+- (void)testSavingToReadingListAndLoadNoNetwork {
   auto network_change_disabler =
       std::make_unique<net::NetworkChangeNotifier::DisableForTest>();
   auto wifi_network = std::make_unique<WifiNetworkChangeNotifier>();
@@ -653,7 +653,7 @@
 // Tests that sharing a web page to the Reading List results in a snackbar
 // appearing, and that the Reading List entry is present in the Reading List.
 // Loads offline version by tapping on entry with delayed web server.
-- (void)DISABLED_testSavingToReadingListAndLoadBadNetwork {
+- (void)testSavingToReadingListAndLoadBadNetwork {
   auto network_change_disabler =
       std::make_unique<net::NetworkChangeNotifier::DisableForTest>();
   auto wifi_network = std::make_unique<WifiNetworkChangeNotifier>();
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.h b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.h
index ccd7208..6646c80 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.h
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.h
@@ -84,8 +84,10 @@
 
 // Fills |model| with appropriate sections and items.
 - (void)loadModel:(ListModel*)model;
+
 // Returns a ActionSheetCoordinator that has action block to clear data of type
 // |dataTypeMaskToRemove|.
+// When action triggered by a UIButton.
 - (ActionSheetCoordinator*)
     actionSheetCoordinatorWithDataTypesToRemove:
         (BrowsingDataRemoveMask)dataTypeMaskToRemove
@@ -93,6 +95,15 @@
                                  (UIViewController*)baseViewController
                                      sourceRect:(CGRect)sourceRect
                                      sourceView:(UIView*)sourceView;
+// When action triggered by a UIBarButtonItem.
+- (ActionSheetCoordinator*)
+    actionSheetCoordinatorWithDataTypesToRemove:
+        (BrowsingDataRemoveMask)dataTypeMaskToRemove
+                             baseViewController:
+                                 (UIViewController*)baseViewController
+                            sourceBarButtonItem:
+                                (UIBarButtonItem*)sourceBarButtonItem;
+
 // Get the text to be displayed by a counter from the given |result|
 - (NSString*)counterTextFromResult:
     (const browsing_data::BrowsingDataCounter::Result&)result;
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
index f2c02ad..18624ab 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
@@ -225,34 +225,32 @@
                                  (UIViewController*)baseViewController
                                      sourceRect:(CGRect)sourceRect
                                      sourceView:(UIView*)sourceView {
-  if (dataTypeMaskToRemove == BrowsingDataRemoveMask::REMOVE_NOTHING) {
-    // Nothing to clear (no data types selected).
-    return nil;
-  }
-  __weak ClearBrowsingDataManager* weakSelf = self;
-  ActionSheetCoordinator* actionCoordinator = [[ActionSheetCoordinator alloc]
-      initWithBaseViewController:baseViewController
-                           title:l10n_util::GetNSString(
-                                     IDS_IOS_CONFIRM_CLEAR_BUTTON_TITLE)
-                         message:nil
-                            rect:sourceRect
-                            view:sourceView];
-  actionCoordinator.popoverArrowDirection =
-      UIPopoverArrowDirectionDown | UIPopoverArrowDirectionUp;
-  [actionCoordinator
-      addItemWithTitle:l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)
-                action:^{
-                  [weakSelf clearDataForDataTypes:dataTypeMaskToRemove];
-                }
-                 style:UIAlertActionStyleDestructive];
-  [actionCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
-                               action:nil
-                                style:UIAlertActionStyleCancel];
+  return [self actionSheetCoordinatorWithDataTypesToRemove:dataTypeMaskToRemove
+                                        baseViewController:baseViewController
+                                                sourceRect:sourceRect
+                                                sourceView:sourceView
+                                       sourceBarButtonItem:nil];
+}
 
-  return actionCoordinator;
+- (ActionSheetCoordinator*)
+    actionSheetCoordinatorWithDataTypesToRemove:
+        (BrowsingDataRemoveMask)dataTypeMaskToRemove
+                             baseViewController:
+                                 (UIViewController*)baseViewController
+                            sourceBarButtonItem:
+                                (UIBarButtonItem*)sourceBarButtonItem {
+  return [self actionSheetCoordinatorWithDataTypesToRemove:dataTypeMaskToRemove
+                                        baseViewController:baseViewController
+                                                sourceRect:CGRectNull
+                                                sourceView:nil
+                                       sourceBarButtonItem:sourceBarButtonItem];
 }
 
 - (void)addClearDataButtonToModel:(ListModel*)model {
+  if (self.listType == ClearBrowsingDataListType::kListTypeTableView &&
+      IsNewClearBrowsingDataUIEnabled()) {
+    return;
+  }
   // Clear Browsing Data button.
   ListItem* clearButtonItem = [self clearButtonItem];
   [model addSectionWithIdentifier:SectionIdentifierClearBrowsingDataButton];
@@ -582,6 +580,57 @@
   }
 }
 
+// Internal helper method which constructs an ActionSheetCoordinator for the two
+// |actionSheetCoordinatorWithDataTypesToRemove:...| in the interface.
+- (ActionSheetCoordinator*)
+    actionSheetCoordinatorWithDataTypesToRemove:
+        (BrowsingDataRemoveMask)dataTypeMaskToRemove
+                             baseViewController:
+                                 (UIViewController*)baseViewController
+                                     sourceRect:(CGRect)sourceRect
+                                     sourceView:(UIView*)sourceView
+                            sourceBarButtonItem:
+                                (UIBarButtonItem*)sourceBarButtonItem {
+  if (dataTypeMaskToRemove == BrowsingDataRemoveMask::REMOVE_NOTHING) {
+    // Nothing to clear (no data types selected).
+    return nil;
+  }
+  __weak ClearBrowsingDataManager* weakSelf = self;
+
+  ActionSheetCoordinator* actionCoordinator;
+  if (sourceBarButtonItem) {
+    DCHECK(!sourceView);
+    actionCoordinator = [[ActionSheetCoordinator alloc]
+        initWithBaseViewController:baseViewController
+                             title:l10n_util::GetNSString(
+                                       IDS_IOS_CONFIRM_CLEAR_BUTTON_TITLE)
+                           message:nil
+                     barButtonItem:sourceBarButtonItem];
+  } else {
+    DCHECK(!sourceBarButtonItem);
+    actionCoordinator = [[ActionSheetCoordinator alloc]
+        initWithBaseViewController:baseViewController
+                             title:l10n_util::GetNSString(
+                                       IDS_IOS_CONFIRM_CLEAR_BUTTON_TITLE)
+                           message:nil
+                              rect:sourceRect
+                              view:sourceView];
+  }
+
+  actionCoordinator.popoverArrowDirection =
+      UIPopoverArrowDirectionDown | UIPopoverArrowDirectionUp;
+  [actionCoordinator
+      addItemWithTitle:l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)
+                action:^{
+                  [weakSelf clearDataForDataTypes:dataTypeMaskToRemove];
+                }
+                 style:UIAlertActionStyleDestructive];
+  [actionCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+                               action:nil
+                                style:UIAlertActionStyleCancel];
+  return actionCoordinator;
+}
+
 #pragma mark Properties
 
 - (void)setShouldShowNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)showNotice
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
index c6daf06d..d4c2854ed 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
@@ -9,6 +9,7 @@
 #include "base/metrics/user_metrics_action.h"
 #include "components/prefs/pref_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
@@ -58,6 +59,8 @@
 // Reference to clear browsing data button for positioning popover confirmation
 // dialog.
 @property(nonatomic, strong) UIButton* clearBrowsingDataButton;
+@property(nonatomic, readonly, strong)
+    UIBarButtonItem* clearBrowsingDataBarButton;
 
 // Modal alert for Browsing history removed dialog.
 @property(nonatomic, strong) AlertCoordinator* alertCoordinator;
@@ -74,6 +77,7 @@
 @synthesize alertCoordinator = _alertCoordinator;
 @synthesize browserState = _browserState;
 @synthesize clearBrowsingDataButton = _clearBrowsingDataButton;
+@synthesize clearBrowsingDataBarButton = _clearBrowsingDataBarButton;
 @synthesize dataManager = _dataManager;
 @synthesize dispatcher = _dispatcher;
 @synthesize localDispatcher = _localDispatcher;
@@ -94,6 +98,31 @@
   return self;
 }
 
+#pragma mark - Property
+
+- (UIBarButtonItem*)clearBrowsingDataBarButton {
+  if (!_clearBrowsingDataBarButton) {
+    _clearBrowsingDataBarButton = [[UIBarButtonItem alloc]
+        initWithTitle:l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)
+                style:UIBarButtonItemStylePlain
+               target:self
+               action:@selector(showClearBrowsingDataAlertController:)];
+    _clearBrowsingDataBarButton.tintColor = [UIColor redColor];
+  }
+  return _clearBrowsingDataBarButton;
+}
+
+#pragma mark - UIViewController
+
+// Overrides parent class specification.
+- (NSArray<UIBarButtonItem*>*)toolbarItems {
+  UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc]
+      initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
+                           target:nil
+                           action:nil];
+  return @[ flexibleSpace, self.clearBrowsingDataBarButton, flexibleSpace ];
+}
+
 - (void)viewDidLoad {
   [super viewDidLoad];
   self.styler.tableViewBackgroundColor = UIColor.whiteColor;
@@ -128,6 +157,16 @@
   self.suppressTableViewUpdates = NO;
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+  [super viewWillAppear:animated];
+
+  if (IsNewClearBrowsingDataUIEnabled()) {
+    // Showing toolbar here because parent class hides toolbar in
+    // viewWillDisappear:.
+    self.navigationController.toolbarHidden = NO;
+  }
+}
+
 - (void)loadModel {
   [super loadModel];
   [self.dataManager loadModel:self.tableViewModel];
@@ -336,19 +375,26 @@
       dataTypeMaskToRemove = dataTypeMaskToRemove | dataTypeItem.dataTypeMask;
     }
   }
-  // Get button's position in coordinate system of table view.
-  DCHECK_EQ(self.clearBrowsingDataButton, sender);
-  CGRect clearBrowsingDataButtonRect = [self.clearBrowsingDataButton
-      convertRect:self.clearBrowsingDataButton.bounds
-           toView:self.tableView];
-  self.actionSheetCoordinator = [self.dataManager
-      actionSheetCoordinatorWithDataTypesToRemove:dataTypeMaskToRemove
-                               baseViewController:self
-                                       sourceRect:clearBrowsingDataButtonRect
-                                       sourceView:self.tableView];
-  if (self.actionSheetCoordinator) {
-    [self.actionSheetCoordinator start];
+  ActionSheetCoordinator* actionSheetCoordinator;
+  if (IsNewClearBrowsingDataUIEnabled()) {
+    actionSheetCoordinator = [self.dataManager
+        actionSheetCoordinatorWithDataTypesToRemove:dataTypeMaskToRemove
+                                 baseViewController:self
+                                sourceBarButtonItem:sender];
+  } else {
+    // Get button's position in coordinate system of table view.
+    DCHECK_EQ(self.clearBrowsingDataButton, sender);
+    CGRect clearBrowsingDataButtonRect = [self.clearBrowsingDataButton
+        convertRect:self.clearBrowsingDataButton.bounds
+             toView:self.tableView];
+    actionSheetCoordinator = [self.dataManager
+        actionSheetCoordinatorWithDataTypesToRemove:dataTypeMaskToRemove
+                                 baseViewController:self
+                                         sourceRect:clearBrowsingDataButtonRect
+                                         sourceView:self.tableView];
   }
+  self.actionSheetCoordinator = actionSheetCoordinator;
+  [self.actionSheetCoordinator start];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
index 10706c7..7051d0f5 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
@@ -461,8 +461,8 @@
 }
 
 - (BOOL)isSyncDisabledByAdministrator {
-  return self.syncService->GetDisableReasons() ==
-         syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY;
+  return (self.syncService->GetDisableReasons() &
+          syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY) != 0;
 }
 
 - (BOOL)isSyncCanBeAvailable {
diff --git a/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
index 0a8aaba..b7be1e1 100644
--- a/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/manage_sync_settings_coordinator.mm
@@ -14,8 +14,8 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
-#include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#include "ios/chrome/browser/sync/sync_observer_bridge.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
@@ -29,7 +29,6 @@
 #import "ios/public/provider/chrome/browser/signin/chrome_identity_browser_opener.h"
 #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
 #import "net/base/mac/url_conversions.h"
-#import "services/identity/public/objc/identity_manager_observer_bridge.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -37,12 +36,11 @@
 
 @interface ManageSyncSettingsCoordinator () <
     ChromeIdentityBrowserOpener,
-    IdentityManagerObserverBridgeDelegate,
     ManageSyncSettingsCommandHandler,
-    ManageSyncSettingsTableViewControllerPresentationDelegate> {
-  // Identity manager observer.
-  std::unique_ptr<identity::IdentityManagerObserverBridge>
-      _identityManagerObserverBridge;
+    ManageSyncSettingsTableViewControllerPresentationDelegate,
+    SyncObserverModelBridge> {
+  // Sync observer.
+  std::unique_ptr<SyncObserverBridge> _syncObserver;
 }
 
 // View controller.
@@ -53,16 +51,16 @@
 // Web and app activity view controller.
 @property(nonatomic, weak)
     UINavigationController* webAndAppSettingDetailsController;
+// Sync service.
+@property(nonatomic, assign, readonly) syncer::SyncService* syncService;
 
 @end
 
 @implementation ManageSyncSettingsCoordinator
 
 - (void)start {
-  syncer::SyncService* syncService =
-      ProfileSyncServiceFactory::GetForBrowserState(self.browserState);
   self.mediator = [[ManageSyncSettingsMediator alloc]
-      initWithSyncService:syncService
+      initWithSyncService:self.syncService
           userPrefService:self.browserState->GetPrefs()];
   self.mediator.syncSetupService =
       SyncSetupServiceFactory::GetForBrowserState(self.browserState);
@@ -77,10 +75,13 @@
   DCHECK(self.navigationController);
   [self.navigationController pushViewController:self.viewController
                                        animated:YES];
-  identity::IdentityManager* identityManager =
-      IdentityManagerFactory::GetForBrowserState(self.browserState);
-  _identityManagerObserverBridge.reset(
-      new identity::IdentityManagerObserverBridge(identityManager, self));
+  _syncObserver.reset(new SyncObserverBridge(self, self.syncService));
+}
+
+#pragma mark - Properties
+
+- (syncer::SyncService*)syncService {
+  return ProfileSyncServiceFactory::GetForBrowserState(self.browserState);
 }
 
 #pragma mark - Private
@@ -92,18 +93,8 @@
   self.webAndAppSettingDetailsController = nil;
 }
 
-#pragma mark - ManageSyncSettingsTableViewControllerPresentationDelegate
-
-- (void)manageSyncSettingsTableViewControllerWasPopped:
-    (ManageSyncSettingsTableViewController*)controller {
-  DCHECK_EQ(self.viewController, controller);
-  [self.delegate manageSyncSettingsCoordinatorWasPopped:self];
-}
-
-#pragma mark - IdentityManagerObserverBridgeDelegate
-
-- (void)onPrimaryAccountCleared:
-    (const CoreAccountInfo&)previousPrimaryAccountInfo {
+// Closes the Manage sync settings view controller.
+- (void)closeManageSyncSettings {
   if (self.viewController.navigationController) {
     if (self.webAndAppSettingDetailsController) {
       [self.navigationController dismissViewControllerAnimated:NO
@@ -116,6 +107,14 @@
   }
 }
 
+#pragma mark - ManageSyncSettingsTableViewControllerPresentationDelegate
+
+- (void)manageSyncSettingsTableViewControllerWasPopped:
+    (ManageSyncSettingsTableViewController*)controller {
+  DCHECK_EQ(self.viewController, controller);
+  [self.delegate manageSyncSettingsCoordinatorWasPopped:self];
+}
+
 #pragma mark - ChromeIdentityBrowserOpener
 
 - (void)openURL:(NSURL*)url
@@ -130,12 +129,10 @@
 
 - (void)openPassphraseDialog {
   DCHECK(self.mediator.shouldEncryptionItemBeEnabled);
-  syncer::SyncService* syncService =
-      ProfileSyncServiceFactory::GetForBrowserState(self.browserState);
   UIViewController<SettingsRootViewControlling>* controllerToPush;
   // If there was a sync error, prompt the user to enter the passphrase.
   // Otherwise, show the full encryption options.
-  if (syncService->GetUserSettings()->IsPassphraseRequired()) {
+  if (self.syncService->GetUserSettings()->IsPassphraseRequired()) {
     controllerToPush = [[SyncEncryptionPassphraseTableViewController alloc]
         initWithBrowserState:self.browserState];
   } else {
@@ -177,4 +174,13 @@
   [self.dispatcher closeSettingsUIAndOpenURL:command];
 }
 
+#pragma mark - SyncObserverModelBridge
+
+- (void)onSyncStateChanged {
+  if (self.syncService->GetDisableReasons() !=
+      syncer::SyncService::DISABLE_REASON_NONE) {
+    [self closeManageSyncSettings];
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index 2076a38..66a711a 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -1048,7 +1048,7 @@
     googleServicesItem.detailText = nil;
     googleServicesItem.image =
         [UIImage imageNamed:kSyncAndGoogleServicesImageName];
-  } else if (syncService->GetDisableReasons() ==
+  } else if (syncService->GetDisableReasons() &
              syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY) {
     googleServicesItem.detailText = l10n_util::GetNSString(
         IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_DISABLBED_BY_ADMINISTRATOR_STATUS);
diff --git a/ios/chrome/browser/ui/translate/translate_infobar_coordinator.h b/ios/chrome/browser/ui/translate/translate_infobar_coordinator.h
index 41688c6..4a0cbec 100644
--- a/ios/chrome/browser/ui/translate/translate_infobar_coordinator.h
+++ b/ios/chrome/browser/ui/translate/translate_infobar_coordinator.h
@@ -9,6 +9,11 @@
 
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 
+// The a11y identifier for the translate infobar's language selection menu.
+extern NSString* const kLanguageSelectorPopupMenuId;
+// The a11y identifier for the translate infobar's translate options menu.
+extern NSString* const kTranslateOptionsPopupMenuId;
+
 class WebStateList;
 
 // Coordinator responsible for presenting and dismissing the translate infobar's
diff --git a/ios/chrome/browser/ui/translate/translate_infobar_coordinator.mm b/ios/chrome/browser/ui/translate/translate_infobar_coordinator.mm
index 8ecfb42..a54a555 100644
--- a/ios/chrome/browser/ui/translate/translate_infobar_coordinator.mm
+++ b/ios/chrome/browser/ui/translate/translate_infobar_coordinator.mm
@@ -27,6 +27,9 @@
 #error "This file requires ARC support."
 #endif
 
+NSString* const kLanguageSelectorPopupMenuId = @"kLanguageSelectorPopupMenuId";
+NSString* const kTranslateOptionsPopupMenuId = @"kTranslateOptionsPopupMenuId";
+
 @interface TranslateInfobarCoordinator () <LanguageSelectionHandler,
                                            PopupMenuPresenterDelegate,
                                            PopupMenuTableViewControllerDelegate,
@@ -117,7 +120,8 @@
   self.mediator.infobarDelegate = context.languageData;
   self.mediator.unavailableLanguageIndex = context.unavailableLanguageIndex;
 
-  [self presentPopupMenu];
+  [self
+      presentPopupMenuWithAccessibilityIdentifier:kLanguageSelectorPopupMenuId];
 }
 
 - (void)dismissLanguageSelector {
@@ -145,7 +149,8 @@
   self.mediator.infobarDelegate = infobarDelegate;
   self.mediator.unavailableLanguageIndex = -1;
 
-  [self presentPopupMenu];
+  [self
+      presentPopupMenuWithAccessibilityIdentifier:kTranslateOptionsPopupMenuId];
 }
 
 - (void)dismissTranslateOptionSelector {
@@ -226,10 +231,11 @@
 #pragma mark - Private
 
 // Presents a popup menu with animation.
-- (void)presentPopupMenu {
+- (void)presentPopupMenuWithAccessibilityIdentifier:(NSString*)identifier {
   self.viewController = [[PopupMenuTableViewController alloc] init];
   self.viewController.baseViewController = self.baseViewController;
   self.viewController.delegate = self;
+  self.viewController.tableView.accessibilityIdentifier = identifier;
 
   self.mediator.consumer = self.viewController;
 
diff --git a/ios/chrome/browser/ui/translate/translate_infobar_view.h b/ios/chrome/browser/ui/translate/translate_infobar_view.h
index 95945f6..db9b349 100644
--- a/ios/chrome/browser/ui/translate/translate_infobar_view.h
+++ b/ios/chrome/browser/ui/translate/translate_infobar_view.h
@@ -19,6 +19,9 @@
 // Height of the infobar.
 extern const CGFloat kInfobarHeight;
 
+// The a11y identifier for the translate infobar view.
+extern NSString* const kTranslateInfobarViewId;
+
 @protocol TranslateInfobarViewDelegate;
 
 // An infobar for translating the page. Starting from the leading edge, it
diff --git a/ios/chrome/browser/ui/translate/translate_infobar_view.mm b/ios/chrome/browser/ui/translate/translate_infobar_view.mm
index 461e80e3..f6017b5 100644
--- a/ios/chrome/browser/ui/translate/translate_infobar_view.mm
+++ b/ios/chrome/browser/ui/translate/translate_infobar_view.mm
@@ -30,6 +30,8 @@
 
 const CGFloat kInfobarHeight = 54;
 
+NSString* const kTranslateInfobarViewId = @"kTranslateInfobarViewId";
+
 namespace {
 
 // Size of the infobar buttons.
@@ -200,6 +202,7 @@
 #pragma mark - Private
 
 - (void)setupSubviews {
+  self.accessibilityIdentifier = kTranslateInfobarViewId;
   [self setAccessibilityViewIsModal:YES];
   NSString* a11yAnnoucement =
       [self a11yAnnouncementFromTranslateInfobarViewState:self.state
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 389e205..b447839 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -25,3 +25,6 @@
 
 const base::Feature kSettingsRefresh{"SettingsRefresh",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kDisplaySearchEngineFavicon{
+    "DisplaySearchEngineFavicon", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
index cb272f3..fe54cc1 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.h
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -32,4 +32,7 @@
 // Feature to apply UI Refresh theme to the settings.
 extern const base::Feature kSettingsRefresh;
 
+// Feature to display search engine favicons in Settings.
+extern const base::Feature kDisplaySearchEngineFavicon;
+
 #endif  // IOS_CHROME_BROWSER_UI_UI_FEATURE_FLAGS_H_
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index d859679..4aac3e92 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -89,7 +89,7 @@
                                  SetCookiesCallback callback) override;
   void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
                                std::string source_scheme,
-                               bool modify_http_only,
+                               const net::CookieOptions& options,
                                SetCookiesCallback callback) override;
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const net::CookieOptions& options,
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 5bc35f4..487b062 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -341,7 +341,7 @@
 void CookieStoreIOS::SetCanonicalCookieAsync(
     std::unique_ptr<net::CanonicalCookie> cookie,
     std::string source_scheme,
-    bool modify_http_only,
+    const net::CookieOptions& options,
     SetCookiesCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -352,7 +352,7 @@
   DCHECK(cookie->IsCanonical());
   // The exclude_httponly() option would only be used by a javascript
   // engine.
-  DCHECK(modify_http_only);
+  DCHECK(!options.exclude_httponly());
 
   bool secure_source =
       GURL::SchemeIsCryptographic(base::ToLowerASCII(source_scheme));
diff --git a/ios/net/cookies/cookie_store_ios_persistent.h b/ios/net/cookies/cookie_store_ios_persistent.h
index 7a0a5170..29681cfb 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.h
+++ b/ios/net/cookies/cookie_store_ios_persistent.h
@@ -48,7 +48,7 @@
                                  SetCookiesCallback callback) override;
   void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
                                std::string source_scheme,
-                               bool modify_http_only,
+                               const net::CookieOptions& options,
                                SetCookiesCallback callback) override;
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const net::CookieOptions& options,
diff --git a/ios/net/cookies/cookie_store_ios_persistent.mm b/ios/net/cookies/cookie_store_ios_persistent.mm
index c117783..80e4a92 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent.mm
@@ -71,12 +71,12 @@
 void CookieStoreIOSPersistent::SetCanonicalCookieAsync(
     std::unique_ptr<CanonicalCookie> cookie,
     std::string source_scheme,
-    bool modify_http_only,
+    const net::CookieOptions& options,
     SetCookiesCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   cookie_monster()->SetCanonicalCookieAsync(
-      std::move(cookie), std::move(source_scheme), modify_http_only,
+      std::move(cookie), std::move(source_scheme), options,
       WrapSetCallback(std::move(callback)));
 }
 
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm
index 0904eb6..25c0b542 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -261,7 +261,7 @@
 
 void WKBasedNavigationManagerImpl::CommitPendingItem(
     std::unique_ptr<NavigationItemImpl> item) {
-  if (!web::features::StorePendingItemInContext()) {
+  if (!features::StorePendingItemInContext() || pending_item_index_ != -1) {
     CommitPendingItem();
     return;
   }
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 39b2a6b9..11709c5 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -449,27 +449,8 @@
 // dropped.
 - (WKNavigation*)loadPOSTRequest:(NSMutableURLRequest*)request;
 
-// Extracts navigation info from WKNavigationAction and sets it as a pending.
-// Some pieces of navigation information are only known in
-// |decidePolicyForNavigationAction|, but must be in a pending state until
-// |didgo/Navigation| where it becames current.
-- (void)updatePendingNavigationInfoFromNavigationAction:
-    (WKNavigationAction*)action;
-// Extracts navigation info from WKNavigationResponse and sets it as a pending.
-// Some pieces of navigation information are only known in
-// |decidePolicyForNavigationResponse|, but must be in a pending state until
-// |didCommitNavigation| where it becames current.
-- (void)updatePendingNavigationInfoFromNavigationResponse:
-    (WKNavigationResponse*)response;
-// Updates current state with any pending information. Should be called when a
-// navigation is committed.
-- (void)commitPendingNavigationInfo;
 // Returns a NSMutableURLRequest that represents the current NavigationItem.
 - (NSMutableURLRequest*)requestForCurrentNavigationItem;
-// Returns the WKBackForwardListItemHolder for the current navigation item.
-- (web::WKBackForwardListItemHolder*)currentBackForwardListItemHolder;
-// Updates the WKBackForwardListItemHolder navigation item.
-- (void)updateCurrentBackForwardListItemHolder;
 
 // Loads a blank page directly into WKWebView as a placeholder for a Native View
 // or WebUI URL. This page has the URL about:blank?for=<encoded original URL>.
@@ -497,9 +478,6 @@
 // If YES, the page should be closed if it successfully redirects to a native
 // application, for example if a new tab redirects to the App Store.
 - (BOOL)shouldClosePageOnNativeApplicationLoad;
-// Updates URL for navigation context and navigation item.
-- (void)didReceiveRedirectForNavigation:(web::NavigationContextImpl*)context
-                                withURL:(const GURL&)URL;
 // Called following navigation completion to generate final navigation lifecycle
 // events. Navigation is considered complete when the document has finished
 // loading, or when other page load mechanics are completed on a
@@ -535,33 +513,10 @@
 - (void)frameBecameUnavailableWithMessage:(WKScriptMessage*)message;
 // Clears the frames list.
 - (void)removeAllWebFrames;
-// Registers load request with empty referrer and link or client redirect
-// transition based on user interaction state. Returns navigation context for
-// this request.
-- (std::unique_ptr<web::NavigationContextImpl>)
-    registerLoadRequestForURL:(const GURL&)URL
-       sameDocumentNavigation:(BOOL)sameDocumentNavigation
-               hasUserGesture:(BOOL)hasUserGesture
-            rendererInitiated:(BOOL)rendererInitiated
-        placeholderNavigation:(BOOL)placeholderNavigation;
-// Prepares web controller and delegates for anticipated page change.
-// Allows several methods to invoke webWill/DidAddPendingURL on anticipated page
-// change, using the same cached request and calculated transition types.
-// Returns navigation context for this request.
-- (std::unique_ptr<web::NavigationContextImpl>)
-    registerLoadRequestForURL:(const GURL&)URL
-                     referrer:(const web::Referrer&)referrer
-                   transition:(ui::PageTransition)transition
-       sameDocumentNavigation:(BOOL)sameDocumentNavigation
-               hasUserGesture:(BOOL)hasUserGesture
-            rendererInitiated:(BOOL)rendererInitiated
-        placeholderNavigation:(BOOL)placeholderNavigation;
 // Maps WKNavigationType to ui::PageTransition.
 - (ui::PageTransition)pageTransitionFromNavigationType:
     (WKNavigationType)navigationType;
 
-// Returns YES if the current live view is a web view with an image MIME type.
-- (BOOL)contentIsImage;
 // Restores the state for this page from session history.
 - (void)restoreStateFromHistory;
 // Extracts the current page's viewport tag information and calls |completion|.
@@ -639,10 +594,6 @@
 // Returns YES if a SafeBrowsing warning is currently displayed within
 // WKWebView.
 - (BOOL)isSafeBrowsingWarningDisplayedInWebView;
-// Returns context for pending navigation that has |URL|. null if there is no
-// matching pending navigation.
-- (web::NavigationContextImpl*)contextForPendingMainFrameNavigationWithURL:
-    (const GURL&)URL;
 // Loads request for the URL of the current navigation item. Subclasses may
 // choose to build a new NSURLRequest and call |loadRequest| on the underlying
 // web view, or use native web view navigation where possible (for example,
@@ -1772,6 +1723,65 @@
          [list.backList indexOfObject:item] != NSNotFound;
 }
 
+// Returns the WKBackForwardListItemHolder for the current navigation item.
+- (web::WKBackForwardListItemHolder*)currentBackForwardListItemHolder {
+  web::NavigationItem* item = self.currentNavItem;
+  DCHECK(item);
+  web::WKBackForwardListItemHolder* holder =
+      web::WKBackForwardListItemHolder::FromNavigationItem(item);
+  DCHECK(holder);
+  return holder;
+}
+
+- (GURL)webURLWithTrustLevel:(web::URLVerificationTrustLevel*)trustLevel {
+  DCHECK(trustLevel);
+  *trustLevel = web::URLVerificationTrustLevel::kAbsolute;
+  // Placeholder URL is an implementation detail. Don't expose it to users of
+  // web layer.
+  if (IsPlaceholderUrl(_documentURL))
+    return ExtractUrlFromPlaceholderUrl(_documentURL);
+  return _documentURL;
+}
+
+- (BOOL)shouldClosePageOnNativeApplicationLoad {
+  // The page should be closed if it was initiated by the DOM and there has been
+  // no user interaction with the page since the web view was created, or if
+  // the page has no navigation items, as occurs when an App Store link is
+  // opened from another application.
+  BOOL rendererInitiatedWithoutInteraction =
+      self.hasOpener && !_userInteractedWithWebController;
+  BOOL noNavigationItems = !(self.navigationManagerImpl->GetItemCount());
+  return rendererInitiatedWithoutInteraction || noNavigationItems;
+}
+
+- (ui::PageTransition)pageTransitionFromNavigationType:
+    (WKNavigationType)navigationType {
+  switch (navigationType) {
+    case WKNavigationTypeLinkActivated:
+      return ui::PAGE_TRANSITION_LINK;
+    case WKNavigationTypeFormSubmitted:
+    case WKNavigationTypeFormResubmitted:
+      return ui::PAGE_TRANSITION_FORM_SUBMIT;
+    case WKNavigationTypeBackForward:
+      return ui::PAGE_TRANSITION_FORWARD_BACK;
+    case WKNavigationTypeReload:
+      return ui::PAGE_TRANSITION_RELOAD;
+    case WKNavigationTypeOther:
+      // The "Other" type covers a variety of very different cases, which may
+      // or may not be the result of user actions. For now, guess based on
+      // whether there's been an interaction since the last URL change.
+      // TODO(crbug.com/549301): See if this heuristic can be improved.
+      return _interactionRegisteredSinceLastURLChange
+                 ? ui::PAGE_TRANSITION_LINK
+                 : ui::PAGE_TRANSITION_CLIENT_REDIRECT;
+  }
+}
+
+#pragma mark - Load helpers
+
+// Registers load request with empty referrer and link or client redirect
+// transition based on user interaction state. Returns navigation context for
+// this request.
 - (std::unique_ptr<web::NavigationContextImpl>)
     registerLoadRequestForURL:(const GURL&)URL
        sameDocumentNavigation:(BOOL)sameDocumentNavigation
@@ -1812,6 +1822,10 @@
   return context;
 }
 
+// Prepares web controller and delegates for anticipated page change.
+// Allows several methods to invoke webWill/DidAddPendingURL on anticipated page
+// change, using the same cached request and calculated transition types.
+// Returns navigation context for this request.
 - (std::unique_ptr<web::NavigationContextImpl>)
     registerLoadRequestForURL:(const GURL&)requestURL
                      referrer:(const web::Referrer&)referrer
@@ -1920,29 +1934,6 @@
   return context;
 }
 
-- (ui::PageTransition)pageTransitionFromNavigationType:
-    (WKNavigationType)navigationType {
-  switch (navigationType) {
-    case WKNavigationTypeLinkActivated:
-      return ui::PAGE_TRANSITION_LINK;
-    case WKNavigationTypeFormSubmitted:
-    case WKNavigationTypeFormResubmitted:
-      return ui::PAGE_TRANSITION_FORM_SUBMIT;
-    case WKNavigationTypeBackForward:
-      return ui::PAGE_TRANSITION_FORWARD_BACK;
-    case WKNavigationTypeReload:
-      return ui::PAGE_TRANSITION_RELOAD;
-    case WKNavigationTypeOther:
-      // The "Other" type covers a variety of very different cases, which may
-      // or may not be the result of user actions. For now, guess based on
-      // whether there's been an interaction since the last URL change.
-      // TODO(crbug.com/549301): See if this heuristic can be improved.
-      return _interactionRegisteredSinceLastURLChange
-                 ? ui::PAGE_TRANSITION_LINK
-                 : ui::PAGE_TRANSITION_CLIENT_REDIRECT;
-  }
-}
-
 // Load the current URL in a web view, first ensuring the web view is visible.
 - (void)loadCurrentURLInWebView {
   web::NavigationItem* item = self.currentNavItem;
@@ -2210,41 +2201,6 @@
       BackForwardNavigationType::BACK_FORWARD_NAVIGATION_TYPE_COUNT);
 }
 
-- (void)updatePendingNavigationInfoFromNavigationAction:
-    (WKNavigationAction*)action {
-  if (action.targetFrame.mainFrame) {
-    _pendingNavigationInfo =
-        [[CRWWebControllerPendingNavigationInfo alloc] init];
-    [_pendingNavigationInfo
-        setReferrer:[self referrerFromNavigationAction:action]];
-    [_pendingNavigationInfo setNavigationType:action.navigationType];
-    [_pendingNavigationInfo setHTTPMethod:action.request.HTTPMethod];
-    BOOL hasUserGesture = web::GetNavigationActionInitiationType(action) ==
-                          web::NavigationActionInitiationType::kUserInitiated;
-    [_pendingNavigationInfo setHasUserGesture:hasUserGesture];
-  }
-}
-
-- (void)updatePendingNavigationInfoFromNavigationResponse:
-    (WKNavigationResponse*)response {
-  if (response.isForMainFrame) {
-    if (!_pendingNavigationInfo) {
-      _pendingNavigationInfo =
-          [[CRWWebControllerPendingNavigationInfo alloc] init];
-    }
-    [_pendingNavigationInfo setMIMEType:response.response.MIMEType];
-  }
-}
-
-- (void)commitPendingNavigationInfo {
-  if ([_pendingNavigationInfo referrer]) {
-    _currentReferrerString = [[_pendingNavigationInfo referrer] copy];
-  }
-  [self updateCurrentBackForwardListItemHolder];
-
-  _pendingNavigationInfo = nil;
-}
-
 - (NSMutableURLRequest*)requestForCurrentNavigationItem {
   web::NavigationItem* item = self.currentNavItem;
   const GURL currentNavigationURL = item ? item->GetURL() : GURL::EmptyGURL();
@@ -2274,132 +2230,6 @@
   return request;
 }
 
-- (web::NavigationContextImpl*)contextForPendingMainFrameNavigationWithURL:
-    (const GURL&)URL {
-  // Here the enumeration variable |navigation| is __strong to allow setting it
-  // to nil.
-  for (__strong id navigation in [_navigationStates pendingNavigations]) {
-    if (navigation == [NSNull null]) {
-      // null is a valid navigation object passed to WKNavigationDelegate
-      // callbacks and represents window opening action.
-      navigation = nil;
-    }
-
-    web::NavigationContextImpl* context =
-        [_navigationStates contextForNavigation:navigation];
-    if (context && context->GetUrl() == URL) {
-      return context;
-    }
-  }
-  return nullptr;
-}
-
-- (web::WKBackForwardListItemHolder*)currentBackForwardListItemHolder {
-  web::NavigationItem* item = self.currentNavItem;
-  DCHECK(item);
-  web::WKBackForwardListItemHolder* holder =
-      web::WKBackForwardListItemHolder::FromNavigationItem(item);
-  DCHECK(holder);
-  return holder;
-}
-
-- (void)updateCurrentBackForwardListItemHolder {
-  // WebUI pages (which are loaded via loadHTMLString:baseURL:) have no entry
-  // in the back/forward list, so the current item will still be the previous
-  // page, and should not be associated.
-  if (_webUIManager)
-    return;
-
-  if (!self.currentNavItem) {
-    // TODO(crbug.com/925304): Pending item (which stores the holder) should be
-    // owned by NavigationContext object. Pending item should never be null.
-    return;
-  }
-
-  web::WKBackForwardListItemHolder* holder =
-      [self currentBackForwardListItemHolder];
-
-  WKNavigationType navigationType =
-      _pendingNavigationInfo ? [_pendingNavigationInfo navigationType]
-                             : WKNavigationTypeOther;
-  holder->set_back_forward_list_item(self.webView.backForwardList.currentItem);
-  holder->set_navigation_type(navigationType);
-  holder->set_http_method([_pendingNavigationInfo HTTPMethod]);
-
-  // Only update the MIME type in the holder if there was MIME type information
-  // as part of this pending load. It will be nil when doing a fast
-  // back/forward navigation, for instance, because the callback that would
-  // populate it is not called in that flow.
-  if ([_pendingNavigationInfo MIMEType])
-    holder->set_mime_type([_pendingNavigationInfo MIMEType]);
-}
-
-- (void)loadErrorPageForNavigationItem:(web::NavigationItemImpl*)item
-                     navigationContext:(web::NavigationContextImpl*)context {
-  NSError* error = context->GetError();
-  DCHECK(error);
-  DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID());
-
-  if (web::IsWKWebViewSSLCertError(error)) {
-    // This could happen only if certificate is absent or could not be parsed.
-    error = web::NetErrorFromError(error, net::ERR_SSL_SERVER_CERT_BAD_FORMAT);
-#if defined(DEBUG)
-    net::SSLInfo info;
-    web::GetSSLInfoFromWKWebViewSSLCertError(error, &info);
-    CHECK(!error.cert);
-#endif
-  } else {
-    error = web::NetErrorFromError(error);
-  }
-  NSString* failingURLString =
-      error.userInfo[NSURLErrorFailingURLStringErrorKey];
-  GURL failingURL(base::SysNSStringToUTF8(failingURLString));
-  NSString* errorHTML = nil;
-  web::GetWebClient()->PrepareErrorPage(
-      self.webStateImpl, failingURL, error, context->IsPost(),
-      self.webStateImpl->GetBrowserState()->IsOffTheRecord(), &errorHTML);
-  WKNavigation* navigation =
-      [self.webView loadHTMLString:errorHTML
-                           baseURL:net::NSURLWithGURL(failingURL)];
-
-  auto loadHTMLContext = web::NavigationContextImpl::CreateNavigationContext(
-      self.webStateImpl, failingURL,
-      /*has_user_gesture=*/false, ui::PAGE_TRANSITION_FIRST,
-      /*is_renderer_initiated=*/false);
-  loadHTMLContext->SetLoadingErrorPage(true);
-  loadHTMLContext->SetNavigationItemUniqueID(item->GetUniqueID());
-
-  [_navigationStates setContext:std::move(loadHTMLContext)
-                  forNavigation:navigation];
-  [_navigationStates setState:web::WKNavigationState::REQUESTED
-                forNavigation:navigation];
-
-  // TODO(crbug.com/803503): only call these for placeholder navigation because
-  // they should have already been triggered during navigation commit for
-  // failures that happen after commit.
-  [self didStartLoading];
-  self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem());
-  web::NavigationItem* lastCommittedItem =
-      self.navigationManagerImpl->GetLastCommittedItem();
-  [self setDocumentURL:lastCommittedItem->GetURL() context:context];
-
-  // If |context| is a placeholder navigation, this is the second part of the
-  // error page load for a provisional load failure. Rewrite the context URL to
-  // actual URL and trigger the deferred |OnNavigationFinished| callback. This
-  // is also needed if |context| is not yet committed, which can happen on a
-  // reload/back/forward load that failed in provisional navigation.
-  if (context->IsPlaceholderNavigation() || !context->HasCommitted()) {
-    context->SetUrl(item->GetURL());
-    context->SetPlaceholderNavigation(false);
-    context->SetHasCommitted(true);
-    self.webStateImpl->OnNavigationFinished(context);
-  }
-
-  [self loadCompleteWithSuccess:NO forContext:context];
-  self.webStateImpl->SetIsLoading(false);
-  self.webStateImpl->OnPageLoaded(failingURL, NO);
-}
-
 - (web::NavigationContextImpl*)
     loadPlaceholderInWebViewForURL:(const GURL&)originalURL
                  rendererInitiated:(BOOL)rendererInitiated
@@ -2429,64 +2259,7 @@
   return [_navigationStates contextForNavigation:navigation];
 }
 
-- (void)handleErrorRetryCommand:(web::ErrorRetryCommand)command
-                 navigationItem:(web::NavigationItemImpl*)item
-              navigationContext:(web::NavigationContextImpl*)context
-             originalNavigation:(WKNavigation*)originalNavigation {
-  if (command == web::ErrorRetryCommand::kDoNothing)
-    return;
-
-  DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID());
-  switch (command) {
-    case web::ErrorRetryCommand::kLoadPlaceholder: {
-      // This case only happens when a new request failed in provisional
-      // navigation. Disassociate the navigation context from the original
-      // request and resuse it for the placeholder navigation.
-      std::unique_ptr<web::NavigationContextImpl> originalContext =
-          [_navigationStates removeNavigation:originalNavigation];
-      [self loadPlaceholderInWebViewForURL:item->GetURL()
-                         rendererInitiated:context->IsRendererInitiated()
-                                forContext:std::move(originalContext)];
-    } break;
-
-    case web::ErrorRetryCommand::kLoadErrorView:
-      [self loadErrorPageForNavigationItem:item navigationContext:context];
-      break;
-
-    case web::ErrorRetryCommand::kReload:
-      [self.webView reload];
-      break;
-
-    case web::ErrorRetryCommand::kRewriteWebViewURL: {
-      std::unique_ptr<web::NavigationContextImpl> navigationContext =
-          [self registerLoadRequestForURL:item->GetURL()
-                   sameDocumentNavigation:NO
-                           hasUserGesture:NO
-                        rendererInitiated:context->IsRendererInitiated()
-                    placeholderNavigation:NO];
-      WKNavigation* navigation =
-          [self.webView loadHTMLString:@""
-                               baseURL:net::NSURLWithGURL(item->GetURL())];
-      navigationContext->SetError(context->GetError());
-      navigationContext->SetIsPost(context->IsPost());
-      [_navigationStates setContext:std::move(navigationContext)
-                      forNavigation:navigation];
-    } break;
-
-    case web::ErrorRetryCommand::kDoNothing:
-      NOTREACHED();
-  }
-}
-
-- (GURL)webURLWithTrustLevel:(web::URLVerificationTrustLevel*)trustLevel {
-  DCHECK(trustLevel);
-  *trustLevel = web::URLVerificationTrustLevel::kAbsolute;
-  // Placeholder URL is an implementation detail. Don't expose it to users of
-  // web layer.
-  if (IsPlaceholderUrl(_documentURL))
-    return ExtractUrlFromPlaceholderUrl(_documentURL);
-  return _documentURL;
-}
+#pragma mark - End of loading
 
 - (void)abortLoad {
   [self.webView stopLoading];
@@ -2506,37 +2279,6 @@
   }
 }
 
-- (BOOL)contentIsImage {
-  if (!self.webView)
-    return NO;
-
-  const std::string image = "image";
-  std::string MIMEType = self.webState->GetContentsMimeType();
-  return MIMEType.compare(0, image.length(), image) == 0;
-}
-
-- (void)didReceiveRedirectForNavigation:(web::NavigationContextImpl*)context
-                                withURL:(const GURL&)URL {
-  context->SetUrl(URL);
-  web::NavigationItemImpl* item =
-      web::GetItemWithUniqueID(self.navigationManagerImpl, context);
-
-  // Associated item can be a pending item, previously discarded by another
-  // navigation. WKWebView allows multiple provisional navigations, while
-  // Navigation Manager has only one pending navigation.
-  if (item) {
-    if (!web::wk_navigation_util::IsWKInternalUrl(URL)) {
-      item->SetVirtualURL(URL);
-      item->SetURL(URL);
-    }
-    // Redirects (3xx response code), must change POST requests to GETs.
-    item->SetPostData(nil);
-    item->ResetHttpRequestHeaders();
-  }
-
-  _lastTransferTimeInSeconds = CFAbsoluteTimeGetCurrent();
-}
-
 - (void)didFinishNavigation:(web::NavigationContextImpl*)context {
   // This can be called at multiple times after the document has loaded. Do
   // nothing if the document has already loaded.
@@ -2629,15 +2371,123 @@
   self.webStateImpl->OnPageLoaded(currentURL, YES);
 }
 
-- (BOOL)shouldClosePageOnNativeApplicationLoad {
-  // The page should be closed if it was initiated by the DOM and there has been
-  // no user interaction with the page since the web view was created, or if
-  // the page has no navigation items, as occurs when an App Store link is
-  // opened from another application.
-  BOOL rendererInitiatedWithoutInteraction =
-      self.hasOpener && !_userInteractedWithWebController;
-  BOOL noNavigationItems = !(self.navigationManagerImpl->GetItemCount());
-  return rendererInitiatedWithoutInteraction || noNavigationItems;
+#pragma mark - Error helpers
+
+- (void)loadErrorPageForNavigationItem:(web::NavigationItemImpl*)item
+                     navigationContext:(web::NavigationContextImpl*)context {
+  const GURL currentURL = item ? item->GetVirtualURL() : GURL::EmptyGURL();
+  NSError* error = context->GetError();
+  DCHECK(error);
+  DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID());
+
+  if (web::IsWKWebViewSSLCertError(error)) {
+    // This could happen only if certificate is absent or could not be parsed.
+    error = web::NetErrorFromError(error, net::ERR_SSL_SERVER_CERT_BAD_FORMAT);
+#if defined(DEBUG)
+    net::SSLInfo info;
+    web::GetSSLInfoFromWKWebViewSSLCertError(error, &info);
+    CHECK(!error.cert);
+#endif
+  } else {
+    error = web::NetErrorFromError(error);
+  }
+  NSString* failingURLString =
+      error.userInfo[NSURLErrorFailingURLStringErrorKey];
+  GURL failingURL(base::SysNSStringToUTF8(failingURLString));
+  NSString* errorHTML = nil;
+  web::GetWebClient()->PrepareErrorPage(
+      self.webStateImpl, failingURL, error, context->IsPost(),
+      self.webStateImpl->GetBrowserState()->IsOffTheRecord(), &errorHTML);
+
+  WKNavigation* navigation =
+      [self.webView loadHTMLString:errorHTML
+                           baseURL:net::NSURLWithGURL(failingURL)];
+
+  auto loadHTMLContext = web::NavigationContextImpl::CreateNavigationContext(
+      self.webStateImpl, failingURL,
+      /*has_user_gesture=*/false, ui::PAGE_TRANSITION_FIRST,
+      /*is_renderer_initiated=*/false);
+  loadHTMLContext->SetLoadingErrorPage(true);
+  loadHTMLContext->SetNavigationItemUniqueID(item->GetUniqueID());
+
+  [_navigationStates setContext:std::move(loadHTMLContext)
+                  forNavigation:navigation];
+  [_navigationStates setState:web::WKNavigationState::REQUESTED
+                forNavigation:navigation];
+
+  // TODO(crbug.com/803503): only call these for placeholder navigation because
+  // they should have already been triggered during navigation commit for
+  // failures that happen after commit.
+  [self didStartLoading];
+  self.navigationManagerImpl->CommitPendingItem(context->ReleaseItem());
+  web::NavigationItem* lastCommittedItem =
+      self.navigationManagerImpl->GetLastCommittedItem();
+  [self setDocumentURL:lastCommittedItem->GetURL() context:context];
+
+  // If |context| is a placeholder navigation, this is the second part of the
+  // error page load for a provisional load failure. Rewrite the context URL to
+  // actual URL and trigger the deferred |OnNavigationFinished| callback. This
+  // is also needed if |context| is not yet committed, which can happen on a
+  // reload/back/forward load that failed in provisional navigation.
+  if (context->IsPlaceholderNavigation() || !context->HasCommitted()) {
+    context->SetUrl(item->GetURL());
+    context->SetPlaceholderNavigation(false);
+    context->SetHasCommitted(true);
+    self.webStateImpl->OnNavigationFinished(context);
+  }
+
+  [self loadCompleteWithSuccess:NO forContext:context];
+  self.webStateImpl->SetIsLoading(false);
+  self.webStateImpl->OnPageLoaded(failingURL, NO);
+}
+
+- (void)handleErrorRetryCommand:(web::ErrorRetryCommand)command
+                 navigationItem:(web::NavigationItemImpl*)item
+              navigationContext:(web::NavigationContextImpl*)context
+             originalNavigation:(WKNavigation*)originalNavigation {
+  if (command == web::ErrorRetryCommand::kDoNothing)
+    return;
+
+  DCHECK_EQ(item->GetUniqueID(), context->GetNavigationItemUniqueID());
+  switch (command) {
+    case web::ErrorRetryCommand::kLoadPlaceholder: {
+      // This case only happens when a new request failed in provisional
+      // navigation. Disassociate the navigation context from the original
+      // request and resuse it for the placeholder navigation.
+      std::unique_ptr<web::NavigationContextImpl> originalContext =
+          [_navigationStates removeNavigation:originalNavigation];
+      [self loadPlaceholderInWebViewForURL:item->GetURL()
+                         rendererInitiated:context->IsRendererInitiated()
+                                forContext:std::move(originalContext)];
+    } break;
+
+    case web::ErrorRetryCommand::kLoadErrorView:
+      [self loadErrorPageForNavigationItem:item navigationContext:context];
+      break;
+
+    case web::ErrorRetryCommand::kReload:
+      [self.webView reload];
+      break;
+
+    case web::ErrorRetryCommand::kRewriteWebViewURL: {
+      std::unique_ptr<web::NavigationContextImpl> navigationContext =
+          [self registerLoadRequestForURL:item->GetURL()
+                   sameDocumentNavigation:NO
+                           hasUserGesture:NO
+                        rendererInitiated:context->IsRendererInitiated()
+                    placeholderNavigation:NO];
+      WKNavigation* navigation =
+          [self.webView loadHTMLString:@""
+                               baseURL:net::NSURLWithGURL(item->GetURL())];
+      navigationContext->SetError(context->GetError());
+      navigationContext->SetIsPost(context->IsPost());
+      [_navigationStates setContext:std::move(navigationContext)
+                      forNavigation:navigation];
+    } break;
+
+    case web::ErrorRetryCommand::kDoNothing:
+      NOTREACHED();
+  }
 }
 
 #pragma mark - JavaScript history manipulation
@@ -5590,6 +5440,138 @@
                            MIMEType, transition);
 }
 
+// Extracts navigation info from WKNavigationAction and sets it as a pending.
+// Some pieces of navigation information are only known in
+// |decidePolicyForNavigationAction|, but must be in a pending state until
+// |didgo/Navigation| where it becames current.
+- (void)updatePendingNavigationInfoFromNavigationAction:
+    (WKNavigationAction*)action {
+  if (action.targetFrame.mainFrame) {
+    _pendingNavigationInfo =
+        [[CRWWebControllerPendingNavigationInfo alloc] init];
+    [_pendingNavigationInfo
+        setReferrer:[self referrerFromNavigationAction:action]];
+    [_pendingNavigationInfo setNavigationType:action.navigationType];
+    [_pendingNavigationInfo setHTTPMethod:action.request.HTTPMethod];
+    BOOL hasUserGesture = web::GetNavigationActionInitiationType(action) ==
+                          web::NavigationActionInitiationType::kUserInitiated;
+    [_pendingNavigationInfo setHasUserGesture:hasUserGesture];
+  }
+}
+
+// Extracts navigation info from WKNavigationResponse and sets it as a pending.
+// Some pieces of navigation information are only known in
+// |decidePolicyForNavigationResponse|, but must be in a pending state until
+// |didCommitNavigation| where it becames current.
+- (void)updatePendingNavigationInfoFromNavigationResponse:
+    (WKNavigationResponse*)response {
+  if (response.isForMainFrame) {
+    if (!_pendingNavigationInfo) {
+      _pendingNavigationInfo =
+          [[CRWWebControllerPendingNavigationInfo alloc] init];
+    }
+    [_pendingNavigationInfo setMIMEType:response.response.MIMEType];
+  }
+}
+
+// Updates current state with any pending information. Should be called when a
+// navigation is committed.
+- (void)commitPendingNavigationInfo {
+  if ([_pendingNavigationInfo referrer]) {
+    _currentReferrerString = [[_pendingNavigationInfo referrer] copy];
+  }
+  [self updateCurrentBackForwardListItemHolder];
+
+  _pendingNavigationInfo = nil;
+}
+
+// Updates the WKBackForwardListItemHolder navigation item.
+- (void)updateCurrentBackForwardListItemHolder {
+  // WebUI pages (which are loaded via loadHTMLString:baseURL:) have no entry
+  // in the back/forward list, so the current item will still be the previous
+  // page, and should not be associated.
+  if (_webUIManager)
+    return;
+
+  if (!self.currentNavItem) {
+    // TODO(crbug.com/925304): Pending item (which stores the holder) should be
+    // owned by NavigationContext object. Pending item should never be null.
+    return;
+  }
+
+  web::WKBackForwardListItemHolder* holder =
+      [self currentBackForwardListItemHolder];
+
+  WKNavigationType navigationType =
+      _pendingNavigationInfo ? [_pendingNavigationInfo navigationType]
+                             : WKNavigationTypeOther;
+  holder->set_back_forward_list_item(self.webView.backForwardList.currentItem);
+  holder->set_navigation_type(navigationType);
+  holder->set_http_method([_pendingNavigationInfo HTTPMethod]);
+
+  // Only update the MIME type in the holder if there was MIME type information
+  // as part of this pending load. It will be nil when doing a fast
+  // back/forward navigation, for instance, because the callback that would
+  // populate it is not called in that flow.
+  if ([_pendingNavigationInfo MIMEType])
+    holder->set_mime_type([_pendingNavigationInfo MIMEType]);
+}
+
+// Returns context for pending navigation that has |URL|. null if there is no
+// matching pending navigation.
+- (web::NavigationContextImpl*)contextForPendingMainFrameNavigationWithURL:
+    (const GURL&)URL {
+  // Here the enumeration variable |navigation| is __strong to allow setting it
+  // to nil.
+  for (__strong id navigation in [_navigationStates pendingNavigations]) {
+    if (navigation == [NSNull null]) {
+      // null is a valid navigation object passed to WKNavigationDelegate
+      // callbacks and represents window opening action.
+      navigation = nil;
+    }
+
+    web::NavigationContextImpl* context =
+        [_navigationStates contextForNavigation:navigation];
+    if (context && context->GetUrl() == URL) {
+      return context;
+    }
+  }
+  return nullptr;
+}
+
+// Updates URL for navigation context and navigation item.
+- (void)didReceiveRedirectForNavigation:(web::NavigationContextImpl*)context
+                                withURL:(const GURL&)URL {
+  context->SetUrl(URL);
+  web::NavigationItemImpl* item =
+      web::GetItemWithUniqueID(self.navigationManagerImpl, context);
+
+  // Associated item can be a pending item, previously discarded by another
+  // navigation. WKWebView allows multiple provisional navigations, while
+  // Navigation Manager has only one pending navigation.
+  if (item) {
+    if (!web::wk_navigation_util::IsWKInternalUrl(URL)) {
+      item->SetVirtualURL(URL);
+      item->SetURL(URL);
+    }
+    // Redirects (3xx response code), must change POST requests to GETs.
+    item->SetPostData(nil);
+    item->ResetHttpRequestHeaders();
+  }
+
+  _lastTransferTimeInSeconds = CFAbsoluteTimeGetCurrent();
+}
+
+// Returns YES if the current live view is a web view with an image MIME type.
+- (BOOL)contentIsImage {
+  if (!self.webView)
+    return NO;
+
+  const std::string image = "image";
+  std::string MIMEType = self.webState->GetContentsMimeType();
+  return MIMEType.compare(0, image.length(), image) == 0;
+}
+
 // WKNavigation objects are used as a weak key to store web::NavigationContext.
 // WKWebView manages WKNavigation lifetime and destroys them after the
 // navigation is finished. However for window opening navigations WKWebView
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index c85897d..dba8c9a 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -41,21 +41,6 @@
   return base::HexEncode(random_bytes, 16);
 }
 
-// Creates a pipe. Returns true on success, otherwise false.
-// On success, |read_fd| will be set to the fd of the read side, and
-// |write_fd| will be set to the one of write side.
-bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) {
-  int fds[2];
-  if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) {
-    PLOG(ERROR) << "pipe2()";
-    return false;
-  }
-
-  read_fd->reset(fds[0]);
-  write_fd->reset(fds[1]);
-  return true;
-}
-
 // Waits until |raw_socket_fd| is readable.  We signal |raw_cancel_fd| when we
 // want to cancel the blocking wait and stop serving connections on
 // |raw_socket_fd|.  To notify such a situation, |raw_cancel_fd| is also passed
@@ -294,9 +279,9 @@
   DCHECK(socket_fd.is_valid());
 
   base::ScopedFD cancel_fd;
-  if (!CreatePipe(&cancel_fd, &cancel_pipe_)) {
+  if (!base::CreatePipe(&cancel_fd, &cancel_pipe_, true)) {
+    PLOG(ERROR) << "Failed to create cancel pipe";
     started->Signal();
-    LOG(ERROR) << "Failed to create cancel pipe";
     return;
   }
 
diff --git a/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc b/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
index 6ea07cb..bd81dc3 100644
--- a/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
+++ b/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
@@ -86,17 +86,19 @@
   if (!result)
     return false;
 
-  const uint16_t width = parse_result.frame_header.visible_width;
-  const uint16_t height = parse_result.frame_header.visible_height;
-
-  if (width != decoded_image->image()->width ||
-      height != decoded_image->image()->height) {
-    DLOG(ERROR) << "Wrong expected decoded JPEG size, " << width << "x"
-                << height << " versus VaAPI provided "
+  const uint16_t coded_width = parse_result.frame_header.coded_width;
+  const uint16_t coded_height = parse_result.frame_header.coded_height;
+  if (coded_width != decoded_image->image()->width ||
+      coded_height != decoded_image->image()->height) {
+    DLOG(ERROR) << "Wrong expected decoded JPEG coded size, " << coded_width
+                << "x" << coded_height << " versus VaAPI provided "
                 << decoded_image->image()->width << "x"
                 << decoded_image->image()->height;
     return false;
   }
+
+  const uint16_t width = parse_result.frame_header.visible_width;
+  const uint16_t height = parse_result.frame_header.visible_height;
   const uint16_t even_width = (width + 1) / 2;
   const uint16_t even_height = (height + 1) / 2;
 
diff --git a/mojo/core/watcher_dispatcher.cc b/mojo/core/watcher_dispatcher.cc
index f2eb2e25..00d2a43 100644
--- a/mojo/core/watcher_dispatcher.cc
+++ b/mojo/core/watcher_dispatcher.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <limits>
 
+#include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -58,6 +59,9 @@
   watch->Cancel();
 }
 
+// handler_ may be address-taken in a different DSO, and hence incompatible with
+// CFI-icall.
+NO_SANITIZE("cfi-icall")
 void WatcherDispatcher::InvokeWatchCallback(uintptr_t context,
                                             MojoResult result,
                                             const HandleSignalsState& state,
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 4352288..64576ee 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2271,6 +2271,8 @@
 
     if (!disable_brotli_filter) {
       public_deps += [ "//third_party/brotli:dec" ]
+    } else {
+      public_deps += [ "//third_party/brotli:headers" ]
     }
   }
 }
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index eef8c494..15a8a67 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -398,7 +398,7 @@
 void CookieMonster::SetCanonicalCookieAsync(
     std::unique_ptr<CanonicalCookie> cookie,
     std::string source_scheme,
-    bool modify_http_only,
+    const CookieOptions& options,
     SetCookiesCallback callback) {
   DCHECK(cookie->IsCanonical());
 
@@ -409,7 +409,7 @@
           // the callback on |*this|, so the callback will not outlive
           // the object.
           &CookieMonster::SetCanonicalCookie, base::Unretained(this),
-          std::move(cookie), std::move(source_scheme), modify_http_only,
+          std::move(cookie), std::move(source_scheme), options,
           std::move(callback)),
       domain);
 }
@@ -702,8 +702,7 @@
   }
 
   DCHECK(cc);
-  SetCanonicalCookie(std::move(cc), url.scheme(), !options.exclude_httponly(),
-                     std::move(callback));
+  SetCanonicalCookie(std::move(cc), url.scheme(), options, std::move(callback));
 }
 
 void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
@@ -1177,7 +1176,7 @@
 
 void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
                                        std::string source_scheme,
-                                       bool modify_http_only,
+                                       const CookieOptions& options,
                                        SetCookiesCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -1190,7 +1189,7 @@
     return;
   }
 
-  if ((cc->IsHttpOnly() && !modify_http_only)) {
+  if (cc->IsHttpOnly() && options.exclude_httponly()) {
     MaybeRunCookieCallback(
         std::move(callback),
         CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
@@ -1215,9 +1214,9 @@
 
   base::Time creation_date_to_inherit;
 
-  CanonicalCookie::CookieInclusionStatus status =
-      DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
-                                already_expired, &creation_date_to_inherit);
+  CanonicalCookie::CookieInclusionStatus status = DeleteAnyEquivalentCookie(
+      key, *cc, secure_source, options.exclude_httponly(), already_expired,
+      &creation_date_to_inherit);
 
   if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
     std::string error;
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index d74a4dc..226c2adb 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -157,7 +157,7 @@
                                  SetCookiesCallback callback) override;
   void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
                                std::string source_scheme,
-                               bool modify_http_only,
+                               const CookieOptions& options,
                                SetCookiesCallback callback) override;
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const CookieOptions& options,
@@ -349,13 +349,15 @@
   static const int kRecordStatisticsIntervalSeconds = 10 * 60;
 
   // Sets a canonical cookie, deletes equivalents and performs garbage
-  // collection.  |source_secure| indicates if the cookie is being set
-  // from a secure source (e.g. a cryptographic scheme).
-  // |modify_http_only| indicates if this setting operation is allowed
-  // to affect http_only cookies.
+  // collection.  |source_scheme| indicates what scheme the cookie is being set
+  // from; secure cookies cannot be altered from insecure schemes, and some
+  // schemes may not be authorized.
+  //
+  // |options| indicates if this setting operation is allowed
+  // to affect http_only or same-site cookies.
   void SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cookie,
                           std::string source_scheme,
-                          bool can_modify_httponly,
+                          const CookieOptions& options,
                           SetCookiesCallback callback);
 
   void GetAllCookies(GetCookieListCallback callback);
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index f833a47..0d5c43e 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -187,7 +187,7 @@
     cm->SetCanonicalCookieAsync(
         CanonicalCookie::Create(url, cookie_line, creation_time,
                                 CookieOptions()),
-        url.scheme(), /* modify_httponly = */ false,
+        url.scheme(), CookieOptions(),
         base::BindOnce(&ResultSavingCookieCallback<
                            CanonicalCookie::CookieInclusionStatus>::Run,
                        base::Unretained(&callback)));
@@ -3259,7 +3259,7 @@
   cm.SetCanonicalCookieAsync(
       CanonicalCookie::Create(GURL("http://a.com/"), "A=B", base::Time::Now(),
                               CookieOptions()),
-      "http", false /* modify_httponly */,
+      "http", CookieOptions(),
       base::BindOnce(&ResultSavingCookieCallback<
                          CanonicalCookie::CookieInclusionStatus>::Run,
                      base::Unretained(&callback_set)));
@@ -3343,7 +3343,7 @@
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_callback_1;
   cm.SetCanonicalCookieAsync(
-      std::move(cookie), url.scheme(), !options.exclude_httponly(),
+      std::move(cookie), url.scheme(), options,
       base::BindOnce(&ResultSavingCookieCallback<
                          CanonicalCookie::CookieInclusionStatus>::Run,
                      base::Unretained(&set_callback_1)));
@@ -3354,7 +3354,7 @@
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_callback_2;
   cm.SetCanonicalCookieAsync(
-      std::move(cookie), url.scheme(), !options.exclude_httponly(),
+      std::move(cookie), url.scheme(), options,
       base::BindOnce(&ResultSavingCookieCallback<
                          CanonicalCookie::CookieInclusionStatus>::Run,
                      base::Unretained(&set_callback_2)));
diff --git a/net/cookies/cookie_options.h b/net/cookies/cookie_options.h
index 52d4fe54..2633272 100644
--- a/net/cookies/cookie_options.h
+++ b/net/cookies/cookie_options.h
@@ -28,8 +28,8 @@
   //
   // * Excludes HttpOnly cookies
   // * Excludes SameSite cookies
-  // * Does not enforce prefix restrictions (e.g. "$Secure-*")
   // * Updates last-accessed time.
+  // * Does not report excluded cookies in APIs that can do so.
   //
   // These settings can be altered by calling:
   //
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index fb89b5d..608e0c48 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -65,13 +65,15 @@
                                          SetCookiesCallback callback) = 0;
 
   // Set the cookie on the cookie store.  |cookie.IsCanonical()| must
-  // be true.  |source_scheme| denotes the scheme of the resource setting this,
-  // and |modify_http_only| indicates if the source of the setting may modify
-  // http_only cookies.  The current time will be used in place of a null
-  // creation time.
+  // be true.  |source_scheme| denotes the scheme of the resource setting this.
+  //
+  // |options| is used to determine the context the operation is run in, and
+  // which cookies it can alter (e.g. http only, or same site).
+  //
+  // The current time will be used in place of a null creation time.
   virtual void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
                                        std::string source_scheme,
-                                       bool modify_http_only,
+                                       const CookieOptions& options,
                                        SetCookiesCallback callback) = 0;
 
   // Obtains a CookieList for the given |url| and |options|. The returned
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 813bfe1..30ed2c21 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -106,11 +106,11 @@
 void DelayedCookieMonster::SetCanonicalCookieAsync(
     std::unique_ptr<CanonicalCookie> cookie,
     std::string source_scheme,
-    bool modify_http_only,
+    const CookieOptions& options,
     SetCookiesCallback callback) {
   did_run_ = false;
   cookie_monster_->SetCanonicalCookieAsync(
-      std::move(cookie), std::move(source_scheme), modify_http_only,
+      std::move(cookie), std::move(source_scheme), options,
       base::Bind(&DelayedCookieMonster::SetCookiesInternalCallback,
                  base::Unretained(this)));
   DCHECK_EQ(did_run_, true);
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index 28fc2c3..4cc6d58 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -59,7 +59,7 @@
 
   void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
                                std::string source_scheme,
-                               bool modify_http_only,
+                               const CookieOptions& options,
                                SetCookiesCallback callback) override;
 
   void GetCookieListWithOptionsAsync(const GURL& url,
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 5608fea..682823e 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -215,8 +215,11 @@
                           bool can_modify_httponly) {
     DCHECK(cs);
     ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
+    CookieOptions options;
+    if (can_modify_httponly)
+      options.set_include_httponly();
     cs->SetCanonicalCookieAsync(
-        std::move(cookie), std::move(source_scheme), can_modify_httponly,
+        std::move(cookie), std::move(source_scheme), options,
         base::BindOnce(&ResultSavingCookieCallback<
                            CanonicalCookie::CookieInclusionStatus>::Run,
                        base::Unretained(&callback)));
@@ -270,8 +273,11 @@
       bool can_modify_httponly) {
     DCHECK(cs);
     ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
+    CookieOptions options;
+    if (can_modify_httponly)
+      options.set_include_httponly();
     cs->SetCanonicalCookieAsync(
-        std::move(cookie), std::move(source_scheme), can_modify_httponly,
+        std::move(cookie), std::move(source_scheme), options,
         base::BindOnce(&ResultSavingCookieCallback<
                            CanonicalCookie::CookieInclusionStatus>::Run,
                        base::Unretained(&callback)));
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc
index 58aa83e..75d61ab 100644
--- a/net/http/http_proxy_connect_job_unittest.cc
+++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -805,12 +805,6 @@
   // Make request hang during host resolution, so can observe priority there.
   session_deps_.host_resolver->set_ondemand_mode(true);
 
-  // Needed to destroy the ConnectJob in the nested socket pools.
-  // TODO(https://crbug.com/927088): Remove this once there are no nested socket
-  // pools.
-  session_deps_.host_resolver->rules()->AddSimulatedFailure(kHttpProxyHost);
-  session_deps_.host_resolver->rules()->AddSimulatedFailure(kHttpsProxyHost);
-
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
@@ -835,13 +829,6 @@
       connect_job->ChangePriority(
           static_cast<RequestPriority>(initial_priority));
       EXPECT_EQ(initial_priority, host_resolver->request_priority(request_id));
-
-      // Complete the resolution, which should result in destroying the
-      // connecting socket. Can't just delete the ConnectJob, since that won't
-      // destroy the ConnectJobs in the underlying pools.
-      host_resolver->ResolveAllPending();
-      EXPECT_THAT(test_delegate.WaitForResult(),
-                  test::IsError(ERR_PROXY_CONNECTION_FAILED));
     }
   }
 }
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index e8f1cae..0ce0c96 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -218,15 +218,15 @@
 
 void CompareCertificateChainWithList(
     const scoped_refptr<X509Certificate>& cert_chain,
-    const base::ListValue* cert_list) {
+    const base::Value* cert_list) {
   ASSERT_TRUE(cert_chain);
+  ASSERT_TRUE(cert_list->is_list());
   std::vector<std::string> pem_encoded_chain;
   cert_chain->GetPEMEncodedChain(&pem_encoded_chain);
-  EXPECT_EQ(pem_encoded_chain.size(), cert_list->GetSize());
+  ASSERT_EQ(pem_encoded_chain.size(), cert_list->GetList().size());
 
   for (size_t i = 0; i < pem_encoded_chain.size(); i++) {
-    std::string list_cert;
-    ASSERT_TRUE(cert_list->GetString(i, &list_cert));
+    const std::string& list_cert = cert_list->GetList()[i].GetString();
     EXPECT_EQ(pem_encoded_chain[i], list_cert);
   }
 }
@@ -239,50 +239,49 @@
     const scoped_refptr<X509Certificate>& served_certificate_chain,
     const scoped_refptr<X509Certificate>& validated_certificate_chain,
     const HashValueVector& known_pins) {
-  std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(report));
-  ASSERT_TRUE(value);
-  ASSERT_TRUE(value->is_dict());
+  base::Optional<base::Value> value = base::JSONReader::Read(report);
+  ASSERT_TRUE(value.has_value());
+  const base::Value& report_dict = value.value();
+  ASSERT_TRUE(report_dict.is_dict());
 
-  base::DictionaryValue* report_dict;
-  ASSERT_TRUE(value->GetAsDictionary(&report_dict));
+  const std::string* report_hostname = report_dict.FindStringKey("hostname");
+  ASSERT_TRUE(report_hostname);
+  EXPECT_EQ(host_port_pair.host(), *report_hostname);
 
-  std::string report_hostname;
-  EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname));
-  EXPECT_EQ(host_port_pair.host(), report_hostname);
+  base::Optional<int> report_port = report_dict.FindIntKey("port");
+  ASSERT_TRUE(report_port.has_value());
+  EXPECT_EQ(host_port_pair.port(), report_port.value());
 
-  int report_port;
-  EXPECT_TRUE(report_dict->GetInteger("port", &report_port));
-  EXPECT_EQ(host_port_pair.port(), report_port);
+  base::Optional<bool> report_include_subdomains =
+      report_dict.FindBoolKey("include-subdomains");
+  ASSERT_TRUE(report_include_subdomains.has_value());
+  EXPECT_EQ(include_subdomains, report_include_subdomains.value());
 
-  bool report_include_subdomains;
-  EXPECT_TRUE(report_dict->GetBoolean("include-subdomains",
-                                      &report_include_subdomains));
-  EXPECT_EQ(include_subdomains, report_include_subdomains);
-
-  std::string report_noted_hostname;
-  EXPECT_TRUE(report_dict->GetString("noted-hostname", &report_noted_hostname));
-  EXPECT_EQ(noted_hostname, report_noted_hostname);
+  const std::string* report_noted_hostname =
+      report_dict.FindStringKey("noted-hostname");
+  ASSERT_TRUE(report_noted_hostname);
+  EXPECT_EQ(noted_hostname, *report_noted_hostname);
 
   // TODO(estark): check times in RFC3339 format.
 
-  std::string report_expiration;
-  EXPECT_TRUE(
-      report_dict->GetString("effective-expiration-date", &report_expiration));
-  EXPECT_FALSE(report_expiration.empty());
+  const std::string* report_expiration =
+      report_dict.FindStringKey("effective-expiration-date");
+  ASSERT_TRUE(report_expiration);
+  EXPECT_FALSE(report_expiration->empty());
 
-  std::string report_date;
-  EXPECT_TRUE(report_dict->GetString("date-time", &report_date));
-  EXPECT_FALSE(report_date.empty());
+  const std::string* report_date = report_dict.FindStringKey("date-time");
+  ASSERT_TRUE(report_date);
+  EXPECT_FALSE(report_date->empty());
 
-  base::ListValue* report_served_certificate_chain;
-  EXPECT_TRUE(report_dict->GetList("served-certificate-chain",
-                                   &report_served_certificate_chain));
+  const base::Value* report_served_certificate_chain =
+      report_dict.FindKey("served-certificate-chain");
+  ASSERT_TRUE(report_served_certificate_chain);
   ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList(
       served_certificate_chain, report_served_certificate_chain));
 
-  base::ListValue* report_validated_certificate_chain;
-  EXPECT_TRUE(report_dict->GetList("validated-certificate-chain",
-                                   &report_validated_certificate_chain));
+  const base::Value* report_validated_certificate_chain =
+      report_dict.FindKey("validated-certificate-chain");
+  ASSERT_TRUE(report_validated_certificate_chain);
   ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList(
       validated_certificate_chain, report_validated_certificate_chain));
 }
diff --git a/net/socket/ssl_connect_job_unittest.cc b/net/socket/ssl_connect_job_unittest.cc
index bd0b411..1a3b1d1 100644
--- a/net/socket/ssl_connect_job_unittest.cc
+++ b/net/socket/ssl_connect_job_unittest.cc
@@ -322,10 +322,6 @@
 
 TEST_F(SSLConnectJobTest, RequestPriority) {
   host_resolver_.set_ondemand_mode(true);
-  // Make resolution eventually fail, so old jobs can easily be removed from the
-  // socket pool.
-  host_resolver_.rules()->AddSimulatedFailure(
-      direct_transport_socket_params_->destination().host());
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
@@ -350,12 +346,6 @@
       ssl_connect_job->ChangePriority(
           static_cast<RequestPriority>(initial_priority));
       EXPECT_EQ(initial_priority, host_resolver_.request_priority(request_id));
-
-      // Complete the resolution, which should result in destroying the
-      // connecting socket.
-      host_resolver_.ResolveAllPending();
-      ASSERT_THAT(test_delegate.WaitForResult(),
-                  test::IsError(ERR_NAME_NOT_RESOLVED));
     }
   }
 }
@@ -554,10 +544,6 @@
 
 TEST_F(SSLConnectJobTest, SOCKSRequestPriority) {
   host_resolver_.set_ondemand_mode(true);
-  // Make resolution eventually fail, so old jobs can easily be removed from the
-  // socket pool.
-  host_resolver_.rules()->AddSimulatedFailure(
-      socks_socket_params_->transport_params()->destination().host());
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
@@ -582,12 +568,6 @@
       ssl_connect_job->ChangePriority(
           static_cast<RequestPriority>(initial_priority));
       EXPECT_EQ(initial_priority, host_resolver_.request_priority(request_id));
-
-      // Complete the resolution, which should result in destroying the
-      // connecting socket.
-      host_resolver_.ResolveAllPending();
-      ASSERT_THAT(test_delegate.WaitForResult(),
-                  test::IsError(ERR_PROXY_CONNECTION_FAILED));
     }
   }
 }
@@ -699,10 +679,6 @@
 
 TEST_F(SSLConnectJobTest, HttpProxyRequestPriority) {
   host_resolver_.set_ondemand_mode(true);
-  // Make resolution eventually fail, so old jobs can easily be removed from the
-  // socket pool.
-  host_resolver_.rules()->AddSimulatedFailure(
-      socks_socket_params_->transport_params()->destination().host());
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
@@ -727,12 +703,6 @@
       ssl_connect_job->ChangePriority(
           static_cast<RequestPriority>(initial_priority));
       EXPECT_EQ(initial_priority, host_resolver_.request_priority(request_id));
-
-      // Complete the resolution, which should result in destroying the
-      // connecting socket.
-      host_resolver_.ResolveAllPending();
-      ASSERT_THAT(test_delegate.WaitForResult(),
-                  test::IsError(ERR_PROXY_CONNECTION_FAILED));
     }
   }
 }
diff --git a/net/ssl/ssl_platform_key_nss.cc b/net/ssl/ssl_platform_key_nss.cc
index 56605c61..2f720ff 100644
--- a/net/ssl/ssl_platform_key_nss.cc
+++ b/net/ssl/ssl_platform_key_nss.cc
@@ -54,7 +54,8 @@
                     crypto::ScopedSECKEYPrivateKey key)
       : type_(type),
         password_delegate_(std::move(password_delegate)),
-        key_(std::move(key)) {}
+        key_(std::move(key)),
+        supports_pss_(PK11_DoesMechanism(key_->pkcs11Slot, CKM_RSA_PKCS_PSS)) {}
   ~SSLPlatformKeyNSS() override = default;
 
   std::string GetProviderName() override {
@@ -66,8 +67,7 @@
   }
 
   std::vector<uint16_t> GetAlgorithmPreferences() override {
-    return SSLPrivateKey::DefaultAlgorithmPreferences(type_,
-                                                      true /* supports PSS */);
+    return SSLPrivateKey::DefaultAlgorithmPreferences(type_, supports_pss_);
   }
 
   Error Sign(uint16_t algorithm,
@@ -182,6 +182,7 @@
   scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate>
       password_delegate_;
   crypto::ScopedSECKEYPrivateKey key_;
+  bool supports_pss_;
 
   DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyNSS);
 };
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 14f4d89..76994eb 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -681,6 +681,10 @@
   CookieOptions options;
   options.set_include_httponly();
   options.set_server_time(response_date);
+  options.set_same_site_cookie_context(
+      net::cookie_util::ComputeSameSiteContextForRequest(
+          request_->method(), request_->url(), request_->site_for_cookies(),
+          request_->initiator(), request_->attach_same_site_cookies()));
 
   // Set all cookies, without waiting for them to be set. Any subsequent read
   // will see the combined result of all cookie operation.
diff --git a/remoting/base/buffered_socket_writer_unittest.cc b/remoting/base/buffered_socket_writer_unittest.cc
index 8f9a5cd..ce22d609 100644
--- a/remoting/base/buffered_socket_writer_unittest.cc
+++ b/remoting/base/buffered_socket_writer_unittest.cc
@@ -104,7 +104,7 @@
                                                &socket_data_provider_));
     socket_data_provider_.set_connect_data(
         net::MockConnect(net::SYNCHRONOUS, net::OK));
-    EXPECT_EQ(net::OK, socket_->Connect(net::CompletionCallback()));
+    EXPECT_EQ(net::OK, socket_->Connect(net::CompletionOnceCallback()));
 
     writer_.reset(new BufferedSocketWriter());
     test_buffer_ = base::MakeRefCounted<net::IOBufferWithSize>(kTestBufferSize);
diff --git a/remoting/protocol/channel_socket_adapter.cc b/remoting/protocol/channel_socket_adapter.cc
index 5922be7..017c8e0 100644
--- a/remoting/protocol/channel_socket_adapter.cc
+++ b/remoting/protocol/channel_socket_adapter.cc
@@ -39,8 +39,9 @@
 }
 
 int TransportChannelSocketAdapter::Recv(
-    const scoped_refptr<net::IOBuffer>& buf, int buffer_size,
-    const net::CompletionCallback& callback) {
+    const scoped_refptr<net::IOBuffer>& buf,
+    int buffer_size,
+    const net::CompletionRepeatingCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(buf);
   DCHECK(!callback.is_null());
@@ -59,8 +60,9 @@
 }
 
 int TransportChannelSocketAdapter::Send(
-    const scoped_refptr<net::IOBuffer>& buffer, int buffer_size,
-    const net::CompletionCallback& callback) {
+    const scoped_refptr<net::IOBuffer>& buffer,
+    int buffer_size,
+    const net::CompletionRepeatingCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(buffer);
   DCHECK(!callback.is_null());
@@ -108,14 +110,14 @@
   channel_ = NULL;
 
   if (!read_callback_.is_null()) {
-    net::CompletionCallback callback = read_callback_;
+    net::CompletionRepeatingCallback callback = read_callback_;
     read_callback_.Reset();
     read_buffer_ = NULL;
     callback.Run(error_code);
   }
 
   if (!write_callback_.is_null()) {
-    net::CompletionCallback callback = write_callback_;
+    net::CompletionRepeatingCallback callback = write_callback_;
     write_callback_.Reset();
     write_buffer_ = NULL;
     callback.Run(error_code);
@@ -142,10 +144,9 @@
 
     memcpy(read_buffer_->data(), data, data_size);
 
-    net::CompletionCallback callback = read_callback_;
+    net::CompletionRepeatingCallback callback = read_callback_;
     read_callback_.Reset();
     read_buffer_ = NULL;
-
     callback.Run(data_size);
   } else {
     LOG(WARNING)
@@ -166,7 +167,7 @@
       result = net::MapSystemError(channel_->GetError());
 
     if (result != net::ERR_IO_PENDING) {
-      net::CompletionCallback callback = write_callback_;
+      net::CompletionRepeatingCallback callback = write_callback_;
       write_callback_.Reset();
       write_buffer_ = NULL;
       callback.Run(result);
diff --git a/remoting/protocol/channel_socket_adapter.h b/remoting/protocol/channel_socket_adapter.h
index dca73a1..b61657d 100644
--- a/remoting/protocol/channel_socket_adapter.h
+++ b/remoting/protocol/channel_socket_adapter.h
@@ -50,10 +50,12 @@
   void Close(int error_code);
 
   // P2PDatagramSocket interface.
-  int Recv(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-           const net::CompletionCallback& callback) override;
-  int Send(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-           const net::CompletionCallback& callback) override;
+  int Recv(const scoped_refptr<net::IOBuffer>& buf,
+           int buf_len,
+           const net::CompletionRepeatingCallback& callback) override;
+  int Send(const scoped_refptr<net::IOBuffer>& buf,
+           int buf_len,
+           const net::CompletionRepeatingCallback& callback) override;
 
  private:
   void OnNewPacket(rtc::PacketTransportInterface* transport,
@@ -70,11 +72,11 @@
 
   base::Closure destruction_callback_;
 
-  net::CompletionCallback read_callback_;
+  net::CompletionRepeatingCallback read_callback_;
   scoped_refptr<net::IOBuffer> read_buffer_;
   int read_buffer_size_;
 
-  net::CompletionCallback write_callback_;
+  net::CompletionRepeatingCallback write_callback_;
   scoped_refptr<net::IOBuffer> write_buffer_;
   int write_buffer_size_;
 
diff --git a/remoting/protocol/channel_socket_adapter_unittest.cc b/remoting/protocol/channel_socket_adapter_unittest.cc
index bb31167a..56bdca1 100644
--- a/remoting/protocol/channel_socket_adapter_unittest.cc
+++ b/remoting/protocol/channel_socket_adapter_unittest.cc
@@ -53,7 +53,7 @@
 
   cricket::MockIceTransport channel_;
   std::unique_ptr<TransportChannelSocketAdapter> target_;
-  net::CompletionCallback callback_;
+  net::CompletionRepeatingCallback callback_;
   int callback_result_;
   base::MessageLoopForIO message_loop_;
 };
diff --git a/remoting/protocol/fake_datagram_socket.cc b/remoting/protocol/fake_datagram_socket.cc
index fddd67a..b81619c 100644
--- a/remoting/protocol/fake_datagram_socket.cc
+++ b/remoting/protocol/fake_datagram_socket.cc
@@ -55,7 +55,7 @@
 
 int FakeDatagramSocket::Recv(const scoped_refptr<net::IOBuffer>& buf,
                              int buf_len,
-                             const net::CompletionCallback& callback) {
+                             const net::CompletionRepeatingCallback& callback) {
   EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
   if (input_pos_ < static_cast<int>(input_packets_.size())) {
     return CopyReadData(buf, buf_len);
@@ -69,7 +69,7 @@
 
 int FakeDatagramSocket::Send(const scoped_refptr<net::IOBuffer>& buf,
                              int buf_len,
-                             const net::CompletionCallback& callback) {
+                             const net::CompletionRepeatingCallback& callback) {
   EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
   EXPECT_FALSE(send_pending_);
 
@@ -85,9 +85,10 @@
   }
 }
 
-void FakeDatagramSocket::DoAsyncSend(const scoped_refptr<net::IOBuffer>& buf,
-                                     int buf_len,
-                                     const net::CompletionCallback& callback) {
+void FakeDatagramSocket::DoAsyncSend(
+    const scoped_refptr<net::IOBuffer>& buf,
+    int buf_len,
+    const net::CompletionRepeatingCallback& callback) {
   EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
 
   EXPECT_TRUE(send_pending_);
diff --git a/remoting/protocol/fake_datagram_socket.h b/remoting/protocol/fake_datagram_socket.h
index 0df2d0e..81c79497 100644
--- a/remoting/protocol/fake_datagram_socket.h
+++ b/remoting/protocol/fake_datagram_socket.h
@@ -12,7 +12,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_repeating_callback.h"
 #include "remoting/protocol/datagram_channel_factory.h"
 #include "remoting/protocol/p2p_datagram_socket.h"
 
@@ -62,16 +62,19 @@
   base::WeakPtr<FakeDatagramSocket> GetWeakPtr();
 
   // P2PDatagramSocket implementation.
-  int Recv(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-           const net::CompletionCallback& callback) override;
-  int Send(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-           const net::CompletionCallback& callback) override;
+  int Recv(const scoped_refptr<net::IOBuffer>& buf,
+           int buf_len,
+           const net::CompletionRepeatingCallback& callback) override;
+  int Send(const scoped_refptr<net::IOBuffer>& buf,
+           int buf_len,
+           const net::CompletionRepeatingCallback& callback) override;
 
  private:
   int CopyReadData(const scoped_refptr<net::IOBuffer>& buf, int buf_len);
 
-  void DoAsyncSend(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-                   const net::CompletionCallback& callback);
+  void DoAsyncSend(const scoped_refptr<net::IOBuffer>& buf,
+                   int buf_len,
+                   const net::CompletionRepeatingCallback& callback);
   int DoSend(const scoped_refptr<net::IOBuffer>& buf, int buf_len);
 
   bool async_send_ = false;
@@ -82,7 +85,7 @@
 
   scoped_refptr<net::IOBuffer> read_buffer_;
   int read_buffer_size_;
-  net::CompletionCallback read_callback_;
+  net::CompletionRepeatingCallback read_callback_;
 
   std::vector<std::string> written_packets_;
   std::vector<std::string> input_packets_;
diff --git a/remoting/protocol/p2p_datagram_socket.h b/remoting/protocol/p2p_datagram_socket.h
index 606ccbb..10e39da 100644
--- a/remoting/protocol/p2p_datagram_socket.h
+++ b/remoting/protocol/p2p_datagram_socket.h
@@ -5,7 +5,7 @@
 #ifndef REMOTING_PROTOCOL_P2P_DATAGRAM_SOCKET_H_
 #define REMOTING_PROTOCOL_P2P_DATAGRAM_SOCKET_H_
 
-#include "net/base/completion_callback.h"
+#include "net/base/completion_repeating_callback.h"
 
 namespace net {
 class IOBuffer;
@@ -29,8 +29,9 @@
   // acquires a reference to the provided buffer until the callback is invoked
   // or the socket is closed. If the socket is destroyed before the read
   // completes, the callback will not be invoked.
-  virtual int Recv(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-                   const net::CompletionCallback& callback) = 0;
+  virtual int Recv(const scoped_refptr<net::IOBuffer>& buf,
+                   int buf_len,
+                   const net::CompletionRepeatingCallback& callback) = 0;
 
   // Sends a packet. Returns |buf_len| to indicate success, otherwise a net
   // error code is returned. ERR_IO_PENDING is returned if the operation could
@@ -39,8 +40,9 @@
   // the socket acquires a reference to the provided buffer until the callback
   // is invoked or the socket is closed. Implementations of this method should
   // not modify the contents of the actual buffer that is written to the socket.
-  virtual int Send(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-                   const net::CompletionCallback& callback) = 0;
+  virtual int Send(const scoped_refptr<net::IOBuffer>& buf,
+                   int buf_len,
+                   const net::CompletionRepeatingCallback& callback) = 0;
 };
 
 }  // namespace protocol
diff --git a/remoting/protocol/pseudotcp_adapter_unittest.cc b/remoting/protocol/pseudotcp_adapter_unittest.cc
index f8cfa1a..ffbf9319 100644
--- a/remoting/protocol/pseudotcp_adapter_unittest.cc
+++ b/remoting/protocol/pseudotcp_adapter_unittest.cc
@@ -92,7 +92,7 @@
     if (!read_callback_.is_null()) {
       int size = std::min(read_buffer_size_, static_cast<int>(data.size()));
       memcpy(read_buffer_->data(), &data[0], data.size());
-      net::CompletionCallback cb = read_callback_;
+      net::CompletionRepeatingCallback cb = read_callback_;
       read_callback_.Reset();
       read_buffer_ = NULL;
       cb.Run(size);
@@ -112,8 +112,9 @@
   void set_latency(int latency_ms) { latency_ms_ = latency_ms; }
 
   // P2PDatagramSocket interface.
-  int Recv(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-           const net::CompletionCallback& callback) override {
+  int Recv(const scoped_refptr<net::IOBuffer>& buf,
+           int buf_len,
+           const net::CompletionRepeatingCallback& callback) override {
     CHECK(read_callback_.is_null());
     CHECK(buf);
 
@@ -132,8 +133,9 @@
     }
   }
 
-  int Send(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
-           const net::CompletionCallback& callback) override {
+  int Send(const scoped_refptr<net::IOBuffer>& buf,
+           int buf_len,
+           const net::CompletionRepeatingCallback& callback) override {
     DCHECK(buf);
     if (peer_socket_) {
       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
@@ -150,7 +152,7 @@
  private:
   scoped_refptr<net::IOBuffer> read_buffer_;
   int read_buffer_size_;
-  net::CompletionCallback read_callback_;
+  net::CompletionRepeatingCallback read_callback_;
 
   base::circular_deque<std::vector<char>> incoming_packets_;
 
@@ -224,7 +226,7 @@
                                     kMessageSize);
       result = client_socket_->Write(
           output_buffer_.get(), bytes_to_write,
-          base::Bind(&TCPChannelTester::OnWritten, base::Unretained(this)),
+          base::BindOnce(&TCPChannelTester::OnWritten, base::Unretained(this)),
           TRAFFIC_ANNOTATION_FOR_TESTS);
       HandleWriteResult(result);
     }
@@ -397,8 +399,8 @@
   DeleteOnConnected host_delete(base::ThreadTaskRunnerHandle::Get(),
                                 &host_pseudotcp_);
 
-  host_pseudotcp_->Connect(base::Bind(&DeleteOnConnected::OnConnected,
-                                      base::Unretained(&host_delete)));
+  host_pseudotcp_->Connect(base::BindOnce(&DeleteOnConnected::OnConnected,
+                                          base::Unretained(&host_delete)));
   client_pseudotcp_->Connect(client_connect_cb.callback());
   base::RunLoop().Run();
 
diff --git a/remoting/signaling/grpc_support/BUILD.gn b/remoting/signaling/grpc_support/BUILD.gn
index aa33721c..d70380b7 100644
--- a/remoting/signaling/grpc_support/BUILD.gn
+++ b/remoting/signaling/grpc_support/BUILD.gn
@@ -57,6 +57,7 @@
     ":grpc_support",
     ":test_support",
     ":unit_tests_grpc_library",
+    "//testing/gmock",
     "//testing/gtest",
   ]
 }
diff --git a/remoting/signaling/grpc_support/README.md b/remoting/signaling/grpc_support/README.md
index 47845b29..0166fd9c 100644
--- a/remoting/signaling/grpc_support/README.md
+++ b/remoting/signaling/grpc_support/README.md
@@ -14,20 +14,17 @@
 ```cpp
 class MyClass {
   public:
-  MyClass() : weak_factory_(this) {}
-  ~MyClass() {}
+  MyClass() = default;
+  ~MyClass() = default;
 
   void SayHello() {
     HelloRequest request;
     dispatcher_->ExecuteAsyncRpc(
-        // This is run immediately inside the call stack of |ExecuteAsyncRpc|.
         base::BindOnce(&HelloService::Stub::AsyncSayHello,
                         base::Unretained(stub_.get())),
         std::make_unique<grpc::ClientContext>(), request,
-        // Callback might be called after the dispatcher is destroyed. Make sure
-        // to bind WeakPtr here.
         base::BindOnce(&MyClass::OnHelloResult,
-                        weak_factory_.GetWeakPtr()));
+                        base::Unretained(this)));
   }
 
   void StartHelloStream() {
@@ -37,9 +34,9 @@
                       base::Unretained(stub_.get())),
         std::make_unique<grpc::ClientContext>(), request,
         base::BindRepeating(&MyClass::OnHelloStreamMessage,
-                            weak_factory_.GetWeakPtr()),
+                            base::Unretained(this)),
         base::BindOnce(&MyClass::OnHelloStreamClosed,
-                        weak_factory_.GetWeakPtr()));
+                        base::Unretained(this)));
   }
 
   void CloseHelloStream() {
@@ -48,14 +45,9 @@
 
   private:
   void OnHelloResult(const grpc::Status& status,
-                      const HelloResponse& response) {
-    if (status.error_code() == grpc::StatusCode::CANCELLED) {
-      // The request has been canceled because |dispatcher_| is destroyed.
-      return;
-    }
-
+                     const HelloResponse& response) {
     if (!status.ok()) {
-      // Handle other error here.
+      // Handle error here.
       return;
     }
 
@@ -68,24 +60,16 @@
   }
 
   void OnHelloStreamClosed(const grpc::Status& status) {
-    switch (status.error_code()) {
-      case grpc::StatusCode::CANCELLED:
-        // The stream is closed by the client, either because the scoped stream
-        // is deleted or the dispatcher is deleted.
-        break;
-      case grpc::StatusCode::UNAVAILABLE:
-        // The stream is either closed by the server or dropped due to
-        // network issues.
-        break;
-      default:
-        NOTREACHED();
-        break;
+    if (!status.ok()) {
+      // Handle error here.
+      return;
     }
+
+    // Stream is closed by the server.
   }
 
   std::unique_ptr<HelloService::Stub> stub_;
   GrpcAsyncDispatcher dispatcher_;
   std::unique_ptr<ScopedGrpcServerStream> scoped_hello_stream_;
-  base::WeakPtrFactory<MyClass> weak_factory_;
 };
 ```
diff --git a/remoting/signaling/grpc_support/grpc_async_call_data.cc b/remoting/signaling/grpc_support/grpc_async_call_data.cc
index 8bdab2d..5682a73 100644
--- a/remoting/signaling/grpc_support/grpc_async_call_data.cc
+++ b/remoting/signaling/grpc_support/grpc_async_call_data.cc
@@ -25,12 +25,28 @@
 }
 
 void GrpcAsyncCallData::DeleteOnCallerThread() {
-  if (caller_task_runner_->BelongsToCurrentThread()) {
-    delete this;
-    return;
-  }
   caller_task_runner_->DeleteSoon(FROM_HERE, this);
 }
 
+void GrpcAsyncCallData::Start() {
+  DCHECK(!is_get_event_tag_allowed_);
+  is_get_event_tag_allowed_ = true;
+  StartInternal();
+  is_get_event_tag_allowed_ = false;
+}
+
+bool GrpcAsyncCallData::OnDequeuedOnDispatcherThread(bool operation_succeeded) {
+  DCHECK(!is_get_event_tag_allowed_);
+  is_get_event_tag_allowed_ = true;
+  bool result = OnDequeuedOnDispatcherThreadInternal(operation_succeeded);
+  is_get_event_tag_allowed_ = false;
+  return result;
+}
+
+void* GrpcAsyncCallData::GetEventTag() {
+  DCHECK(is_get_event_tag_allowed_);
+  return this;
+}
+
 }  // namespace internal
 }  // namespace remoting
diff --git a/remoting/signaling/grpc_support/grpc_async_call_data.h b/remoting/signaling/grpc_support/grpc_async_call_data.h
index ad879589..b4052c2 100644
--- a/remoting/signaling/grpc_support/grpc_async_call_data.h
+++ b/remoting/signaling/grpc_support/grpc_async_call_data.h
@@ -30,6 +30,9 @@
 // re-enqueue itself, OnDequeuedOnDispatcherThread() should return false, which
 // will delete the call data by calling DeleteOnCallerThread().
 //
+// Subclass is not allowed to enqueue itself outside the call stack of
+// StartInternal() and OnDequeuedOnDispatcherThread().
+//
 // Ctor, dtor, and methods except OnDequeuedOnDispatcherThread() will be called
 // from the same thread (caller_task_runner_).
 class GrpcAsyncCallData {
@@ -40,24 +43,42 @@
   // Force dequeues any pending request.
   void CancelRequest();
 
-  // Can be called from any thread.
+  // Posts a task to delete |this| on the caller thread.
   void DeleteOnCallerThread();
 
+  void Start();
+
   // Returns true iff the task is not finished and the subclass will
   // *immediately* enqueue itself back to the completion queue. If this method
   // returns false, the object will be deleted by calling
-  // DeleteOnCallerThread().
+  // DeleteOnCallerThread(). Tasks posted within this method will be scheduled
+  // before DeleteOnCallerThread()'s deletion task, so subclass still has a
+  // chance to run on the caller thread before it gets deleted.
   // Note that this will be called from an anonymous thread.
-  virtual bool OnDequeuedOnDispatcherThread(bool operation_succeeded) = 0;
+  bool OnDequeuedOnDispatcherThread(bool operation_succeeded);
 
  protected:
+  // Gets an event tag for enqueueing |this| to the completion queue. This has
+  // to be called within StartInternal() and
+  // OnDequeuedOnDispatcherThreadInternal() without task posting, otherwise it
+  // will fail a DCHECK.
+  void* GetEventTag();
+
+  // The first enqueue must be done within this method.
+  virtual void StartInternal() = 0;
+
+  // See OnDequeuedOnDispatcherThread().
+  virtual bool OnDequeuedOnDispatcherThreadInternal(
+      bool operation_succeeded) = 0;
+
   // Called after CancelRequest() is called.
-  virtual void OnRequestCanceled() {}
+  virtual void OnRequestCanceled() = 0;
 
   scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
   grpc::Status status_{grpc::StatusCode::UNKNOWN, "Uninitialized"};
 
  private:
+  bool is_get_event_tag_allowed_ = false;
   std::unique_ptr<grpc::ClientContext> context_;
 
   DISALLOW_COPY_AND_ASSIGN(GrpcAsyncCallData);
diff --git a/remoting/signaling/grpc_support/grpc_async_dispatcher.cc b/remoting/signaling/grpc_support/grpc_async_dispatcher.cc
index d0d9b1a..6cab88b 100644
--- a/remoting/signaling/grpc_support/grpc_async_dispatcher.cc
+++ b/remoting/signaling/grpc_support/grpc_async_dispatcher.cc
@@ -60,7 +60,7 @@
   DCHECK(pending_rpcs_.find(rpc_data.get()) == pending_rpcs_.end());
   pending_rpcs_.insert(rpc_data.get());
   // Ownership of |rpc_data| is transferred to the completion queue.
-  rpc_data.release();
+  rpc_data.release()->Start();
 }
 
 }  // namespace remoting
diff --git a/remoting/signaling/grpc_support/grpc_async_dispatcher.h b/remoting/signaling/grpc_support/grpc_async_dispatcher.h
index fe3d36c..891ea26 100644
--- a/remoting/signaling/grpc_support/grpc_async_dispatcher.h
+++ b/remoting/signaling/grpc_support/grpc_async_dispatcher.h
@@ -54,13 +54,9 @@
   GrpcAsyncDispatcher();
   ~GrpcAsyncDispatcher();
 
-  // Immediately executes |rpc_function| inside the call stack of this function,
-  // and runs |callback| once the server responses. If the dispatcher is
-  // destroyed before the server responses, |callback| will be called with
-  // a CANCELLED status *after* the dispatcher is destroyed.
-  //
-  // It is safe to bind raw pointer into |rpc_function|, but you should bind
-  // weak pointer in |callback|.
+  // Executes |rpc_function| before this function returns, and runs |callback|
+  // once the server responds. Callback will be silently dropped if the
+  // dispatcher is destroyed before the response is received.
   template <typename RequestType, typename ResponseType>
   void ExecuteAsyncRpc(AsyncRpcFunction<RequestType, ResponseType> rpc_function,
                        std::unique_ptr<grpc::ClientContext> context,
@@ -80,13 +76,10 @@
   //
   // |on_incoming_msg| is called whenever a new message is received from the
   // server.
-  // |on_channel_closed| will be called with CANCELLED if the stream is stopped
-  // by the client, either by deleting the stream holder or deleting the
-  // dispatcher.
-  //
-  // |rpc_function| is called immediately inside the call stack, while
-  // |on_incoming_msg| and |on_channel_closed| might be called after the
-  // dispatcher is deleted.
+  // |on_channel_closed| will be called if the channel is closed by the server
+  // or the connection is dropped.
+  // All callbacks will be silently dropped if the dispatcher is destroyed
+  // before the response is received.
   template <typename RequestType, typename ResponseType>
   std::unique_ptr<ScopedGrpcServerStream> ExecuteAsyncServerStreamingRpc(
       AsyncServerStreamingRpcFunction<RequestType, ResponseType> rpc_function,
@@ -94,14 +87,12 @@
       const RequestType& request,
       const RpcStreamCallback<ResponseType>& on_incoming_msg,
       RpcChannelClosedCallback on_channel_closed) WARN_UNUSED_RESULT {
-    grpc::ClientContext* raw_context = context.get();
+    auto start_and_create_reader_cb = base::BindOnce(
+        std::move(rpc_function), context.get(), request, &completion_queue_);
     auto data = std::make_unique<
         internal::GrpcAsyncServerStreamingCallData<ResponseType>>(
-        std::move(context), on_incoming_msg, std::move(on_channel_closed));
-    auto reader =
-        std::move(rpc_function)
-            .Run(raw_context, request, &completion_queue_, data.get());
-    data->Initialize(std::move(reader));
+        std::move(context), std::move(start_and_create_reader_cb),
+        on_incoming_msg, std::move(on_channel_closed));
     std::unique_ptr<ScopedGrpcServerStream> stream_holder =
         data->CreateStreamHolder();
     RegisterRpcData(std::move(data));
diff --git a/remoting/signaling/grpc_support/grpc_async_dispatcher_unittest.cc b/remoting/signaling/grpc_support/grpc_async_dispatcher_unittest.cc
index d4a5a16..59715c9 100644
--- a/remoting/signaling/grpc_support/grpc_async_dispatcher_unittest.cc
+++ b/remoting/signaling/grpc_support/grpc_async_dispatcher_unittest.cc
@@ -13,10 +13,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
+#include "base/test/mock_callback.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "remoting/signaling/grpc_support/grpc_async_dispatcher_test_services.grpc.pb.h"
 #include "remoting/signaling/grpc_support/grpc_async_test_server.h"
 #include "remoting/signaling/grpc_support/grpc_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/grpc/src/include/grpcpp/grpcpp.h"
 
@@ -24,6 +26,10 @@
 
 namespace {
 
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Property;
+
 using EchoStreamResponder = test::GrpcServerStreamResponder<EchoResponse>;
 
 base::RepeatingCallback<void(const EchoResponse&)>
@@ -31,6 +37,10 @@
   return base::BindRepeating([](const EchoResponse&) { NOTREACHED(); });
 }
 
+base::RepeatingCallback<void(const grpc::Status&)> NotReachedStatusCallback() {
+  return base::BindRepeating([](const grpc::Status&) { NOTREACHED(); });
+}
+
 EchoResponse ResponseForText(const std::string& text) {
   EchoResponse response;
   response.set_text(text);
@@ -55,6 +65,8 @@
 
  protected:
   void HandleOneEchoRequest();
+  std::unique_ptr<test::GrpcServerResponder<EchoResponse>>
+  GetResponderAndFillEchoRequest(EchoRequest* request);
   std::unique_ptr<EchoStreamResponder> HandleEchoStream(
       const base::Location& from_here,
       const std::string& expected_request_text);
@@ -108,11 +120,16 @@
 
 void GrpcAsyncDispatcherTest::HandleOneEchoRequest() {
   EchoRequest request;
-  auto responder = server_->HandleRequest(
-      &GrpcAsyncDispatcherTestService::AsyncService::RequestEcho, &request);
+  auto responder = GetResponderAndFillEchoRequest(&request);
   EchoResponse response;
   response.set_text(request.text());
-  responder->Respond(response, grpc::Status::OK);
+  ASSERT_TRUE(responder->Respond(response, grpc::Status::OK));
+}
+
+std::unique_ptr<test::GrpcServerResponder<EchoResponse>>
+GrpcAsyncDispatcherTest::GetResponderAndFillEchoRequest(EchoRequest* request) {
+  return server_->HandleRequest(
+      &GrpcAsyncDispatcherTestService::AsyncService::RequestEcho, request);
 }
 
 std::unique_ptr<EchoStreamResponder> GrpcAsyncDispatcherTest::HandleEchoStream(
@@ -194,26 +211,42 @@
   run_loop.Run();
 }
 
+TEST_F(GrpcAsyncDispatcherTest,
+       ControlGroup_RpcChannelStillOpenAfterRunLoopQuit) {
+  base::RunLoop run_loop;
+  AsyncSendText("Hello", base::BindLambdaForTesting(
+                             [&](const grpc::Status&, const EchoResponse&) {
+                               NOTREACHED();
+                             }));
+  EchoRequest request;
+  auto responder = GetResponderAndFillEchoRequest(&request);
+  run_loop.RunUntilIdle();
+  ASSERT_TRUE(responder->Respond(EchoResponse(), grpc::Status::OK));
+}
+
 TEST_F(GrpcAsyncDispatcherTest, RpcCanceledOnDestruction) {
   base::RunLoop run_loop;
-  AsyncSendText("Hello",
-                base::BindLambdaForTesting([&](const grpc::Status& status,
-                                               const EchoResponse& response) {
-                  EXPECT_EQ(grpc::StatusCode::CANCELLED, status.error_code());
-                  run_loop.QuitWhenIdle();
-                }));
+  AsyncSendText("Hello", base::BindLambdaForTesting(
+                             [&](const grpc::Status&, const EchoResponse&) {
+                               NOTREACHED();
+                             }));
+  EchoRequest request;
+  auto responder = GetResponderAndFillEchoRequest(&request);
   dispatcher_.reset();
-  run_loop.Run();
+  run_loop.RunUntilIdle();
+  ASSERT_FALSE(responder->Respond(EchoResponse(), grpc::Status::OK));
 }
 
 TEST_F(GrpcAsyncDispatcherTest, ServerStreamNotAcceptedByServer) {
   base::RunLoop run_loop;
-  auto scoped_stream =
-      StartEchoStream("Hello", NotReachedStreamingCallback(),
-                      test::CheckStatusThenQuitRunLoopCallback(
-                          FROM_HERE, grpc::StatusCode::CANCELLED, &run_loop));
+  auto scoped_stream = StartEchoStream(
+      "Hello", NotReachedStreamingCallback(),
+      base::BindLambdaForTesting([&](const grpc::Status&) { NOTREACHED(); }));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindLambdaForTesting([&]() { dispatcher_.reset(); }));
+      FROM_HERE, base::BindLambdaForTesting([&]() {
+        dispatcher_.reset();
+        run_loop.QuitWhenIdle();
+      }));
   run_loop.Run();
 }
 
@@ -250,7 +283,6 @@
   auto scoped_stream = StartEchoStream(
       "Hello", base::BindLambdaForTesting([&](const EchoResponse& response) {
         ASSERT_EQ("Echo 1", response.text());
-        responder->OnClientReceivedMessage();
         responder.reset();
       }),
       test::CheckStatusThenQuitRunLoopCallback(FROM_HERE, grpc::StatusCode::OK,
@@ -263,73 +295,87 @@
 TEST_F(GrpcAsyncDispatcherTest, ServerStreamsTwoMessagesThenClosedByServer) {
   base::RunLoop run_loop;
   std::unique_ptr<EchoStreamResponder> responder;
-  int received_messages_count = 0;
-  auto scoped_stream = StartEchoStream(
-      "Hello", base::BindLambdaForTesting([&](const EchoResponse& response) {
-        if (received_messages_count == 0) {
-          ASSERT_EQ("Echo 1", response.text());
-          responder->OnClientReceivedMessage();
+
+  base::MockCallback<base::RepeatingCallback<void(const EchoResponse&)>>
+      mock_on_incoming_msg;
+
+  {
+    InSequence sequence;
+    EXPECT_CALL(mock_on_incoming_msg,
+                Run(Property(&EchoResponse::text, "Echo 1")))
+        .WillOnce(Invoke([&](const EchoResponse&) {
           responder->SendMessage(ResponseForText("Echo 2"));
-          received_messages_count++;
-          return;
-        }
-        if (received_messages_count == 1) {
-          ASSERT_EQ("Echo 2", response.text());
-          responder->OnClientReceivedMessage();
-          responder.reset();
-          received_messages_count++;
-          return;
-        }
-        NOTREACHED();
-      }),
-      test::CheckStatusThenQuitRunLoopCallback(FROM_HERE, grpc::StatusCode::OK,
-                                               &run_loop));
+        }));
+    EXPECT_CALL(mock_on_incoming_msg,
+                Run(Property(&EchoResponse::text, "Echo 2")))
+        .WillOnce(Invoke([&](const EchoResponse&) { responder.reset(); }));
+  }
+
+  auto scoped_stream =
+      StartEchoStream("Hello", mock_on_incoming_msg.Get(),
+                      test::CheckStatusThenQuitRunLoopCallback(
+                          FROM_HERE, grpc::StatusCode::OK, &run_loop));
   responder = HandleEchoStream(FROM_HERE, "Hello");
-  responder->SendMessage(ResponseForText("Echo 1"));
+  ASSERT_TRUE(responder->SendMessage(ResponseForText("Echo 1")));
   run_loop.Run();
-  ASSERT_EQ(2, received_messages_count);
+}
+
+TEST_F(GrpcAsyncDispatcherTest,
+       ControlGroup_ServerStreamStillOpenAfterRunLoopQuit) {
+  base::RunLoop run_loop;
+  auto scoped_stream = StartEchoStream("Hello", NotReachedStreamingCallback(),
+                                       NotReachedStatusCallback());
+  auto responder = HandleEchoStream(FROM_HERE, "Hello");
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindLambdaForTesting([&]() { run_loop.QuitWhenIdle(); }));
+  run_loop.Run();
+  ASSERT_TRUE(responder->SendMessage(ResponseForText("Echo 1")));
 }
 
 TEST_F(GrpcAsyncDispatcherTest,
        ServerStreamOpenThenClosedByClientAtDestruction) {
   base::RunLoop run_loop;
-  auto scoped_stream =
-      StartEchoStream("Hello", NotReachedStreamingCallback(),
-                      test::CheckStatusThenQuitRunLoopCallback(
-                          FROM_HERE, grpc::StatusCode::CANCELLED, &run_loop));
+  auto scoped_stream = StartEchoStream("Hello", NotReachedStreamingCallback(),
+                                       NotReachedStatusCallback());
   auto responder = HandleEchoStream(FROM_HERE, "Hello");
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindLambdaForTesting([&]() { dispatcher_.reset(); }));
+      FROM_HERE, base::BindLambdaForTesting([&]() {
+        dispatcher_.reset();
+        run_loop.QuitWhenIdle();
+      }));
   run_loop.Run();
+  ASSERT_FALSE(responder->SendMessage(ResponseForText("Echo 1")));
 }
 
 TEST_F(GrpcAsyncDispatcherTest, ServerStreamClosedByStreamHolder) {
   base::RunLoop run_loop;
-  std::unique_ptr<EchoStreamResponder> responder;
-  std::unique_ptr<ScopedGrpcServerStream> scoped_stream =
-      StartEchoStream("Hello", NotReachedStreamingCallback(),
-                      test::CheckStatusThenQuitRunLoopCallback(
-                          FROM_HERE, grpc::StatusCode::CANCELLED, &run_loop));
-  responder = HandleEchoStream(FROM_HERE, "Hello");
-  scoped_stream.reset();
+  auto scoped_stream = StartEchoStream("Hello", NotReachedStreamingCallback(),
+                                       NotReachedStatusCallback());
+  auto responder = HandleEchoStream(FROM_HERE, "Hello");
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindLambdaForTesting([&]() {
+        scoped_stream.reset();
+        run_loop.QuitWhenIdle();
+      }));
   run_loop.Run();
+  ASSERT_FALSE(responder->SendMessage(ResponseForText("Echo 1")));
 }
 
 TEST_F(GrpcAsyncDispatcherTest,
        ServerStreamsOneMessageThenClosedByStreamHolder) {
   base::RunLoop run_loop;
-  std::unique_ptr<EchoStreamResponder> responder;
   std::unique_ptr<ScopedGrpcServerStream> scoped_stream = StartEchoStream(
       "Hello", base::BindLambdaForTesting([&](const EchoResponse& response) {
         ASSERT_EQ("Echo 1", response.text());
-        responder->OnClientReceivedMessage();
         scoped_stream.reset();
+        run_loop.QuitWhenIdle();
       }),
-      test::CheckStatusThenQuitRunLoopCallback(
-          FROM_HERE, grpc::StatusCode::CANCELLED, &run_loop));
-  responder = HandleEchoStream(FROM_HERE, "Hello");
-  responder->SendMessage(ResponseForText("Echo 1"));
+      NotReachedStatusCallback());
+  auto responder = HandleEchoStream(FROM_HERE, "Hello");
+  ASSERT_TRUE(responder->SendMessage(ResponseForText("Echo 1")));
   run_loop.Run();
+  ASSERT_FALSE(responder->SendMessage(ResponseForText("Echo 2")));
 }
 
 }  // namespace remoting
diff --git a/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.cc b/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.cc
index 2209117..e598f2ca 100644
--- a/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.cc
+++ b/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.cc
@@ -16,12 +16,14 @@
     : GrpcAsyncCallData(std::move(context)), weak_factory_(this) {
   DCHECK(on_channel_closed);
   on_channel_closed_ = std::move(on_channel_closed);
+  weak_ptr_ = weak_factory_.GetWeakPtr();
 }
 
-GrpcAsyncServerStreamingCallDataBase::~GrpcAsyncServerStreamingCallDataBase() =
-    default;
+GrpcAsyncServerStreamingCallDataBase::~GrpcAsyncServerStreamingCallDataBase() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
 
-bool GrpcAsyncServerStreamingCallDataBase::OnDequeuedOnDispatcherThread(
+bool GrpcAsyncServerStreamingCallDataBase::OnDequeuedOnDispatcherThreadInternal(
     bool operation_succeeded) {
   base::AutoLock autolock(state_lock_);
   if (state_ == State::CLOSED) {
@@ -55,17 +57,24 @@
 
 std::unique_ptr<ScopedGrpcServerStream>
 GrpcAsyncServerStreamingCallDataBase::CreateStreamHolder() {
-  return std::make_unique<ScopedGrpcServerStream>(weak_factory_.GetWeakPtr());
+  return std::make_unique<ScopedGrpcServerStream>(weak_ptr_);
 }
 
 void GrpcAsyncServerStreamingCallDataBase::OnRequestCanceled() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   base::AutoLock autolock(state_lock_);
   if (state_ == State::CLOSED) {
     return;
   }
   state_ = State::CLOSED;
   status_ = grpc::Status::CANCELLED;
-  ResolveChannelClosed();
+  weak_factory_.InvalidateWeakPtrs();
+}
+
+void GrpcAsyncServerStreamingCallDataBase::RunClosure(
+    base::OnceClosure closure) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  std::move(closure).Run();
 }
 
 void GrpcAsyncServerStreamingCallDataBase::ResolveChannelClosed() {
diff --git a/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.h b/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.h
index 04c349a33..d8eeeaa 100644
--- a/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.h
+++ b/remoting/signaling/grpc_support/grpc_async_server_streaming_call_data.h
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
 #include "remoting/signaling/grpc_support/grpc_async_call_data.h"
@@ -34,10 +35,14 @@
   ~GrpcAsyncServerStreamingCallDataBase() override;
 
   // GrpcAsyncCallData implementations.
-  bool OnDequeuedOnDispatcherThread(bool operation_succeeded) override;
+  bool OnDequeuedOnDispatcherThreadInternal(bool operation_succeeded) override;
 
   std::unique_ptr<ScopedGrpcServerStream> CreateStreamHolder();
 
+  // Helper method for subclass to run callback only when the weak pointer is
+  // valid.
+  void RunClosure(base::OnceClosure closure);
+
  protected:
   enum class State {
     STARTING,
@@ -58,12 +63,15 @@
 
   base::Lock state_lock_;
   State state_ GUARDED_BY(state_lock_) = State::STARTING;
+  base::WeakPtr<GrpcAsyncServerStreamingCallDataBase> weak_ptr_;
 
  private:
   void ResolveChannelClosed();
 
   base::OnceCallback<void(const grpc::Status&)> on_channel_closed_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   base::WeakPtrFactory<GrpcAsyncServerStreamingCallDataBase> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(GrpcAsyncServerStreamingCallDataBase);
 };
@@ -74,40 +82,48 @@
  public:
   using OnIncomingMessageCallback =
       base::RepeatingCallback<void(const ResponseType&)>;
+  using StartAndCreateReaderCallback =
+      base::OnceCallback<std::unique_ptr<grpc::ClientAsyncReader<ResponseType>>(
+          void* event_tag)>;
 
   GrpcAsyncServerStreamingCallData(
       std::unique_ptr<grpc::ClientContext> context,
+      StartAndCreateReaderCallback create_reader_callback,
       const OnIncomingMessageCallback& on_incoming_msg,
       base::OnceCallback<void(const grpc::Status&)> on_channel_closed)
       : GrpcAsyncServerStreamingCallDataBase(std::move(context),
                                              std::move(on_channel_closed)) {
+    create_reader_callback_ = std::move(create_reader_callback);
     on_incoming_msg_ = on_incoming_msg;
   }
   ~GrpcAsyncServerStreamingCallData() override = default;
 
-  void Initialize(
-      std::unique_ptr<grpc::ClientAsyncReader<ResponseType>> reader) {
-    reader_ = std::move(reader);
+  // GrpcAsyncCallData implementations
+  void StartInternal() override {
+    reader_ = std::move(create_reader_callback_).Run(GetEventTag());
   }
 
  protected:
   // GrpcAsyncServerStreamingCallDataBase implementations.
   void ResolveIncomingMessage() override {
-    caller_task_runner_->PostTask(FROM_HERE,
-                                  base::BindOnce(on_incoming_msg_, response_));
+    caller_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&GrpcAsyncServerStreamingCallDataBase::RunClosure,
+                       weak_ptr_, base::BindOnce(on_incoming_msg_, response_)));
   }
 
   void WaitForIncomingMessage() override {
     DCHECK(reader_);
-    reader_->Read(&response_, /* event_tag */ this);
+    reader_->Read(&response_, GetEventTag());
   }
 
   void FinishStream() override {
     DCHECK(reader_);
-    reader_->Finish(&status_, /* event_tag */ this);
+    reader_->Finish(&status_, GetEventTag());
   }
 
  private:
+  StartAndCreateReaderCallback create_reader_callback_;
   ResponseType response_;
   std::unique_ptr<grpc::ClientAsyncReader<ResponseType>> reader_;
   OnIncomingMessageCallback on_incoming_msg_;
diff --git a/remoting/signaling/grpc_support/grpc_async_unary_call_data.h b/remoting/signaling/grpc_support/grpc_async_unary_call_data.h
index 22c5d17..b4d88f94 100644
--- a/remoting/signaling/grpc_support/grpc_async_unary_call_data.h
+++ b/remoting/signaling/grpc_support/grpc_async_unary_call_data.h
@@ -11,6 +11,8 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "remoting/signaling/grpc_support/grpc_async_call_data.h"
 #include "third_party/grpc/src/include/grpcpp/support/async_unary_call.h"
 
@@ -30,26 +32,50 @@
       std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>
           response_reader,
       RpcCallback callback)
-      : GrpcAsyncCallData(std::move(context)) {
+      : GrpcAsyncCallData(std::move(context)), weak_factory_(this) {
     response_reader_ = std::move(response_reader);
     callback_ = std::move(callback);
-    response_reader_->Finish(&response_, &status_, /* event_tag */ this);
+    weak_ptr_ = weak_factory_.GetWeakPtr();
   }
-  ~GrpcAsyncUnaryCallData() override = default;
+  ~GrpcAsyncUnaryCallData() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
 
-  bool OnDequeuedOnDispatcherThread(bool operation_succeeded) override {
+  // GrpcAsyncCallData implementations
+
+  void StartInternal() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    response_reader_->Finish(&response_, &status_, GetEventTag());
+  }
+
+  bool OnDequeuedOnDispatcherThreadInternal(bool operation_succeeded) override {
     DCHECK(operation_succeeded);
     caller_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback_), status_, response_));
+        FROM_HERE,
+        base::BindOnce(&GrpcAsyncUnaryCallData::RunCallback, weak_ptr_));
     return false;
   }
 
  private:
+  void OnRequestCanceled() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    weak_factory_.InvalidateWeakPtrs();
+  }
+
+  void RunCallback() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    std::move(callback_).Run(status_, response_);
+  }
+
   std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>
       response_reader_;
   ResponseType response_;
   RpcCallback callback_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtr<GrpcAsyncUnaryCallData<ResponseType>> weak_ptr_;
+  base::WeakPtrFactory<GrpcAsyncUnaryCallData<ResponseType>> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(GrpcAsyncUnaryCallData);
 };
 
diff --git a/remoting/signaling/grpc_support/grpc_test_util.h b/remoting/signaling/grpc_support/grpc_test_util.h
index 5fc8fbe0..38080833 100644
--- a/remoting/signaling/grpc_support/grpc_test_util.h
+++ b/remoting/signaling/grpc_support/grpc_test_util.h
@@ -46,9 +46,9 @@
 
   ~GrpcServerResponder() = default;
 
-  void Respond(const ResponseType& response, const grpc::Status& status) {
+  bool Respond(const ResponseType& response, const grpc::Status& status) {
     writer_.Finish(response, status, this);
-    WaitForCompletionAndAssertOk(FROM_HERE, completion_queue_, this);
+    return WaitForCompletion(FROM_HERE, completion_queue_, this);
   }
 
   grpc::ServerContext* context() { return &context_; }
@@ -74,13 +74,9 @@
 
   ~GrpcServerStreamResponder() { Close(grpc::Status::OK); }
 
-  // Must be followed by a call to OnClientReceivedMessage()
-  void SendMessage(const ResponseType& response) {
+  bool SendMessage(const ResponseType& response) {
     writer_.Write(response, /* event_tag */ this);
-  }
-
-  void OnClientReceivedMessage() {
-    WaitForCompletionAndAssertOk(FROM_HERE, completion_queue_, this);
+    return WaitForCompletion(FROM_HERE, completion_queue_, this);
   }
 
   void Close(const grpc::Status& status) {
diff --git a/services/network/OWNERS b/services/network/OWNERS
index 16c2dba..07a1ddb 100644
--- a/services/network/OWNERS
+++ b/services/network/OWNERS
@@ -28,3 +28,5 @@
 per-file network_sandbox_win.*=file://sandbox/win/OWNERS
 
 per-file resource_scheduler*=tbansal@chromium.org
+
+# COMPONENT: Internals>Services>Network
diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc
index 8c792e5..122a856f 100644
--- a/services/network/cookie_manager.cc
+++ b/services/network/cookie_manager.cc
@@ -93,11 +93,11 @@
 
 void CookieManager::SetCanonicalCookie(const net::CanonicalCookie& cookie,
                                        const std::string& source_scheme,
-                                       bool modify_http_only,
+                                       const net::CookieOptions& cookie_options,
                                        SetCanonicalCookieCallback callback) {
   cookie_store_->SetCanonicalCookieAsync(
       std::make_unique<net::CanonicalCookie>(cookie), source_scheme,
-      modify_http_only, AdaptCookieInclusionStatusToBool(std::move(callback)));
+      cookie_options, AdaptCookieInclusionStatusToBool(std::move(callback)));
 }
 
 void CookieManager::DeleteCanonicalCookie(
diff --git a/services/network/cookie_manager.h b/services/network/cookie_manager.h
index 6cef8ce..ed3d08f 100644
--- a/services/network/cookie_manager.h
+++ b/services/network/cookie_manager.h
@@ -60,7 +60,7 @@
                      GetCookieListCallback callback) override;
   void SetCanonicalCookie(const net::CanonicalCookie& cookie,
                           const std::string& source_scheme,
-                          bool modify_http_only,
+                          const net::CookieOptions& cookie_options,
                           SetCanonicalCookieCallback callback) override;
   void DeleteCanonicalCookie(const net::CanonicalCookie& cookie,
                              DeleteCanonicalCookieCallback callback) override;
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index 44b7b5d..ade4ee7 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -95,8 +95,11 @@
                           bool modify_http_only) {
     base::RunLoop run_loop;
     bool result = false;
+    net::CookieOptions options;
+    if (modify_http_only)
+      options.set_include_httponly();
     cookie_service_->SetCanonicalCookie(
-        cookie, std::move(source_scheme), modify_http_only,
+        cookie, std::move(source_scheme), options,
         base::BindOnce(&SynchronousCookieManager::SetCookieCallback, &run_loop,
                        &result));
     run_loop.Run();
@@ -184,9 +187,12 @@
                           bool can_modify_httponly) {
     net::ResultSavingCookieCallback<net::CanonicalCookie::CookieInclusionStatus>
         callback;
+    net::CookieOptions options;
+    if (can_modify_httponly)
+      options.set_include_httponly();
     cookie_monster_->SetCanonicalCookieAsync(
         std::make_unique<net::CanonicalCookie>(cookie),
-        std::move(source_scheme), can_modify_httponly,
+        std::move(source_scheme), options,
         base::BindOnce(&net::ResultSavingCookieCallback<
                            net::CanonicalCookie::CookieInclusionStatus>::Run,
                        base::Unretained(&callback)));
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 172e1a7..3965fb0 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -2014,12 +2014,15 @@
   // Set a cookie through the cookie interface.
   base::RunLoop run_loop1;
   bool result = false;
+  net::CookieOptions options;
+  options.set_include_httponly();
   cookie_manager_ptr->SetCanonicalCookie(
       net::CanonicalCookie("TestCookie", "1", "www.test.com", "/", base::Time(),
                            base::Time(), base::Time(), false, false,
                            net::CookieSameSite::NO_RESTRICTION,
                            net::COOKIE_PRIORITY_LOW),
-      "https", true, base::BindOnce(&SetCookieCallback, &run_loop1, &result));
+      "https", options,
+      base::BindOnce(&SetCookieCallback, &run_loop1, &result));
   run_loop1.Run();
   EXPECT_TRUE(result);
 
diff --git a/services/network/public/cpp/cookie_manager.typemap b/services/network/public/cpp/cookie_manager.typemap
index 7f56a8a5..ecb99ed 100644
--- a/services/network/public/cpp/cookie_manager.typemap
+++ b/services/network/public/cpp/cookie_manager.typemap
@@ -16,7 +16,7 @@
 type_mappings = [
   "network.mojom.CookiePriority=net::CookiePriority",
   "network.mojom.CookieSameSite=net::CookieSameSite",
-  "network.mojom.CookieSameSiteFilter=net::CookieOptions::SameSiteCookieContext",
+  "network.mojom.CookieSameSiteContext=net::CookieOptions::SameSiteCookieContext",
   "network.mojom.CookieOptions=net::CookieOptions",
   "network.mojom.CanonicalCookie=net::CanonicalCookie",
   "network.mojom.CookieInclusionStatus=net::CanonicalCookie::CookieInclusionStatus",
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.cc b/services/network/public/cpp/cookie_manager_mojom_traits.cc
index 5efac7b..caff3cb 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.cc
@@ -185,34 +185,34 @@
   return false;
 }
 
-network::mojom::CookieSameSiteFilter
-EnumTraits<network::mojom::CookieSameSiteFilter,
+network::mojom::CookieSameSiteContext
+EnumTraits<network::mojom::CookieSameSiteContext,
            net::CookieOptions::SameSiteCookieContext>::
     ToMojom(net::CookieOptions::SameSiteCookieContext input) {
   switch (input) {
     case net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT:
-      return network::mojom::CookieSameSiteFilter::INCLUDE_STRICT_AND_LAX;
+      return network::mojom::CookieSameSiteContext::SAME_SITE_STRICT;
     case net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX:
-      return network::mojom::CookieSameSiteFilter::INCLUDE_LAX;
+      return network::mojom::CookieSameSiteContext::SAME_SITE_LAX;
     case net::CookieOptions::SameSiteCookieContext::CROSS_SITE:
-      return network::mojom::CookieSameSiteFilter::DO_NOT_INCLUDE;
+      return network::mojom::CookieSameSiteContext::CROSS_SITE;
   }
   NOTREACHED();
-  return static_cast<network::mojom::CookieSameSiteFilter>(input);
+  return network::mojom::CookieSameSiteContext::CROSS_SITE;
 }
 
-bool EnumTraits<network::mojom::CookieSameSiteFilter,
+bool EnumTraits<network::mojom::CookieSameSiteContext,
                 net::CookieOptions::SameSiteCookieContext>::
-    FromMojom(network::mojom::CookieSameSiteFilter input,
+    FromMojom(network::mojom::CookieSameSiteContext input,
               net::CookieOptions::SameSiteCookieContext* output) {
   switch (input) {
-    case network::mojom::CookieSameSiteFilter::INCLUDE_STRICT_AND_LAX:
+    case network::mojom::CookieSameSiteContext::SAME_SITE_STRICT:
       *output = net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT;
       return true;
-    case network::mojom::CookieSameSiteFilter::INCLUDE_LAX:
+    case network::mojom::CookieSameSiteContext::SAME_SITE_LAX:
       *output = net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX;
       return true;
-    case network::mojom::CookieSameSiteFilter::DO_NOT_INCLUDE:
+    case network::mojom::CookieSameSiteContext::CROSS_SITE:
       *output = net::CookieOptions::SameSiteCookieContext::CROSS_SITE;
       return true;
   }
@@ -228,7 +228,7 @@
     cookie_options->set_include_httponly();
 
   net::CookieOptions::SameSiteCookieContext same_site_cookie_context;
-  if (!mojo_options.ReadCookieSameSiteFilter(&same_site_cookie_context))
+  if (!mojo_options.ReadSameSiteCookieContext(&same_site_cookie_context))
     return false;
   cookie_options->set_same_site_cookie_context(same_site_cookie_context);
 
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
index 52c80598..064ed8a 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits.h
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.h
@@ -38,12 +38,12 @@
 };
 
 template <>
-struct EnumTraits<network::mojom::CookieSameSiteFilter,
+struct EnumTraits<network::mojom::CookieSameSiteContext,
                   net::CookieOptions::SameSiteCookieContext> {
-  static network::mojom::CookieSameSiteFilter ToMojom(
+  static network::mojom::CookieSameSiteContext ToMojom(
       net::CookieOptions::SameSiteCookieContext input);
 
-  static bool FromMojom(network::mojom::CookieSameSiteFilter input,
+  static bool FromMojom(network::mojom::CookieSameSiteContext input,
                         net::CookieOptions::SameSiteCookieContext* output);
 };
 
@@ -52,7 +52,7 @@
   static bool exclude_httponly(const net::CookieOptions& o) {
     return o.exclude_httponly();
   }
-  static net::CookieOptions::SameSiteCookieContext cookie_same_site_filter(
+  static net::CookieOptions::SameSiteCookieContext same_site_cookie_context(
       const net::CookieOptions& o) {
     return o.same_site_cookie_context();
   }
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc b/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
index 68a67ce..d77c689 100644
--- a/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/cookie_manager_mojom_traits_unittest.cc
@@ -16,6 +16,12 @@
 namespace network {
 namespace {
 
+template <typename MojoType, typename NativeType>
+bool SerializeAndDeserializeEnum(NativeType in, NativeType* out) {
+  MojoType intermediate = mojo::EnumTraits<MojoType, NativeType>::ToMojom(in);
+  return mojo::EnumTraits<MojoType, NativeType>::FromMojom(intermediate, out);
+}
+
 TEST(CookieManagerTraitsTest, Roundtrips_CookieInclusionStatus) {
   std::vector<net::CanonicalCookie::CookieInclusionStatus> statuses = {
       net::CanonicalCookie::CookieInclusionStatus::INCLUDE,
@@ -109,8 +115,57 @@
   EXPECT_EQ(original.status, copied.status);
 }
 
-// TODO: Add tests for CookiePriority, CookieSameSite, CookieSameSiteFilter, &
-// CookieOptions
+TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSite) {
+  for (net::CookieSameSite cookie_state :
+       {net::CookieSameSite::NO_RESTRICTION, net::CookieSameSite::LAX_MODE,
+        net::CookieSameSite::STRICT_MODE}) {
+    net::CookieSameSite roundtrip;
+    ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieSameSite>(cookie_state,
+                                                                   &roundtrip));
+    EXPECT_EQ(cookie_state, roundtrip);
+  }
+
+  for (net::CookieOptions::SameSiteCookieContext context_state :
+       {net::CookieOptions::SameSiteCookieContext::CROSS_SITE,
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT}) {
+    net::CookieOptions::SameSiteCookieContext roundtrip;
+    ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieSameSiteContext>(
+        context_state, &roundtrip));
+    EXPECT_EQ(context_state, roundtrip);
+  }
+}
+
+TEST(CookieManagerTraitsTest, Roundtrips_CookieOptions) {
+  {
+    net::CookieOptions least_trusted, copy;
+    EXPECT_FALSE(least_trusted.return_excluded_cookies());
+    least_trusted.set_return_excluded_cookies();  // differ from default.
+
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
+        &least_trusted, &copy));
+    EXPECT_TRUE(copy.exclude_httponly());
+    EXPECT_EQ(net::CookieOptions::SameSiteCookieContext::CROSS_SITE,
+              copy.same_site_cookie_context());
+    EXPECT_TRUE(copy.return_excluded_cookies());
+  }
+
+  {
+    net::CookieOptions very_trusted, copy;
+    very_trusted.set_include_httponly();
+    very_trusted.set_same_site_cookie_context(
+        net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT);
+
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
+        &very_trusted, &copy));
+    EXPECT_FALSE(copy.exclude_httponly());
+    EXPECT_EQ(net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
+              copy.same_site_cookie_context());
+    EXPECT_FALSE(copy.return_excluded_cookies());
+  }
+}
+
+// TODO: Add tests for CookiePriority, more extensive CookieOptions ones
 
 }  // namespace
 }  // namespace network
diff --git a/services/network/public/cpp/server/http_server.cc b/services/network/public/cpp/server/http_server.cc
index d82d8e8..078b090 100644
--- a/services/network/public/cpp/server/http_server.cc
+++ b/services/network/public/cpp/server/http_server.cc
@@ -78,7 +78,7 @@
 
 void HttpServer::SendOverWebSocket(
     int connection_id,
-    const std::string& data,
+    base::StringPiece data,
     net::NetworkTrafficAnnotationTag traffic_annotation) {
   HttpConnection* connection = FindConnection(connection_id);
   if (connection == NULL)
@@ -274,7 +274,7 @@
         Close(connection->id());
         return;
       }
-      delegate_->OnWebSocketMessage(connection->id(), message);
+      delegate_->OnWebSocketMessage(connection->id(), std::move(message));
       if (HasClosedConnection(connection)) {
         return;
       }
diff --git a/services/network/public/cpp/server/http_server.h b/services/network/public/cpp/server/http_server.h
index c02a3473..a5162d29 100644
--- a/services/network/public/cpp/server/http_server.h
+++ b/services/network/public/cpp/server/http_server.h
@@ -15,6 +15,7 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -47,8 +48,7 @@
                                const HttpServerRequestInfo& info) = 0;
     virtual void OnWebSocketRequest(int connection_id,
                                     const HttpServerRequestInfo& info) = 0;
-    virtual void OnWebSocketMessage(int connection_id,
-                                    const std::string& data) = 0;
+    virtual void OnWebSocketMessage(int connection_id, std::string data) = 0;
     virtual void OnClose(int connection_id) = 0;
   };
 
@@ -64,7 +64,7 @@
                        const HttpServerRequestInfo& request,
                        net::NetworkTrafficAnnotationTag traffic_annotation);
   void SendOverWebSocket(int connection_id,
-                         const std::string& data,
+                         base::StringPiece data,
                          net::NetworkTrafficAnnotationTag traffic_annotation);
   // Sends the provided data directly to the given connection. No validation is
   // performed that data constitutes a valid HTTP response. A valid HTTP
diff --git a/services/network/public/cpp/server/http_server_unittest.cc b/services/network/public/cpp/server/http_server_unittest.cc
index 05facf1..6ad13dac 100644
--- a/services/network/public/cpp/server/http_server_unittest.cc
+++ b/services/network/public/cpp/server/http_server_unittest.cc
@@ -211,7 +211,7 @@
     NOTREACHED();
   }
 
-  void OnWebSocketMessage(int connection_id, const std::string& data) override {
+  void OnWebSocketMessage(int connection_id, std::string data) override {
     NOTREACHED();
   }
 
@@ -296,8 +296,7 @@
     HttpServerTest::OnHttpRequest(connection_id, info);
   }
 
-  void OnWebSocketMessage(int connection_id, const std::string& data) override {
-  }
+  void OnWebSocketMessage(int connection_id, std::string data) override {}
 };
 
 TEST_F(HttpServerTest, SetNonexistingConnectionBuffer) {
diff --git a/services/network/public/cpp/server/web_socket.cc b/services/network/public/cpp/server/web_socket.cc
index 230a877b..b43622bf 100644
--- a/services/network/public/cpp/server/web_socket.cc
+++ b/services/network/public/cpp/server/web_socket.cc
@@ -129,7 +129,7 @@
 }
 
 void WebSocket::Send(
-    const std::string& message,
+    base::StringPiece message,
     const net::NetworkTrafficAnnotationTag traffic_annotation) {
   if (closed_)
     return;
diff --git a/services/network/public/cpp/server/web_socket.h b/services/network/public/cpp/server/web_socket.h
index f8caccd..b98dc29 100644
--- a/services/network/public/cpp/server/web_socket.h
+++ b/services/network/public/cpp/server/web_socket.h
@@ -30,7 +30,7 @@
   void Accept(const HttpServerRequestInfo& request,
               const net::NetworkTrafficAnnotationTag traffic_annotation);
   ParseResult Read(std::string* message);
-  void Send(const std::string& message,
+  void Send(base::StringPiece message,
             const net::NetworkTrafficAnnotationTag traffic_annotation);
   ~WebSocket();
 
diff --git a/services/network/public/cpp/server/web_socket_encoder.cc b/services/network/public/cpp/server/web_socket_encoder.cc
index 94fd1f4..d0f23c9 100644
--- a/services/network/public/cpp/server/web_socket_encoder.cc
+++ b/services/network/public/cpp/server/web_socket_encoder.cc
@@ -142,13 +142,13 @@
   return closed ? WebSocket::FRAME_CLOSE : WebSocket::FRAME_OK;
 }
 
-void EncodeFrameHybi17(const std::string& message,
+void EncodeFrameHybi17(base::StringPiece message,
                        int masking_key,
                        bool compressed,
                        std::string* output) {
   std::vector<char> frame;
   OpCode op_code = kOpCodeText;
-  size_t data_length = message.length();
+  size_t data_length = message.size();
 
   int reserved1 = compressed ? kReserved1Bit : 0;
   frame.push_back(kFinalBit | op_code | reserved1);
@@ -304,7 +304,7 @@
   return result;
 }
 
-void WebSocketEncoder::EncodeFrame(const std::string& frame,
+void WebSocketEncoder::EncodeFrame(base::StringPiece frame,
                                    int masking_key,
                                    std::string* output) {
   std::string compressed;
@@ -336,8 +336,7 @@
   return true;
 }
 
-bool WebSocketEncoder::Deflate(const std::string& message,
-                               std::string* output) {
+bool WebSocketEncoder::Deflate(base::StringPiece message, std::string* output) {
   if (!deflater_)
     return false;
   if (!deflater_->AddBytes(message.data(), message.length())) {
diff --git a/services/network/public/cpp/server/web_socket_encoder.h b/services/network/public/cpp/server/web_socket_encoder.h
index 7063b8f..c5226582 100644
--- a/services/network/public/cpp/server/web_socket_encoder.h
+++ b/services/network/public/cpp/server/web_socket_encoder.h
@@ -43,7 +43,7 @@
   WebSocket::ParseResult DecodeFrame(const base::StringPiece& frame,
                                      int* bytes_consumed,
                                      std::string* output);
-  void EncodeFrame(const std::string& frame,
+  void EncodeFrame(base::StringPiece frame,
                    int masking_key,
                    std::string* output);
 
@@ -60,7 +60,7 @@
                    std::unique_ptr<net::WebSocketInflater> inflater);
 
   bool Inflate(std::string* message);
-  bool Deflate(const std::string& message, std::string* output);
+  bool Deflate(base::StringPiece message, std::string* output);
 
   Type type_;
   std::unique_ptr<net::WebSocketDeflater> deflater_;
diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom
index 0d127eae..2ada2103 100644
--- a/services/network/public/mojom/cookie_manager.mojom
+++ b/services/network/public/mojom/cookie_manager.mojom
@@ -41,16 +41,16 @@
   STRICT_MODE
 };
 
-enum CookieSameSiteFilter {
-  INCLUDE_STRICT_AND_LAX,
-  INCLUDE_LAX,
-  DO_NOT_INCLUDE
+enum CookieSameSiteContext {
+  CROSS_SITE,
+  SAME_SITE_LAX,
+  SAME_SITE_STRICT
 };
 
 // Keep defaults here in sync with net/cookies/cookie_options.cc.
 struct CookieOptions {
   bool exclude_httponly = true;
-  CookieSameSiteFilter cookie_same_site_filter = DO_NOT_INCLUDE;
+  CookieSameSiteContext same_site_cookie_context = CROSS_SITE;
   bool update_access_time = true;
   // TODO(rdsmith): Remove this element from the mojo structure?  It's only
   // used in the underlying net:: structure in CanonicalCookie::Create().
@@ -213,11 +213,10 @@
   // Set a cookie.  |source_scheme| is used to check whether existing secure
   // cookies can be overwritten (secure cookies may be created from a
   // non-secure source), and whether the scheme is permitted to use cookies in
-  // the first place.  |modify_http_only| indicates whether http_only
-  // cookies may be overwritten.
-  SetCanonicalCookie(
-      CanonicalCookie cookie, string source_scheme, bool modify_http_only) =>
-      (bool success);
+  // the first place.  |cookie_options| indicates whether http_only
+  // or SameSite cookies may be overwritten.
+  SetCanonicalCookie(CanonicalCookie cookie, string source_scheme,
+                     CookieOptions cookie_options) => (bool success);
 
   // Delete a cookie. Returns true if a cookie was deleted.
   DeleteCanonicalCookie(CanonicalCookie cookie) => (bool success);
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index f4d77b65..c21f073f 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -190,9 +190,13 @@
       cookie.SameSite(), cookie.Priority());
 
   // TODO(pwnall): source_scheme might depend on the renderer.
-  bool modify_http_only = false;
+  net::CookieOptions options;
+  // TODO(https://crbug.com/925311): Wire initiator here.
+  options.set_same_site_cookie_context(net::cookie_util::ComputeSameSiteContext(
+      url, site_for_cookies, base::nullopt /*initiator*/));
+  options.set_exclude_httponly();  // Default, but make it explicit here.
   cookie_store_->SetCanonicalCookieAsync(
-      std::move(sanitized_cookie), origin_.scheme(), modify_http_only,
+      std::move(sanitized_cookie), origin_.scheme(), options,
       AdaptCookieInclusionStatusToBool(std::move(callback)));
 }
 
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index 7b6ea91..421cb85 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -111,9 +111,12 @@
                           bool can_modify_httponly) {
     net::ResultSavingCookieCallback<net::CanonicalCookie::CookieInclusionStatus>
         callback;
+    net::CookieOptions options;
+    if (can_modify_httponly)
+      options.set_include_httponly();
     cookie_monster_.SetCanonicalCookieAsync(
         std::make_unique<net::CanonicalCookie>(cookie),
-        std::move(source_scheme), can_modify_httponly,
+        std::move(source_scheme), options,
         base::BindOnce(&net::ResultSavingCookieCallback<
                            net::CanonicalCookie::CookieInclusionStatus>::Run,
                        base::Unretained(&callback)));
diff --git a/services/network/test/test_cookie_manager.cc b/services/network/test/test_cookie_manager.cc
index 1654025..2c05cde 100644
--- a/services/network/test/test_cookie_manager.cc
+++ b/services/network/test/test_cookie_manager.cc
@@ -15,7 +15,7 @@
 void TestCookieManager::SetCanonicalCookie(
     const net::CanonicalCookie& cookie,
     const std::string& source_scheme,
-    bool modify_http_only,
+    const net::CookieOptions& cookie_options,
     SetCanonicalCookieCallback callback) {
   std::move(callback).Run(false);
 }
diff --git a/services/network/test/test_cookie_manager.h b/services/network/test/test_cookie_manager.h
index cce528a..3bd9a21 100644
--- a/services/network/test/test_cookie_manager.h
+++ b/services/network/test/test_cookie_manager.h
@@ -23,7 +23,7 @@
 
   void SetCanonicalCookie(const net::CanonicalCookie& cookie,
                           const std::string& source_scheme,
-                          bool modify_http_only,
+                          const net::CookieOptions& cookie_options,
                           SetCanonicalCookieCallback callback) override;
   void GetAllCookies(GetAllCookiesCallback callback) override {}
   void GetCookieList(const GURL& url,
diff --git a/services/service_manager/zygote/zygote_linux.cc b/services/service_manager/zygote/zygote_linux.cc
index 3252818..e49fb86 100644
--- a/services/service_manager/zygote/zygote_linux.cc
+++ b/services/service_manager/zygote/zygote_linux.cc
@@ -64,13 +64,6 @@
   return -1;
 }
 
-void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
-  int raw_pipe[2];
-  PCHECK(0 == pipe(raw_pipe));
-  read_pipe->reset(raw_pipe[0]);
-  write_pipe->reset(raw_pipe[1]);
-}
-
 void KillAndReap(pid_t pid, ZygoteForkDelegate* helper) {
   if (helper) {
     // Helper children may be forked in another PID namespace, so |pid| might
@@ -427,7 +420,7 @@
     // Helpers should never return in the child process.
     CHECK_NE(pid, 0);
   } else {
-    CreatePipe(&read_pipe, &write_pipe);
+    PCHECK(base::CreatePipe(&read_pipe, &write_pipe));
     if (sandbox_flags_ & service_manager::SandboxLinux::kPIDNS &&
         sandbox_flags_ & service_manager::SandboxLinux::kUserNS) {
       pid = sandbox::NamespaceSandbox::ForkInNewPidNamespace(
diff --git a/services/tracing/perfetto/consumer_host.h b/services/tracing/perfetto/consumer_host.h
index 74e3782..ce601542 100644
--- a/services/tracing/perfetto/consumer_host.h
+++ b/services/tracing/perfetto/consumer_host.h
@@ -62,6 +62,7 @@
   void OnDetach(bool success) override {}
   void OnAttach(bool success, const perfetto::TraceConfig&) override {}
   void OnTraceStats(bool success, const perfetto::TraceStats&) override {}
+  void OnObservableEvents(const perfetto::ObservableEvents&) override {}
 
  private:
   void WriteToStream(const void* start, size_t size);
diff --git a/services/tracing/perfetto/perfetto_tracing_coordinator.cc b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
index 20156e4..65bbd12 100644
--- a/services/tracing/perfetto/perfetto_tracing_coordinator.cc
+++ b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
@@ -234,6 +234,8 @@
         .Run(true, percent_full, 0 /*approx_event_count*/);
   }
 
+  void OnObservableEvents(const perfetto::ObservableEvents&) override {}
+
  private:
   mojo::ScopedDataPipeProducerHandle stream_;
   std::unique_ptr<JSONTraceExporter> json_trace_exporter_;
diff --git a/services/tracing/perfetto/test_utils.h b/services/tracing/perfetto/test_utils.h
index d518a62..35089eb 100644
--- a/services/tracing/perfetto/test_utils.h
+++ b/services/tracing/perfetto/test_utils.h
@@ -107,6 +107,7 @@
   void OnDetach(bool success) override;
   void OnAttach(bool success, const perfetto::TraceConfig&) override;
   void OnTraceStats(bool success, const perfetto::TraceStats&) override;
+  void OnObservableEvents(const perfetto::ObservableEvents&) override {}
 
  private:
   std::unique_ptr<perfetto::TracingService::ConsumerEndpoint>
diff --git a/services/ws/public/mojom/window_manager.mojom b/services/ws/public/mojom/window_manager.mojom
index 99cef47..d25ee01 100644
--- a/services/ws/public/mojom/window_manager.mojom
+++ b/services/ws/public/mojom/window_manager.mojom
@@ -87,10 +87,8 @@
   // The modal parent of a child modal window. Type: window Id.
   const string kChildModalParent_Property = "prop:child-modal-parent";
 
-  // If true, the window is considered as has-content and occludes windows
-  // behind it.
-  const string kClientWindowHasContent_Property =
-      "prop:client-window-has-content";
+  // If true, the window's layer has drawn content.
+  const string kWindowLayerDrawn_Property = "prop:window-layer-drawn";
 
   // Whether the window is trying to draw attention to itself (e.g. pulsing its
   // shelf icon). Type: bool.
diff --git a/services/ws/public/mojom/window_tree.mojom b/services/ws/public/mojom/window_tree.mojom
index e4f8026..21ab60d 100644
--- a/services/ws/public/mojom/window_tree.mojom
+++ b/services/ws/public/mojom/window_tree.mojom
@@ -177,6 +177,9 @@
   // Sets the opacity of the specified window to |opacity|.
   SetWindowOpacity(uint32 change_id, uint64 window_id, float opacity);
 
+  // Sets the transparent status of the specified window to |transparent|.
+  SetWindowTransparent(uint32 change_id, uint64 window_id, bool transparent);
+
   // Attaches a CompositorFrameSink to a particular window.
   AttachCompositorFrameSink(
       uint64 window_id,
diff --git a/services/ws/window_service.cc b/services/ws/window_service.cc
index 66b71c8..41c045c 100644
--- a/services/ws/window_service.cc
+++ b/services/ws/window_service.cc
@@ -39,7 +39,7 @@
 // Returns true if |window| is a proxy window and marked as has-content.
 bool IsOpaqueProxyWindow(const aura::Window* window) {
   return WindowService::IsProxyWindow(window) &&
-         window->GetProperty(aura::client::kClientWindowHasContent);
+         window->GetProperty(aura::client::kWindowLayerDrawn);
 }
 
 // Factory to create ws::WindowOcclusionChangeBuilder that dispatches occlusion
diff --git a/services/ws/window_tree.cc b/services/ws/window_tree.cc
index 12eb3eb..63582717 100644
--- a/services/ws/window_tree.cc
+++ b/services/ws/window_tree.cc
@@ -1185,6 +1185,21 @@
   return false;
 }
 
+bool WindowTree::SetWindowTransparentImpl(const ClientWindowId& window_id,
+                                          bool transparent) {
+  aura::Window* window = GetWindowByClientId(window_id);
+  DVLOG(3) << "SetWindowTransparent client=" << client_id_
+           << " client window_id=" << window_id.ToString();
+  if (IsClientCreatedWindow(window) || IsClientRootWindow(window)) {
+    if (window->transparent() == transparent)
+      return true;
+    window->SetTransparent(transparent);
+    return true;
+  }
+  DVLOG(1) << "SetWindowTransparent failed (invalid window or access denied)";
+  return false;
+}
+
 bool WindowTree::SetWindowBoundsImpl(
     const ClientWindowId& window_id,
     const gfx::Rect& bounds,
@@ -1813,6 +1828,14 @@
       SetWindowOpacityImpl(MakeClientWindowId(transport_window_id), opacity));
 }
 
+void WindowTree::SetWindowTransparent(uint32_t change_id,
+                                      Id transport_window_id,
+                                      bool transparent) {
+  window_tree_client_->OnChangeCompleted(
+      change_id, SetWindowTransparentImpl(
+                     MakeClientWindowId(transport_window_id), transparent));
+}
+
 void WindowTree::AttachCompositorFrameSink(
     Id transport_window_id,
     viz::mojom::CompositorFrameSinkRequest compositor_frame_sink,
diff --git a/services/ws/window_tree.h b/services/ws/window_tree.h
index 412818f..befbec1 100644
--- a/services/ws/window_tree.h
+++ b/services/ws/window_tree.h
@@ -351,6 +351,8 @@
                  mojom::WindowTreeClient* window_tree_client,
                  uint32_t flags);
   bool SetWindowOpacityImpl(const ClientWindowId& window_id, float opacity);
+  bool SetWindowTransparentImpl(const ClientWindowId& window_id,
+                                bool transparent);
   bool SetWindowBoundsImpl(const ClientWindowId& window_id,
                            const gfx::Rect& bounds,
                            const base::Optional<viz::LocalSurfaceIdAllocation>&
@@ -435,6 +437,9 @@
   void SetWindowOpacity(uint32_t change_id,
                         Id transport_window_id,
                         float opacity) override;
+  void SetWindowTransparent(uint32_t change_id,
+                            Id transport_window_id,
+                            bool transparent) override;
   void AttachCompositorFrameSink(
       Id transport_window_id,
       viz::mojom::CompositorFrameSinkRequest compositor_frame_sink,
diff --git a/services/ws/window_tree_unittest.cc b/services/ws/window_tree_unittest.cc
index a6f09aec..4fe1d98 100644
--- a/services/ws/window_tree_unittest.cc
+++ b/services/ws/window_tree_unittest.cc
@@ -2319,7 +2319,7 @@
   aura::Window* blocking_window =
       setup.window_tree_test_helper()->NewTopLevelWindow();
   ASSERT_TRUE(blocking_window);
-  blocking_window->SetProperty(aura::client::kClientWindowHasContent, true);
+  blocking_window->SetProperty(aura::client::kWindowLayerDrawn, true);
   blocking_window->SetBounds(gfx::Rect(0, 0, 15, 15));
   blocking_window->Show();
 
@@ -2351,7 +2351,7 @@
   aura::Window* blocking_window =
       setup.window_tree_test_helper()->NewTopLevelWindow();
   ASSERT_TRUE(blocking_window);
-  blocking_window->SetProperty(aura::client::kClientWindowHasContent, true);
+  blocking_window->SetProperty(aura::client::kWindowLayerDrawn, true);
   blocking_window->SetBounds(gfx::Rect(0, 0, 20, 15));
   blocking_window->Show();
 
@@ -2390,7 +2390,7 @@
   aura::Window* blocking_window =
       setup.window_tree_test_helper()->NewTopLevelWindow();
   ASSERT_TRUE(blocking_window);
-  blocking_window->SetProperty(aura::client::kClientWindowHasContent, true);
+  blocking_window->SetProperty(aura::client::kWindowLayerDrawn, true);
   blocking_window->SetBounds(gfx::Rect(0, 0, 20, 15));
   blocking_window->Show();
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index a07558d..fd8f457e 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1062,12 +1062,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -1779,12 +1773,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 7038e82..101ea97 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -420,12 +420,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -1439,18 +1433,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -2565,18 +2547,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -8557,12 +8527,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -9300,15 +9264,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -9937,12 +9892,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -10492,12 +10441,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -11050,12 +10993,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -11612,12 +11549,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -12176,12 +12107,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -12706,12 +12631,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -13490,15 +13409,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -14042,12 +13952,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -14735,12 +14639,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -15359,12 +15257,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -15983,12 +15875,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -17023,18 +16909,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -18217,18 +18091,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -19411,18 +19273,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -20189,12 +20039,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -20813,12 +20657,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -21437,12 +21275,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -22061,12 +21893,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -22649,12 +22475,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -23569,17 +23389,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index a70abc8e..49ba297 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -709,12 +709,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -2562,12 +2556,6 @@
         "swarming": {
           "can_use_on_swarming_builders": false
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": false
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -4819,12 +4807,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "services_unittests"
       },
       {
@@ -5106,12 +5088,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "services_unittests"
       },
       {
@@ -5489,15 +5465,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--enable-blink-features=HeapUnifiedGarbageCollection"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "services_unittests"
       },
       {
@@ -5804,12 +5771,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "services_unittests"
       },
       {
@@ -6542,13 +6503,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -7149,12 +7103,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -7926,13 +7874,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -11240,12 +11181,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -12375,19 +12310,6 @@
           ],
           "expiration": 21600
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14"
-            }
-          ],
-          "expiration": 21600
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index cb3842a..69f369d 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -258,12 +258,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "sandbox_linux_unittests"
       },
       {
@@ -591,12 +585,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "sandbox_linux_unittests"
       },
       {
@@ -1516,12 +1504,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -2261,12 +2243,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -2974,12 +2950,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -3981,17 +3951,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 95012a7..2b1dce4 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -746,18 +746,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.10"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -1878,18 +1866,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.11"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -3010,18 +2986,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -4179,18 +4143,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -5342,18 +5294,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 3c043e9f..b7f3c1d 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -3251,15 +3251,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -3942,12 +3933,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -4835,15 +4820,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -6287,21 +6263,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -7630,21 +7591,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -8547,15 +8493,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -9299,15 +9236,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -10379,17 +10307,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index f0d3374..661bee55 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -85,13 +85,6 @@
         "test": "blink_platform_unittests"
       },
       {
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -476,12 +469,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -1666,18 +1653,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -2853,18 +2828,6 @@
             }
           ]
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -3445,13 +3408,6 @@
         "test": "blink_platform_unittests"
       },
       {
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "blink_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -3836,12 +3792,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
@@ -4605,12 +4555,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 4569b9f..349581d 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -676,7 +676,7 @@
       "command_buffer_perftests",
       "--non-telemetry=true",
       "--adb-path",
-      "src/third_party/android_tools/sdk/platform-tools/adb",
+      "src/third_party/android_sdk/public/platform-tools/adb",
     ],
     "label": "//gpu:command_buffer_perftests",
     "script": "//testing/scripts/run_performance_tests.py",
@@ -1093,7 +1093,7 @@
       "gpu_perftests",
       "--non-telemetry=true",
       "--adb-path",
-      "src/third_party/android_tools/sdk/platform-tools/adb",
+      "src/third_party/android_sdk/public/platform-tools/adb",
     ],
     "label": "//gpu:gpu_perftests",
     "script": "//testing/scripts/run_performance_tests.py",
@@ -2514,7 +2514,7 @@
       "--non-telemetry=true",
       "--test-launcher-print-test-stdio=always",
       "--adb-path",
-      "src/third_party/android_tools/sdk/platform-tools/adb",
+      "src/third_party/android_sdk/public/platform-tools/adb",
     ],
     "label": "//components/tracing:tracing_perftests",
     "script": "//testing/scripts/run_performance_tests.py",
@@ -2696,7 +2696,7 @@
       "vr_common_perftests",
       "--non-telemetry=true",
       "--adb-path",
-      "src/third_party/android_tools/sdk/platform-tools/adb",
+      "src/third_party/android_sdk/public/platform-tools/adb",
     ],
     "label": "//chrome/browser/vr:vr_common_perftests",
     "script": "//testing/scripts/run_performance_tests.py",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 4747add3..82a1f4b 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1055,22 +1055,6 @@
       'ToTWinThinLTO64',
     ],
   },
-  'perfetto_unittests': {
-    'remove_from': [
-      'android-kitkat-arm-rel',
-      'android-marshmallow-arm64-rel',
-      'Android CFI',
-      'KitKat Phone Tester (dbg)',
-      'KitKat Tablet Tester',
-      'Lollipop Phone Tester',
-      'Lollipop Tablet Tester',
-      'Marshmallow 64 bit Tester',
-      'Marshmallow Tablet Tester',
-      'Nougat Phone Tester',
-      'ToTAndroid',
-      'ToTAndroidCFI'
-    ]
-  },
   'performance_test_suite': {
     'modifications': {
       'Mac10.13 Tests (dbg)': {
@@ -1806,6 +1790,11 @@
         },
       },
     },
+    'remove_from': [
+      # Flakily fails on Win7. https://crbug.com/943372.
+      'Win7 Tests (1)',
+      'Win 7 Tests x64 (1)',
+    ],
   },
   'webui_polymer1_browser_tests': {
     'remove_from': [
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index c1f2818..bbe9599 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -2346,7 +2346,6 @@
         ],
         'test': 'content_browsertests',
       },
-      'perfetto_unittests': {},
       'services_unittests': {},
       'shell_dialogs_unittests': {},
       'skia_unittests': {},
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
index d631eab..a1e52d61e 100644
--- a/testing/buildbot/tryserver.chromium.linux.json
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -465,13 +465,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "perfetto_unittests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ppapi_unittests"
       },
       {
diff --git a/testing/libfuzzer/fuzzers/mach/BUILD.gn b/testing/libfuzzer/fuzzers/mach/BUILD.gn
new file mode 100644
index 0000000..238cf115
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/mach/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  sources = [
+    "mach_message.proto",
+  ]
+}
+
+source_set("converter") {
+  sources = [
+    "mach_message_converter.cc",
+    "mach_message_converter.h",
+  ]
+  public_deps = [
+    ":proto",
+  ]
+  deps = [
+    "//base",
+  ]
+}
diff --git a/testing/libfuzzer/fuzzers/mach/mach_message.proto b/testing/libfuzzer/fuzzers/mach/mach_message.proto
new file mode 100644
index 0000000..4a3c1b6e
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/mach/mach_message.proto
@@ -0,0 +1,61 @@
+// 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.
+
+syntax = "proto2";
+
+package mach_fuzzer;
+
+// Specifies a type of Mach port right to create.
+enum MachPortType {
+  // Create a receive right and move it to the peer, while holding
+  // a send right.
+  RECEIVE = 0;
+  // Create a receive right and make a send right during mach_msg.
+  SEND = 1;
+  // Create a receive right and vend a send-once right during mach_msg.
+  SEND_ONCE = 2;
+  // Create a dead name right and give a send right to it to the peer.
+  DEAD_NAME = 3;
+  // Create a receive right with no senders and move the receive right
+  // to the peer.
+  RECEIVE_NO_SENDERS = 4;
+}
+
+// Data to send in an out-of-line memory region in Mach message descriptor.
+message OutOfLineMemory {
+  required bytes data = 1;
+}
+
+// Models a mach_msg_descriptor_t.
+message Descriptor {
+  oneof descriptor_oneof {
+    MachPortType port = 1;
+    OutOfLineMemory ool = 2;
+  }
+}
+
+// Models a Mach message structure including the header, optional body,
+// and inline data.
+message MachMessage {
+  // Creates an optional port to put in msgh_local_port. If this is a receive
+  // right, it will be dropped.
+  optional MachPortType local_port = 1;
+
+  // The msgh_id field.
+  optional uint32 id = 2;
+
+  // Optional Descriptors to carry in the message.
+  repeated Descriptor descriptors = 3;
+
+  // If no Descriptors are present, whether or not to include a mach_msg_body_t
+  // in the message.
+  required bool include_body_if_not_complex = 4;
+
+  // Raw data bytes to send inline with the message.
+  optional bytes data = 5;
+
+  // Extensions can be used by clients to express structured message data,
+  // which can be converted into bytes and placed in |data|.
+  extensions 100 to 199;
+}
diff --git a/testing/libfuzzer/fuzzers/mach/mach_message_converter.cc b/testing/libfuzzer/fuzzers/mach/mach_message_converter.cc
new file mode 100644
index 0000000..313f82d
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/mach/mach_message_converter.cc
@@ -0,0 +1,171 @@
+// 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 "testing/libfuzzer/fuzzers/mach/mach_message_converter.h"
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <utility>
+
+#include "base/containers/buffer_iterator.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_msg_destroy.h"
+
+namespace mach_fuzzer {
+
+namespace {
+
+SendablePort ConvertPort(const MachPortType& port_proto) {
+  constexpr struct {
+    bool insert_send_right;
+    bool deallocate_receive_right;
+    mach_msg_type_name_t disposition;
+  } kPortRecipes[] = {
+      [RECEIVE] = {true, false, MACH_MSG_TYPE_MOVE_RECEIVE},
+      [SEND] = {false, false, MACH_MSG_TYPE_MAKE_SEND},
+      [SEND_ONCE] = {false, false, MACH_MSG_TYPE_MAKE_SEND_ONCE},
+      [DEAD_NAME] = {true, true, MACH_MSG_TYPE_COPY_SEND},
+      [RECEIVE_NO_SENDERS] = {false, false, MACH_MSG_TYPE_MOVE_RECEIVE},
+  };
+  const auto* recipe = &kPortRecipes[port_proto];
+
+  SendablePort port;
+  kern_return_t kr = mach_port_allocate(
+      mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
+      base::mac::ScopedMachReceiveRight::Receiver(port.receive_right).get());
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_allocate";
+
+  port.name = port.receive_right.get();
+  port.disposition = recipe->disposition;
+  port.proto_type = port_proto;
+
+  if (recipe->insert_send_right) {
+    kr = mach_port_insert_right(mach_task_self(), port.name, port.name,
+                                MACH_MSG_TYPE_MAKE_SEND);
+    MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_right";
+    port.send_right.reset(port.name);
+  }
+
+  if (recipe->deallocate_receive_right) {
+    port.receive_right.reset();
+  }
+
+  return port;
+}
+
+bool ConvertDescriptor(base::BufferIterator<uint8_t>* iterator,
+                       const Descriptor& descriptor_proto,
+                       SendablePort* opt_port) {
+  switch (descriptor_proto.descriptor_oneof_case()) {
+    case Descriptor::kPort: {
+      auto* descriptor = iterator->MutableObject<mach_msg_port_descriptor_t>();
+      SendablePort port = ConvertPort(descriptor_proto.port());
+      descriptor->name = port.name;
+      descriptor->pad1 = 0;
+      descriptor->pad2 = 0;
+      descriptor->disposition = port.disposition;
+      descriptor->type = MACH_MSG_PORT_DESCRIPTOR;
+      *opt_port = std::move(port);
+      return true;
+    }
+    case Descriptor::kOol: {
+      auto* descriptor = iterator->MutableObject<mach_msg_ool_descriptor_t>();
+      descriptor->address =
+          const_cast<char*>(descriptor_proto.ool().data().data());
+      descriptor->size = descriptor_proto.ool().data().size();
+      descriptor->copy = MACH_MSG_VIRTUAL_COPY;
+      descriptor->pad1 = 0;
+      descriptor->type = MACH_MSG_OOL_DESCRIPTOR;
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+
+}  // namespace
+
+SendableMessage ConvertProtoToMachMessage(const MachMessage& proto) {
+  SendableMessage message;
+
+  const size_t descriptor_count = proto.descriptors().size();
+  const size_t data_size = proto.data().size();
+  const bool include_body =
+      proto.include_body_if_not_complex() || descriptor_count > 0;
+
+  // This is the maximum size of the message. Depending on the descriptor type,
+  // the actual msgh_size may be less.
+  const size_t message_size =
+      sizeof(mach_msg_header_t) + (include_body ? sizeof(mach_msg_body_t) : 0) +
+      (sizeof(mach_msg_descriptor_t) * descriptor_count) + data_size;
+  message.buffer = std::make_unique<uint8_t[]>(round_msg(message_size));
+
+  base::BufferIterator<uint8_t> iterator(message.buffer.get(), message_size);
+
+  auto* header = iterator.MutableObject<mach_msg_header_t>();
+  message.header = header;
+  header->msgh_id = proto.id();
+
+  if (proto.has_local_port()) {
+    SendablePort port = ConvertPort(proto.local_port());
+    auto disposition = port.disposition;
+    // It's not legal to have a receive reply report.
+    if (disposition != MACH_MSG_TYPE_MOVE_RECEIVE) {
+      header->msgh_bits |= MACH_MSGH_BITS(0, disposition);
+      header->msgh_local_port = port.name;
+      message.ports.push_back(std::move(port));
+    }
+  }
+
+  if (include_body) {
+    auto* body = iterator.MutableObject<mach_msg_body_t>();
+    body->msgh_descriptor_count = descriptor_count;
+  }
+
+  if (descriptor_count > 0) {
+    header->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
+    for (const auto& descriptor : proto.descriptors()) {
+      SendablePort opt_port;
+      if (!ConvertDescriptor(&iterator, descriptor, &opt_port)) {
+        return SendableMessage();
+      }
+      if (opt_port.name != MACH_PORT_NULL) {
+        message.ports.push_back(std::move(opt_port));
+      }
+    }
+  }
+
+  auto data = iterator.MutableSpan<uint8_t>(data_size);
+  memcpy(data.data(), proto.data().data(), proto.data().size());
+
+  header->msgh_size = round_msg(iterator.position());
+
+  return message;
+}
+
+SendResult SendMessage(mach_port_t remote_port, const MachMessage& proto) {
+  SendResult result;
+  result.message = ConvertProtoToMachMessage(proto);
+  if (!result.message.header) {
+    result.kr = KERN_FAILURE;
+    return result;
+  }
+
+  result.message.header->msgh_remote_port = remote_port;
+  result.message.header->msgh_bits |=
+      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+
+  base::ScopedMachMsgDestroy scoped_message(result.message.header);
+
+  result.kr = mach_msg_send(result.message.header);
+
+  if (result.kr == KERN_SUCCESS) {
+    scoped_message.Disarm();
+  }
+
+  return result;
+}
+
+}  // namespace mach_fuzzer
diff --git a/testing/libfuzzer/fuzzers/mach/mach_message_converter.h b/testing/libfuzzer/fuzzers/mach/mach_message_converter.h
new file mode 100644
index 0000000..9c9f61e
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/mach/mach_message_converter.h
@@ -0,0 +1,62 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TESTING_LIBFUZZER_FUZZERS_MACH_MACH_MESSAGE_CONVERTER_H_
+#define TESTING_LIBFUZZER_FUZZERS_MACH_MACH_MESSAGE_CONVERTER_H_
+
+#include <mach/mach.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/mac/scoped_mach_port.h"
+#include "testing/libfuzzer/fuzzers/mach/mach_message.pb.h"
+
+namespace mach_fuzzer {
+
+// Container for a Mach port right that will be sent in a message.
+struct SendablePort {
+  mach_port_t name = MACH_PORT_NULL;
+  mach_msg_type_name_t disposition = 0;
+  MachPortType proto_type = static_cast<MachPortType>(-1);
+
+  base::mac::ScopedMachSendRight send_right;
+  base::mac::ScopedMachReceiveRight receive_right;
+};
+
+// Holds the buffer allocation and port references for a message to be sent.
+struct SendableMessage {
+  // The message buffer.
+  std::unique_ptr<uint8_t[]> buffer;
+
+  // The |ports| are also encoded into the body of the message, but they are
+  // accessible here to allow for further manipulation.
+  std::vector<SendablePort> ports;
+
+  // Pointer to the header of the message stored in |buffer|.
+  mach_msg_header_t* header = nullptr;
+};
+
+// Converts the given protobuf message into a live Mach message, including port
+// rights.
+SendableMessage ConvertProtoToMachMessage(const MachMessage& proto);
+
+// Takes the protobuf |proto|, converts it to a Mach message using
+// ConvertProtoToMachMessage(), and then sends it via |local_port|. The port
+// named by |local_port| must have a send right, which will be copied.
+struct SendResult {
+  // The return value from mach_msg_send().
+  kern_return_t kr;
+
+  // The message that was sent, including its descriptors. This allows callers
+  // to control the lifetimes of any Mach rights after the message has been
+  // sent.
+  SendableMessage message;
+};
+SendResult SendMessage(mach_port_t local_port, const MachMessage& proto);
+
+}  // namespace mach_fuzzer
+
+#endif  // TESTING_LIBFUZZER_FUZZERS_MACH_MACH_MESSAGE_CONVERTER_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index fae85f31..71a1eb8 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4512,7 +4512,7 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled_20190212",
+                    "name": "Enabled_20190318",
                     "enable_features": [
                         "ServiceWorkerAggressiveCodeCache"
                     ]
diff --git a/third_party/android_sdk/README.chromium b/third_party/android_sdk/README.chromium
index ea867e9..eac869d 100644
--- a/third_party/android_sdk/README.chromium
+++ b/third_party/android_sdk/README.chromium
@@ -3,12 +3,13 @@
 Version: 28
   Android SDK Build-tools 27.0.3
   Android SDK Emulator 28.0.23
-  Android SDK Platform-tools 28.0.1
+  Android SDK Platform-tools 28.0.2
   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
@@ -22,8 +23,10 @@
 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
 - public/tools-lint/
   - Go to go/studio-master-grid
   - Find the first green build under sdk_tools_linux
diff --git a/third_party/android_sdk/cipd_build-tools.yaml b/third_party/android_sdk/cipd_build-tools.yaml
index 527d50c..a7d47f5 100644
--- a/third_party/android_sdk/cipd_build-tools.yaml
+++ b/third_party/android_sdk/cipd_build-tools.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: build-tools
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_emulator.yaml b/third_party/android_sdk/cipd_emulator.yaml
index 90d249b..8a501a84 100644
--- a/third_party/android_sdk/cipd_emulator.yaml
+++ b/third_party/android_sdk/cipd_emulator.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: emulator
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_extras.yaml b/third_party/android_sdk/cipd_extras.yaml
index eeb87e4..ccc1be1d 100644
--- a/third_party/android_sdk/cipd_extras.yaml
+++ b/third_party/android_sdk/cipd_extras.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: extras
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_patcher.yaml b/third_party/android_sdk/cipd_patcher.yaml
new file mode 100644
index 0000000..c1d8367
--- /dev/null
+++ b/third_party/android_sdk/cipd_patcher.yaml
@@ -0,0 +1,15 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd_tools.yaml
+package: chromium/third_party/android_sdk/public/patcher
+description: patcher Android SDK Tools library
+root: public/
+data:
+  - dir: patcher
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_platform-tools.yaml b/third_party/android_sdk/cipd_platform-tools.yaml
index 855fa6f..06b5dee 100644
--- a/third_party/android_sdk/cipd_platform-tools.yaml
+++ b/third_party/android_sdk/cipd_platform-tools.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: platform-tools
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_platforms.yaml b/third_party/android_sdk/cipd_platforms.yaml
index 1ebf00da..154f06b 100644
--- a/third_party/android_sdk/cipd_platforms.yaml
+++ b/third_party/android_sdk/cipd_platforms.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: platforms
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_sources.yaml b/third_party/android_sdk/cipd_sources.yaml
index a4ff323..8963f26 100644
--- a/third_party/android_sdk/cipd_sources.yaml
+++ b/third_party/android_sdk/cipd_sources.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: sources
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_tools-lint.yaml b/third_party/android_sdk/cipd_tools-lint.yaml
index 0e3604d..77745ca 100644
--- a/third_party/android_sdk/cipd_tools-lint.yaml
+++ b/third_party/android_sdk/cipd_tools-lint.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: tools-lint
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/android_sdk/cipd_tools.yaml b/third_party/android_sdk/cipd_tools.yaml
index 0b1beff8..896b31b 100644
--- a/third_party/android_sdk/cipd_tools.yaml
+++ b/third_party/android_sdk/cipd_tools.yaml
@@ -9,3 +9,7 @@
 root: public/
 data:
   - dir: tools
+# Some tools inspect their argv0 and don't handle CIPD's symlink structure
+# correctly. Install in copy mode so that they can find the other directories
+# relative to themselves.
+install_mode: copy
diff --git a/third_party/blink/common/messaging/transferable_message_struct_traits.cc b/third_party/blink/common/messaging/transferable_message_struct_traits.cc
index 5100fa0..e629d98 100644
--- a/third_party/blink/common/messaging/transferable_message_struct_traits.cc
+++ b/third_party/blink/common/messaging/transferable_message_struct_traits.cc
@@ -27,6 +27,7 @@
   out->stream_channels =
       blink::MessagePortChannel::CreateFromHandles(std::move(stream_channels));
   out->has_user_gesture = data.has_user_gesture();
+  out->transfer_user_activation = data.transfer_user_activation();
   return true;
 }
 
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 59462e4..d038e60 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -654,7 +654,6 @@
       [ "//third_party/blink/renderer/platform:blink_platform_public_deps" ]
   sources = [
     "platform/modules/bluetooth/web_bluetooth.mojom",
-    "platform/modules/credentialmanager/credential_manager.mojom",
     "platform/modules/idle/idle_manager.mojom",
     "platform/modules/notifications/notification_service.mojom",
     "platform/modules/webdatabase/web_database.mojom",
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index fc49392..906c4ae 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -32,6 +32,7 @@
     "contacts/contacts_manager.mojom",
     "cookie_store/cookie_store.mojom",
     "crash/crash_memory_metrics_reporter.mojom",
+    "credentialmanager/credential_manager.mojom",
     "csp/content_security_policy.mojom",
     "devtools/console_message.mojom",
     "devtools/devtools_agent.mojom",
diff --git a/third_party/blink/public/platform/modules/credentialmanager/OWNERS b/third_party/blink/public/mojom/credentialmanager/OWNERS
similarity index 72%
rename from third_party/blink/public/platform/modules/credentialmanager/OWNERS
rename to third_party/blink/public/mojom/credentialmanager/OWNERS
index cae285e..9e26b66 100644
--- a/third_party/blink/public/platform/modules/credentialmanager/OWNERS
+++ b/third_party/blink/public/mojom/credentialmanager/OWNERS
@@ -1,7 +1,3 @@
-engedy@chromium.org
-mkwst@chromium.org
-vasilii@chromium.org
-
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 
diff --git a/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom b/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom
similarity index 100%
rename from third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
rename to third_party/blink/public/mojom/credentialmanager/credential_manager.mojom
diff --git a/third_party/blink/public/mojom/messaging/transferable_message.mojom b/third_party/blink/public/mojom/messaging/transferable_message.mojom
index e382d4e..5cd699fb 100644
--- a/third_party/blink/public/mojom/messaging/transferable_message.mojom
+++ b/third_party/blink/public/mojom/messaging/transferable_message.mojom
@@ -35,4 +35,7 @@
   bool has_user_gesture;
   // The user activation state, null if the frame isn't providing it.
   UserActivationSnapshot? user_activation;
+  // Whether the state of user activation should be transferred to the
+  // destination frame.
+  bool transfer_user_activation;
 };
diff --git a/third_party/blink/public/platform/web_database_observer.h b/third_party/blink/public/platform/web_database_observer.h
index 7bd01496..607d637 100644
--- a/third_party/blink/public/platform/web_database_observer.h
+++ b/third_party/blink/public/platform/web_database_observer.h
@@ -43,7 +43,7 @@
   virtual void DatabaseOpened(const WebSecurityOrigin&,
                               const WebString& database_name,
                               const WebString& database_display_name,
-                              unsigned long estimated_size) = 0;
+                              uint32_t estimated_size) = 0;
   virtual void DatabaseModified(const WebSecurityOrigin&,
                                 const WebString& database_name) = 0;
   virtual void DatabaseClosed(const WebSecurityOrigin&,
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
index e55cf8a..e8e5749 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/iterators/text_searcher_icu.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
 #include "third_party/blink/renderer/core/invisible_dom/invisible_dom.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -143,9 +144,10 @@
          IsHTMLIFrameElement(element) || IsHTMLImageElement(element) ||
          IsHTMLLegendElement(element) || IsHTMLMeterElement(element) ||
          IsHTMLObjectElement(element) || IsHTMLProgressElement(element) ||
-         IsHTMLSelectElement(element) || IsHTMLStyleElement(element) ||
-         IsHTMLScriptElement(element) || IsHTMLVideoElement(element) ||
-         IsHTMLAudioElement(element) ||
+         (IsHTMLSelectElement(element) &&
+          !ToHTMLSelectElement(element).IsMultiple()) ||
+         IsHTMLStyleElement(element) || IsHTMLScriptElement(element) ||
+         IsHTMLVideoElement(element) || IsHTMLAudioElement(element) ||
          (element.GetDisplayLockContext() &&
           !element.GetDisplayLockContext()->IsActivatable());
 }
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc b/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
index 7f41a0e..7f68e944d 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/editing/finder/find_buffer.h"
 
+#include "build/build_config.h"
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
@@ -624,4 +625,14 @@
   ASSERT_EQ(0u, results->CountForTesting());
 }
 
+TEST_F(FindBufferTest, SelectMultipleTest) {
+  SetBodyContent("<select multiple><option>find me</option></select>");
+  FindBuffer buffer(WholeDocumentRange());
+#if defined(OS_ANDROID)
+  ASSERT_EQ(0u, buffer.FindMatches("find", 0)->CountForTesting());
+#else
+  ASSERT_EQ(1u, buffer.FindMatches("find", 0)->CountForTesting());
+#endif  // defined(OS_ANDROID)
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc
index c2f4b79..fccc801c 100644
--- a/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -497,8 +497,8 @@
       std::move(channels), std::move(message), source_origin, String(), source,
       user_activation, options->transferUserActivation());
 
-  // TODO(mustaq): Also transfer in the frame trees in all other processes
-  // (browser and other renderers).  See crbug.com/928838.
+  // Transfer user activation state in the source's renderer when
+  // |transferUserActivation| is true.
   LocalFrame* source_frame = source->GetFrame();
   if (RuntimeEnabledFeatures::UserActivationPostMessageTransferEnabled() &&
       options->transferUserActivation() &&
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 2e04330..7d3ec935 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2273,6 +2273,17 @@
     UserGestureIndicator::SetWasForwardedCrossProcess();
   }
 
+  // Transfer user activation state in the target's renderer when
+  // |transferUserActivation| is true.
+  MessageEvent* msg_event = static_cast<MessageEvent*>((Event*)event);
+  Frame* source_frame = nullptr;
+  if (msg_event->source() && msg_event->source()->ToDOMWindow())
+    source_frame = msg_event->source()->ToDOMWindow()->GetFrame();
+  if (RuntimeEnabledFeatures::UserActivationPostMessageTransferEnabled() &&
+      msg_event->transferUserActivation()) {
+    GetFrame()->TransferActivationFrom(source_frame);
+  }
+
   GetFrame()->DomWindow()->DispatchMessageEventWithOriginCheck(
       intended_target_origin.Get(), event,
       std::make_unique<SourceLocation>(String(), 0, 0, nullptr));
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.cc b/third_party/blink/renderer/core/layout/layout_frame_set.cc
index 37f8fb6f..8cb81ee0 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -38,7 +38,9 @@
 namespace blink {
 
 // Adjusts proportionally the size with remaining size.
-static int AdjustSizeToRemainingSize(int current, int remaining, int total) {
+static int AdjustSizeToRemainingSize(int current,
+                                     int remaining,
+                                     int64_t total) {
   // Performs the math operations step by step to avoid the overflow.
   base::CheckedNumeric<int64_t> temp_product = current;
   temp_product *= remaining;
@@ -99,7 +101,7 @@
   DCHECK(grid_len);
 
   int total_relative = 0;
-  int total_fixed = 0;
+  int64_t total_fixed = 0;
   int total_percent = 0;
   int count_relative = 0;
   int count_fixed = 0;
diff --git a/third_party/blink/renderer/core/layout/shapes/shape.cc b/third_party/blink/renderer/core/layout/shapes/shape.cc
index 8509e4a..c2baa18 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape.cc
+++ b/third_party/blink/renderer/core/layout/shapes/shape.cc
@@ -255,14 +255,11 @@
   PaintFlags flags;
   FloatRect image_source_rect(FloatPoint(), FloatSize(image->Size()));
   IntRect image_dest_rect(IntPoint(), image_size);
-  // TODO(ccameron): No color conversion is required here.
-  std::unique_ptr<cc::PaintCanvas> canvas =
-      color_params.WrapCanvas(surface->getCanvas());
-  canvas->save();
-  canvas->clear(SK_ColorTRANSPARENT);
+  SkiaPaintCanvas canvas(surface->getCanvas());
+  canvas.clear(SK_ColorTRANSPARENT);
 
-  image->Draw(canvas.get(), flags, FloatRect(image_dest_rect),
-              image_source_rect, kDoNotRespectImageOrientation,
+  image->Draw(&canvas, flags, FloatRect(image_dest_rect), image_source_rect,
+              kDoNotRespectImageOrientation,
               Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
 
   return StaticBitmapImage::ConvertToArrayBufferContents(
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
index fe3e97c6..b855cd7 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
@@ -84,6 +84,7 @@
       std::make_move_iterator(stream_channels.begin()),
       std::make_move_iterator(stream_channels.end()));
   out->has_user_gesture = data.has_user_gesture();
+  out->transfer_user_activation = data.transfer_user_activation();
 
   out->message->SetArrayBufferContentsArray(
       std::move(array_buffer_contents_array));
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index 673e50f..5da6a2b 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -169,12 +169,11 @@
   // not clipped by a scrollable div). That is, we've taken "element-clipping"
   // into account - now we only need to ensure that this node isn't clipped by
   // a frame.
-  IntRect rect_in_root_frame;
   if (auto* document = DynamicTo<Document>(node))
     node = document->body();
   if (node && node->IsElementNode())
-    rect_in_root_frame = ToElement(*node).VisibleBoundsInVisualViewport();
-  return rect_in_root_frame.IsEmpty();
+    return ToElement(*node).VisibleBoundsInVisualViewport().IsEmpty();
+  return true;
 }
 
 // As IsOffscreen() but returns visibility through the |node|'s frame's viewport
@@ -423,6 +422,13 @@
   LayoutRect rect = node->GetDocument().GetFrame()->View()->ConvertToRootFrame(
       node->BoundingBox());
 
+  // Ensure the rect isn't empty. This can happen in some cases as the bounding
+  // box is made up of the corners of multiple child elements. If the first
+  // child is to the right or bottom of the last child, the bounding box will
+  // be empty. Ensure its not empty so intersections with the root frame don't
+  // lie about being off-screen.
+  rect.UniteEvenIfEmpty(LayoutRect(rect.Location(), LayoutSize(1, 1)));
+
   // For authors that use border instead of outline in their CSS, we compensate
   // by ignoring the border when calculating the rect of the focused element.
   if (ignore_border) {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index a74e738..981edef 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -736,6 +736,15 @@
   return object.FirstFragment().ClipPathPath();
 }
 
+static CompositingReasons CompositingReasonsForEffectProperty() {
+  // TODO(crbug.com/900241): See the comment in compositing_reasons.h about
+  // the bug for the reason of this.
+  return RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+                 RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
+             ? CompositingReason::kDirectReasonsForEffectProperty
+             : CompositingReason::kActiveOpacityAnimation;
+}
+
 static bool NeedsEffect(const LayoutObject& object,
                         CompositingReasons direct_compositing_reasons) {
   const ComputedStyle& style = object.StyleRef();
@@ -798,8 +807,7 @@
   if (style.Opacity() != 1.0f || style.HasWillChangeOpacityHint())
     return true;
 
-  if (direct_compositing_reasons &
-      CompositingReason::kDirectReasonsForEffectProperty)
+  if (direct_compositing_reasons & CompositingReasonsForEffectProperty())
     return true;
 
   if (object.StyleRef().HasMask())
@@ -1026,10 +1034,18 @@
   return page->GetLinkHighlights().NeedsHighlightEffect(object);
 }
 
+static CompositingReasons CompositingReasonsForFilterProperty() {
+  // TODO(crbug.com/900241): See the comment in compositing_reasons.h about
+  // the bug for the reason of this.
+  return RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+                 RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
+             ? CompositingReason::kDirectReasonsForFilterProperty
+             : CompositingReason::kActiveFilterAnimation;
+}
+
 static bool NeedsFilter(const LayoutObject& object,
                         CompositingReasons direct_compositing_reasons) {
-  if (direct_compositing_reasons &
-      CompositingReason::kDirectReasonsForFilterProperty)
+  if (direct_compositing_reasons & CompositingReasonsForFilterProperty())
     return true;
 
   if (!object.IsBoxModelObject() || !ToLayoutBoxModelObject(object).Layer())
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 283b59f..57c8719 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -697,13 +697,33 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest,
+       TransformAnimationCreatesEffectAndFilterNodes) {
+  LoadTestData("transform-animation.html");
+  // TODO(flackr): Verify that after https://crbug.com/900241 is fixed we no
+  // longer create opacity or filter nodes for transform animations.
+  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Transform());
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+      RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Effect());
+    EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
+  } else {
+    EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Effect());
+    EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Filter());
+  }
+}
+
+TEST_P(PaintPropertyTreeBuilderTest,
        OpacityAnimationCreatesTransformAndFilterNodes) {
   LoadTestData("opacity-animation.html");
   // TODO(flackr): Verify that after https://crbug.com/900241 is fixed we no
   // longer create transform or filter nodes for opacity animations.
   EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Transform());
   EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Effect());
-  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+      RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
+  else
+    EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Filter());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest,
diff --git a/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h b/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h
index ff96bb62..d442236 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h
+++ b/third_party/blink/renderer/modules/credentialmanager/credential_manager_proxy.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_CREDENTIAL_MANAGER_PROXY_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_CREDENTIAL_MANAGER_PROXY_H_
 
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom-blink.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
diff --git a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h
index dd94aab..5e35519 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h
+++ b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_CREDENTIAL_MANAGER_TYPE_CONVERTERS_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGER_CREDENTIAL_MANAGER_TYPE_CONVERTERS_H_
 
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/webauthn/authenticator.mojom-blink.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index c030563..80f9549 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include <utility>
 
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_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/document.h"
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
index b016faf..527a9c52 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
@@ -11,7 +11,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom-blink.h"
+#include "third_party/blink/public/mojom/credentialmanager/credential_manager.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
 #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_index.cc b/third_party/blink/renderer/modules/indexeddb/idb_index.cc
index a20657b..dce0cab 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_index.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_index.cc
@@ -250,7 +250,7 @@
 
 IDBRequest* IDBIndex::getAll(ScriptState* script_state,
                              const ScriptValue& range,
-                             unsigned long max_count,
+                             uint32_t max_count,
                              ExceptionState& exception_state) {
   IDB_TRACE1("IDBIndex::getAllRequestSetup", "index_name",
              metadata_->name.Utf8());
@@ -328,7 +328,7 @@
 
 IDBRequest* IDBIndex::GetAllInternal(ScriptState* script_state,
                                      const ScriptValue& range,
-                                     unsigned long max_count,
+                                     uint32_t max_count,
                                      ExceptionState& exception_state,
                                      bool key_only,
                                      IDBRequest::AsyncTraceState metrics) {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_index.h b/third_party/blink/renderer/modules/indexeddb/idb_index.h
index 20e69c4..751a75b8 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_index.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_index.h
@@ -81,7 +81,7 @@
   IDBRequest* getAll(ScriptState*, const ScriptValue& range, ExceptionState&);
   IDBRequest* getAll(ScriptState*,
                      const ScriptValue& range,
-                     unsigned long max_count,
+                     uint32_t max_count,
                      ExceptionState&);
   IDBRequest* getKey(ScriptState*, const ScriptValue& key, ExceptionState&);
   IDBRequest* getAllKeys(ScriptState*,
@@ -133,7 +133,7 @@
                           IDBRequest::AsyncTraceState metrics);
   IDBRequest* GetAllInternal(ScriptState*,
                              const ScriptValue& range,
-                             unsigned long max_count,
+                             uint32_t max_count,
                              ExceptionState&,
                              bool key_only,
                              IDBRequest::AsyncTraceState metrics);
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc b/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
index 7ec33b59..dc812c6 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_object_store.cc
@@ -213,7 +213,7 @@
 
 IDBRequest* IDBObjectStore::getAll(ScriptState* script_state,
                                    const ScriptValue& key_range,
-                                   unsigned long max_count,
+                                   uint32_t max_count,
                                    ExceptionState& exception_state) {
   IDB_TRACE1("IDBObjectStore::getAllRequestSetup", "store_name",
              metadata_->name.Utf8());
@@ -260,7 +260,7 @@
 
 IDBRequest* IDBObjectStore::getAllKeys(ScriptState* script_state,
                                        const ScriptValue& key_range,
-                                       unsigned long max_count,
+                                       uint32_t max_count,
                                        ExceptionState& exception_state) {
   IDB_TRACE1("IDBObjectStore::getAllKeysRequestSetup", "store_name",
              metadata_->name.Utf8());
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_object_store.h b/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
index 0f833244..a91472d4 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
+++ b/third_party/blink/renderer/modules/indexeddb/idb_object_store.h
@@ -86,12 +86,12 @@
   IDBRequest* getKey(ScriptState*, const ScriptValue& key, ExceptionState&);
   IDBRequest* getAll(ScriptState*,
                      const ScriptValue& range,
-                     unsigned long max_count,
+                     uint32_t max_count,
                      ExceptionState&);
   IDBRequest* getAll(ScriptState*, const ScriptValue& range, ExceptionState&);
   IDBRequest* getAllKeys(ScriptState*,
                          const ScriptValue& range,
-                         unsigned long max_count,
+                         uint32_t max_count,
                          ExceptionState&);
   IDBRequest* getAllKeys(ScriptState*,
                          const ScriptValue& range,
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
index 26cdc33..9a16725 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.cc
@@ -230,7 +230,7 @@
   pending_onsuccess_callbacks_ = 0;
 }
 
-void WebIDBCursorImpl::CachedAdvance(unsigned long count,
+void WebIDBCursorImpl::CachedAdvance(uint32_t count,
                                      WebIDBCallbacks* callbacks) {
   DCHECK_GE(prefetch_keys_.size(), count);
   DCHECK_EQ(prefetch_primary_keys_.size(), prefetch_keys_.size());
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
index e37de34..f4722bd 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_cursor_impl.h
@@ -43,7 +43,7 @@
                        Vector<std::unique_ptr<IDBKey>> primary_keys,
                        Vector<std::unique_ptr<IDBValue>> values);
 
-  void CachedAdvance(unsigned long count, WebIDBCallbacks* callbacks);
+  void CachedAdvance(uint32_t count, WebIDBCallbacks* callbacks);
   void CachedContinue(WebIDBCallbacks* callbacks);
 
   // This method is virtual so it can be overridden in unit tests.
diff --git a/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc b/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc
index 0bd8f206..c8eae0f 100644
--- a/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc
+++ b/third_party/blink/renderer/modules/indexeddb/web_idb_database_impl_unittest.cc
@@ -80,7 +80,7 @@
 
   std::unique_ptr<IDBKey> key = IDBKey::CreateString(key_string);
   DCHECK_EQ(value_data->size(), kMaxValueSizeForTesting - kKeySize);
-  DCHECK_GT(key->SizeEstimate() - kKeySize, static_cast<unsigned long>(0));
+  DCHECK_GT(key->SizeEstimate() - kKeySize, static_cast<size_t>(0));
   DCHECK_GT(value_data->size() + key->SizeEstimate(), kMaxValueSizeForTesting);
 
   ThreadState::Current()->CollectAllGarbage();
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index 45bf4c0..8b2c514 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -1983,6 +1983,7 @@
   if (display_cutout_fullscreen_button_)
     display_cutout_fullscreen_button_->SetIsWanted(false);
 
+  HidePopupMenu();
   StopHideMediaControlsTimer();
   StartHideMediaControlsTimer();
 }
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
index 7880c39..d58b5da 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.cc
@@ -22,8 +22,9 @@
       host_thread_(std::move(host_thread)),
       host_(nullptr, base::OnTaskRunnerDeleter(host_thread_)),
       delegate_(delegate),
-      connection_handle_for_scheduler_(
-          frame.GetFrameScheduler()->OnActiveConnectionCreated()),
+      feature_handle_for_scheduler_(frame.GetFrameScheduler()->RegisterFeature(
+          SchedulingPolicy::Feature::kWebRTC,
+          {SchedulingPolicy::DisableAggressiveThrottling()})),
       weak_ptr_factory_(this) {
   DCHECK(host_thread_);
   DCHECK(delegate_);
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
index 76abbb44..cbbd9a3 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h
@@ -116,8 +116,8 @@
   // This handle notifies scheduler about an active connection associated
   // with a frame. Handle should be destroyed when connection is closed.
   // This should have the same lifetime as |proxy_|.
-  std::unique_ptr<FrameScheduler::ActiveConnectionHandle>
-      connection_handle_for_scheduler_;
+  FrameScheduler::SchedulingAffectingFeatureHandle
+      feature_handle_for_scheduler_;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 41d9e55..2d20e09e 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -778,8 +778,10 @@
     return;
   }
 
-  connection_handle_for_scheduler_ =
-      document->GetFrame()->GetFrameScheduler()->OnActiveConnectionCreated();
+  feature_handle_for_scheduler_ =
+      document->GetFrame()->GetFrameScheduler()->RegisterFeature(
+          SchedulingPolicy::Feature::kWebRTC,
+          {SchedulingPolicy::DisableAggressiveThrottling()});
 }
 
 RTCPeerConnection::~RTCPeerConnection() {
@@ -2869,7 +2871,7 @@
 
   peer_handler_.reset();
   dispatch_scheduled_events_task_handle_.Cancel();
-  connection_handle_for_scheduler_.reset();
+  feature_handle_for_scheduler_.reset();
 }
 
 void RTCPeerConnection::ClosePeerConnection() {
@@ -3003,7 +3005,7 @@
   HostsUsingFeatures::CountAnyWorld(
       *document, HostsUsingFeatures::Feature::kRTCPeerConnectionUsed);
 
-  connection_handle_for_scheduler_.reset();
+  feature_handle_for_scheduler_.reset();
 }
 
 void RTCPeerConnection::ScheduleDispatchEvent(Event* event) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
index 7eff3d94..2cd4164 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -508,8 +508,8 @@
 
   // This handle notifies scheduler about an active connection associated
   // with a frame. Handle should be destroyed when connection is closed.
-  std::unique_ptr<FrameScheduler::ActiveConnectionHandle>
-      connection_handle_for_scheduler_;
+  FrameScheduler::SchedulingAffectingFeatureHandle
+      feature_handle_for_scheduler_;
 
   bool negotiation_needed_;
   bool stopped_;
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
index f0c03ece..0746bec 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/inspector/console_types.h"
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
index e9eddb5..175421c 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -341,6 +341,9 @@
 
   void RejectPendingDecodeAudioDataResolvers();
 
+  // When the context goes away, reject any pending script promise resolvers.
+  virtual void RejectPendingResolvers();
+
   // Returns the Document wich wich the instance is associated.
   Document* GetDocument() const;
 
@@ -364,8 +367,6 @@
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
  private:
-  friend class AudioContextAutoplayTest;
-
   // Unique ID for each context.
   const String uuid_;
 
@@ -379,10 +380,6 @@
   // Listener for the PannerNodes
   Member<AudioListener> listener_;
 
-  // When the context is going away, reject any pending script promise
-  // resolvers.
-  virtual void RejectPendingResolvers();
-
   // Set to |true| by the audio thread when it posts a main-thread task to
   // perform delayed state sync'ing updates that needs to be done on the main
   // thread. Cleared by the main thread task once it has run.
diff --git a/third_party/blink/renderer/modules/webdatabase/database.cc b/third_party/blink/renderer/modules/webdatabase/database.cc
index a0897dc..f57a499 100644
--- a/third_party/blink/renderer/modules/webdatabase/database.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database.cc
@@ -220,7 +220,7 @@
                    const String& name,
                    const String& expected_version,
                    const String& display_name,
-                   unsigned estimated_size)
+                   uint32_t estimated_size)
     : database_context_(database_context),
       name_(name.IsolatedCopy()),
       expected_version_(expected_version.IsolatedCopy()),
@@ -617,7 +617,7 @@
   return display_name_.IsolatedCopy();
 }
 
-unsigned Database::EstimatedSize() const {
+uint32_t Database::EstimatedSize() const {
   return estimated_size_;
 }
 
diff --git a/third_party/blink/renderer/modules/webdatabase/database.h b/third_party/blink/renderer/modules/webdatabase/database.h
index 567dbf1..217580a 100644
--- a/third_party/blink/renderer/modules/webdatabase/database.h
+++ b/third_party/blink/renderer/modules/webdatabase/database.h
@@ -58,7 +58,7 @@
            const String& name,
            const String& expected_version,
            const String& display_name,
-           unsigned estimated_size);
+           uint32_t estimated_size);
   ~Database() override;
   void Trace(blink::Visitor*) override;
 
@@ -101,7 +101,7 @@
   const SecurityOrigin* GetSecurityOrigin() const;
   String StringIdentifier() const;
   String DisplayName() const;
-  unsigned EstimatedSize() const;
+  uint32_t EstimatedSize() const;
   String FileName() const;
   SQLiteDatabase& SqliteDatabase() { return sqlite_database_; }
 
@@ -178,7 +178,7 @@
   String name_;
   String expected_version_;
   String display_name_;
-  unsigned estimated_size_;
+  uint32_t estimated_size_;
   String filename_;
 
   DatabaseGuid guid_;
diff --git a/third_party/blink/renderer/modules/webdatabase/database_manager.cc b/third_party/blink/renderer/modules/webdatabase/database_manager.cc
index 9dda0be..ba8b939b 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_manager.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database_manager.cc
@@ -134,7 +134,7 @@
     const String& name,
     const String& expected_version,
     const String& display_name,
-    unsigned estimated_size,
+    uint32_t estimated_size,
     V8DatabaseCallback* creation_callback,
     bool set_version_in_new_database,
     DatabaseError& error,
@@ -170,7 +170,7 @@
                                         const String& name,
                                         const String& expected_version,
                                         const String& display_name,
-                                        unsigned estimated_size,
+                                        uint32_t estimated_size,
                                         V8DatabaseCallback* creation_callback,
                                         DatabaseError& error,
                                         String& error_message) {
diff --git a/third_party/blink/renderer/modules/webdatabase/database_manager.h b/third_party/blink/renderer/modules/webdatabase/database_manager.h
index c00aa8e..50a7cc7 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_manager.h
+++ b/third_party/blink/renderer/modules/webdatabase/database_manager.h
@@ -70,7 +70,7 @@
                          const String& name,
                          const String& expected_version,
                          const String& display_name,
-                         unsigned estimated_size,
+                         uint32_t estimated_size,
                          V8DatabaseCallback*,
                          DatabaseError&,
                          String& error_message);
@@ -94,7 +94,7 @@
                                  const String& name,
                                  const String& expected_version,
                                  const String& display_name,
-                                 unsigned estimated_size,
+                                 uint32_t estimated_size,
                                  V8DatabaseCallback*,
                                  bool set_version_in_new_database,
                                  DatabaseError&,
diff --git a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc
index 9700310..ac59107 100644
--- a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc
+++ b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc
@@ -42,7 +42,7 @@
                                              const String& name,
                                              const String& version,
                                              const String& display_name,
-                                             unsigned estimated_size,
+                                             uint32_t estimated_size,
                                              ExceptionState& exception_state) {
   return openDatabase(window, name, version, display_name, estimated_size,
                       nullptr, exception_state);
@@ -53,7 +53,7 @@
     const String& name,
     const String& version,
     const String& display_name,
-    unsigned estimated_size,
+    uint32_t estimated_size,
     V8DatabaseCallback* creation_callback,
     ExceptionState& exception_state) {
   if (!window.IsCurrentlyDisplayedInFrame())
diff --git a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.h b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.h
index 91c8685..cfa9ac4 100644
--- a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.h
+++ b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.h
@@ -45,13 +45,13 @@
                                 const String& name,
                                 const String& version,
                                 const String& display_name,
-                                unsigned estimated_size,
+                                uint32_t estimated_size,
                                 ExceptionState&);
   static Database* openDatabase(LocalDOMWindow&,
                                 const String& name,
                                 const String& version,
                                 const String& display_name,
-                                unsigned estimated_size,
+                                uint32_t estimated_size,
                                 V8DatabaseCallback* creation_callback,
                                 ExceptionState&);
 };
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
index fc2b705e..7024b69 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -219,8 +219,11 @@
   if (GetBaseFetchContext()->ShouldBlockWebSocketByMixedContentCheck(url))
     return false;
 
-  if (auto* scheduler = execution_context_->GetScheduler())
-    connection_handle_for_scheduler_ = scheduler->OnActiveConnectionCreated();
+  if (auto* scheduler = execution_context_->GetScheduler()) {
+    feature_handle_for_scheduler_ = scheduler->RegisterFeature(
+        SchedulingPolicy::Feature::kWebSocket,
+        {SchedulingPolicy::DisableAggressiveThrottling()});
+  }
 
   if (MixedContentChecker::IsMixedContent(
           execution_context_->GetSecurityOrigin(), url)) {
@@ -396,7 +399,7 @@
         "data", InspectorWebSocketEvent::Data(execution_context_, identifier_));
     probe::DidCloseWebSocket(execution_context_, identifier_);
   }
-  connection_handle_for_scheduler_.reset();
+  feature_handle_for_scheduler_.reset();
   AbortAsyncOperations();
   handshake_throttle_.reset();
   handle_.reset();
@@ -611,7 +614,7 @@
   NETWORK_DVLOG(1) << this << " DidFail(" << handle << ", " << String(message)
                    << ")";
 
-  connection_handle_for_scheduler_.reset();
+  feature_handle_for_scheduler_.reset();
 
   DCHECK(handle_);
   DCHECK_EQ(handle, handle_.get());
@@ -689,7 +692,7 @@
   NETWORK_DVLOG(1) << this << " DidClose(" << handle << ", " << was_clean
                    << ", " << code << ", " << String(reason) << ")";
 
-  connection_handle_for_scheduler_.reset();
+  feature_handle_for_scheduler_.reset();
 
   DCHECK(handle_);
   DCHECK_EQ(handle, handle_.get());
@@ -777,7 +780,7 @@
 
 void WebSocketChannelImpl::TearDownFailedConnection() {
   // |handle_| and |client_| can be null here.
-  connection_handle_for_scheduler_.reset();
+  feature_handle_for_scheduler_.reset();
   handshake_throttle_.reset();
 
   if (client_)
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
index 402fa3a0..6ba794de 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -202,8 +202,8 @@
   uint64_t sending_quota_;
   uint64_t received_data_size_for_flow_control_;
   wtf_size_t sent_size_of_top_message_;
-  std::unique_ptr<FrameScheduler::ActiveConnectionHandle>
-      connection_handle_for_scheduler_;
+  FrameScheduler::SchedulingAffectingFeatureHandle
+      feature_handle_for_scheduler_;
 
   std::unique_ptr<SourceLocation> location_at_construction_;
   network::mojom::blink::WebSocketHandshakeRequestPtr handshake_request_;
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
index da49926..4d343cdc 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.cc
@@ -64,23 +64,28 @@
   return base::RandInt(min, max - 1);
 }
 
-bool DarkModeImageClassifier::ShouldApplyDarkModeFilterToImage(Image& image) {
-  DarkModeClassification result = image.GetDarkModeClassification();
+bool DarkModeImageClassifier::ShouldApplyDarkModeFilterToImage(
+    Image& image,
+    const FloatRect& src_rect) {
+  DarkModeClassification result = image.GetDarkModeClassification(src_rect);
+  // Check if the image has already been classified.
   if (result != DarkModeClassification::kNotClassified)
     return result == DarkModeClassification::kApplyDarkModeFilter;
 
-  if (image.width() < kMinImageSizeForClassification1D ||
-      image.height() < kMinImageSizeForClassification1D) {
+  if (src_rect.Width() < kMinImageSizeForClassification1D ||
+      src_rect.Height() < kMinImageSizeForClassification1D) {
     result = DarkModeClassification::kApplyDarkModeFilter;
   } else {
     std::vector<float> features;
-    if (!ComputeImageFeatures(image, &features))
+    if (!ComputeImageFeatures(image, src_rect, &features))
       result = DarkModeClassification::kDoNotApplyDarkModeFilter;
     else
       result = ClassifyImage(features);
   }
 
-  image.SetDarkModeClassification(result);
+  // Store the classification result in the image object using
+  // src_rect's location as a key for the map.
+  image.AddDarkModeClassification(src_rect, result);
   return result == DarkModeClassification::kApplyDarkModeFilter;
 }
 
@@ -89,9 +94,10 @@
 // method, and |GetFeatures| function for description of the features.
 bool DarkModeImageClassifier::ComputeImageFeatures(
     Image& image,
+    const FloatRect& src_rect,
     std::vector<float>* features) {
   SkBitmap bitmap;
-  if (!GetBitmap(image, &bitmap))
+  if (!GetBitmap(image, src_rect, &bitmap))
     return false;
 
   if (use_testing_random_generator_)
@@ -106,16 +112,25 @@
   return true;
 }
 
-bool DarkModeImageClassifier::GetBitmap(Image& image, SkBitmap* bitmap) {
-  if (!image.IsBitmapImage() || !image.width() || !image.height())
+bool DarkModeImageClassifier::GetBitmap(Image& image,
+                                        const FloatRect& src_rect,
+                                        SkBitmap* bitmap) {
+  if (!image.IsBitmapImage() || !src_rect.Width() || !src_rect.Height())
     return false;
 
-  bitmap->allocPixels(
-      SkImageInfo::MakeN32(image.width(), image.height(), kPremul_SkAlphaType));
+  SkScalar sx = SkFloatToScalar(src_rect.X());
+  SkScalar sy = SkFloatToScalar(src_rect.Y());
+  SkScalar sw = SkFloatToScalar(src_rect.Width());
+  SkScalar sh = SkFloatToScalar(src_rect.Height());
+  SkRect src = {sx, sy, sx + sw, sy + sh};
+  SkRect dest = {0, 0, sw, sh};
+  bitmap->allocPixels(SkImageInfo::MakeN32(static_cast<int>(src_rect.Width()),
+                                           static_cast<int>(src_rect.Height()),
+                                           kPremul_SkAlphaType));
   SkCanvas canvas(*bitmap);
   canvas.clear(SK_ColorTRANSPARENT);
-  canvas.drawImageRect(image.PaintImageForCurrentFrame().GetSkImage(),
-                       SkRect::MakeIWH(image.width(), image.height()), nullptr);
+  canvas.drawImageRect(image.PaintImageForCurrentFrame().GetSkImage(), src,
+                       dest, nullptr);
   return true;
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
index 0c2aa1f..6d7d968d 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -23,11 +24,20 @@
   ~DarkModeImageClassifier() = default;
 
   // Decides if a dark mode filter should be applied to the image or not.
-  bool ShouldApplyDarkModeFilterToImage(Image&);
+  // |src_rect| is needed in case of image sprites for the location and
+  // size of the smaller images that the sprite holds.
+  // For images that come from sprites the |src_rect.X| and |src_rect.Y|
+  // can be non-zero. But for normal images they are both zero.
+  bool ShouldApplyDarkModeFilterToImage(Image& image,
+                                        const FloatRect& src_rect);
 
   bool ComputeImageFeaturesForTesting(Image& image,
                                       std::vector<float>* features) {
-    return ComputeImageFeatures(image, features);
+    return ComputeImageFeatures(
+        image,
+        FloatRect(0, 0, static_cast<float>(image.width()),
+                  static_cast<float>(image.height())),
+        features);
   }
 
   void SetRandomGeneratorForTesting() { use_testing_random_generator_ = true; }
@@ -41,10 +51,10 @@
   enum class ColorMode { kColor = 0, kGrayscale = 1 };
 
   // Computes the features vector for a given image.
-  bool ComputeImageFeatures(Image&, std::vector<float>*);
+  bool ComputeImageFeatures(Image&, const FloatRect&, std::vector<float>*);
 
   // Converts image to SkBitmap and returns true if successful.
-  bool GetBitmap(Image&, SkBitmap*);
+  bool GetBitmap(Image&, const FloatRect&, SkBitmap*);
 
   // Given a SkBitmap, extracts a sample set of pixels (|sampled_pixels|),
   // |transparency_ratio|, and |background_ratio|.
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
index f078f4f..c9fc63b 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_image_classifier_test.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -17,6 +18,28 @@
 
 namespace blink {
 
+class FakeImageForCacheTest : public Image {
+ public:
+  static scoped_refptr<FakeImageForCacheTest> Create() {
+    return base::AdoptRef(new FakeImageForCacheTest());
+  }
+
+  int GetMapSize() { return dark_mode_classifications_.size(); }
+
+  // Pure virtual functions that have to be overridden.
+  bool CurrentFrameKnownToBeOpaque() override { return false; }
+  IntSize Size() const override { return IntSize(0, 0); }
+  void DestroyDecodedData() override {}
+  PaintImage PaintImageForCurrentFrame() override { return PaintImage(); }
+  void Draw(cc::PaintCanvas*,
+            const cc::PaintFlags&,
+            const FloatRect& dst_rect,
+            const FloatRect& src_rect,
+            RespectImageOrientationEnum,
+            ImageClampingMode,
+            ImageDecodingMode) override {}
+};
+
 class DarkModeImageClassifierTest : public testing::Test {
  public:
   // Loads the image from |file_name|, computes features vector into |features|,
@@ -27,7 +50,8 @@
     scoped_refptr<BitmapImage> image = LoadImage(file_name);
     classifier_.SetRandomGeneratorForTesting();
     classifier_.ComputeImageFeaturesForTesting(*image.get(), features);
-    return classifier_.ShouldApplyDarkModeFilterToImage(*image.get());
+    return classifier_.ShouldApplyDarkModeFilterToImage(
+        *image.get(), FloatRect(0, 0, image->width(), image->height()));
   }
 
   void AssertFeaturesEqual(const std::vector<float>& features,
@@ -117,4 +141,34 @@
   AssertFeaturesEqual(features, {1.0f, 0.0166016f, 0.0f, 0.59f});
 }
 
+TEST_F(DarkModeImageClassifierTest, Caching) {
+  scoped_refptr<FakeImageForCacheTest> image = FakeImageForCacheTest::Create();
+  FloatRect src_rect1(0, 0, 50, 50);
+  FloatRect src_rect2(5, 20, 100, 100);
+  FloatRect src_rect3(6, -9, 50, 50);
+
+  EXPECT_EQ(image->GetDarkModeClassification(src_rect1),
+            DarkModeClassification::kNotClassified);
+  image->AddDarkModeClassification(
+      src_rect1, DarkModeClassification::kApplyDarkModeFilter);
+  EXPECT_EQ(image->GetDarkModeClassification(src_rect1),
+            DarkModeClassification::kApplyDarkModeFilter);
+
+  EXPECT_EQ(image->GetDarkModeClassification(src_rect2),
+            DarkModeClassification::kNotClassified);
+  image->AddDarkModeClassification(
+      src_rect2, DarkModeClassification::kDoNotApplyDarkModeFilter);
+  EXPECT_EQ(image->GetDarkModeClassification(src_rect2),
+            DarkModeClassification::kDoNotApplyDarkModeFilter);
+
+  EXPECT_EQ(image->GetDarkModeClassification(src_rect3),
+            DarkModeClassification::kNotClassified);
+  image->AddDarkModeClassification(
+      src_rect3, DarkModeClassification::kApplyDarkModeFilter);
+  EXPECT_EQ(image->GetDarkModeClassification(src_rect3),
+            DarkModeClassification::kApplyDarkModeFilter);
+
+  EXPECT_EQ(image->GetMapSize(), 3);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 386e77a..e11034e 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -916,7 +916,7 @@
   image_flags.setBlendMode(op);
   image_flags.setColor(SK_ColorBLACK);
   image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src));
-  if (ShouldApplyDarkModeFilterToImage(*image))
+  if (ShouldApplyDarkModeFilterToImage(*image, src))
     image_flags.setColorFilter(dark_mode_filter_);
   image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation,
               Image::kClampImageToSourceRect, decode_mode);
@@ -1414,14 +1414,16 @@
   return nullptr;
 }
 
-bool GraphicsContext::ShouldApplyDarkModeFilterToImage(Image& image) {
+bool GraphicsContext::ShouldApplyDarkModeFilterToImage(
+    Image& image,
+    const FloatRect& src_rect) {
   if (!dark_mode_filter_)
     return false;
 
   switch (dark_mode_settings_.image_policy) {
     case DarkModeImagePolicy::kFilterSmart:
       return dark_mode_image_classifier_.ShouldApplyDarkModeFilterToImage(
-          image);
+          image, src_rect);
     case DarkModeImagePolicy::kFilterAll:
       return true;
     default:
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index 1feabd1..8c28c928 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -469,7 +469,8 @@
                                const Color&);
 
   class DarkModeFlags;
-  bool ShouldApplyDarkModeFilterToImage(Image&);
+  bool ShouldApplyDarkModeFilterToImage(Image& image,
+                                        const FloatRect& src_rect);
   Color ApplyDarkModeFilter(const Color& input) const;
 
   // null indicates painting is contextDisabled. Never delete this object.
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index 9a5d62e..6f17c4de 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -92,8 +92,7 @@
     : image_observer_disabled_(false),
       image_observer_(observer),
       stable_image_id_(PaintImage::GetNextId()),
-      is_multipart_(is_multipart),
-      dark_mode_classification_(DarkModeClassification::kNotClassified) {}
+      is_multipart_(is_multipart) {}
 
 Image::~Image() = default;
 
@@ -375,4 +374,28 @@
   return bitmap;
 }
 
+DarkModeClassification Image::GetDarkModeClassification(
+    const FloatRect& src_rect) {
+  // Assuming that multiple uses of the same sprite region all have the same
+  // size, only the top left corner coordinates of the src_rect are used to
+  // generate the key for caching and retrieving the classification.
+  ClassificationKey key(src_rect.X(), src_rect.Y());
+  std::map<ClassificationKey, DarkModeClassification>::iterator result =
+      dark_mode_classifications_.find(key);
+  if (result == dark_mode_classifications_.end())
+    return DarkModeClassification::kNotClassified;
+
+  return result->second;
+}
+
+void Image::AddDarkModeClassification(
+    const FloatRect& src_rect,
+    DarkModeClassification dark_mode_classification) {
+  // Add the classification in the map only if the image is not classified yet.
+  DCHECK(GetDarkModeClassification(src_rect) ==
+         DarkModeClassification::kNotClassified);
+  ClassificationKey key(src_rect.X(), src_rect.Y());
+  dark_mode_classifications_[key] = dark_mode_classification;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/image.h b/third_party/blink/renderer/platform/graphics/image.h
index 00df2f2..6ce60ae 100644
--- a/third_party/blink/renderer/platform/graphics/image.h
+++ b/third_party/blink/renderer/platform/graphics/image.h
@@ -236,16 +236,13 @@
     return nullptr;
   }
 
-  DarkModeClassification GetDarkModeClassification() {
-    return dark_mode_classification_;
-  }
+  DarkModeClassification GetDarkModeClassification(const FloatRect& src_rect);
 
   // Dark mode classification result is cached to be consistent and have
   // higher performance for future paints.
-  void SetDarkModeClassification(
-      const DarkModeClassification dark_mode_classification) {
-    dark_mode_classification_ = dark_mode_classification;
-  }
+  void AddDarkModeClassification(
+      const FloatRect& src_rect,
+      const DarkModeClassification dark_mode_classification);
 
   PaintImage::Id paint_image_id() const { return stable_image_id_; }
 
@@ -270,6 +267,10 @@
   // Whether or not size is available yet.
   virtual bool IsSizeAvailable() { return true; }
 
+  typedef std::pair<float, float> ClassificationKey;
+  std::map<ClassificationKey, DarkModeClassification>
+      dark_mode_classifications_;
+
  private:
   bool image_observer_disabled_;
   scoped_refptr<SharedBuffer> encoded_image_data_;
@@ -283,8 +284,6 @@
   WeakPersistent<ImageObserver> image_observer_;
   PaintImage::Id stable_image_id_;
   const bool is_multipart_;
-  DarkModeClassification dark_mode_classification_;
-
   DISALLOW_COPY_AND_ASSIGN(Image);
 };
 
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc
index 8dacef4..09b23ba5b 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.cc
+++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -663,7 +663,8 @@
     }
   }
 
-  if (ShouldScheduleIdleGC()) {
+  if (!RuntimeEnabledFeatures::HeapUnifiedGarbageCollectionEnabled() &&
+      ShouldScheduleIdleGC()) {
     VLOG(2) << "[state:" << this << "] "
             << "ScheduleGCIfNeeded: Scheduled idle GC";
     ScheduleIdleGC();
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn
index d6f3455..5668e06 100644
--- a/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -116,6 +116,7 @@
     "public/post_cancellable_task.h",
     "public/post_cross_thread_task.h",
     "public/scheduling_lifecycle_state.h",
+    "public/scheduling_policy.h",
     "public/thread.h",
     "public/thread_cpu_throttler.h",
     "public/thread_scheduler.h",
diff --git a/third_party/blink/renderer/platform/scheduler/DEPS b/third_party/blink/renderer/platform/scheduler/DEPS
index cee8cd07..4ebd130 100644
--- a/third_party/blink/renderer/platform/scheduler/DEPS
+++ b/third_party/blink/renderer/platform/scheduler/DEPS
@@ -44,6 +44,7 @@
   "+base/threading/sequenced_task_runner_handle.h",
   "+base/threading/thread.h",
   "+base/threading/thread_checker.h",
+  "+base/traits_bag.h",
   "+components/scheduling_metrics",
   "+services/metrics",
 
diff --git a/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc
index d5b0eb59..a635738d 100644
--- a/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/frame_or_worker_scheduler.cc
@@ -16,12 +16,44 @@
     scheduler_->RemoveLifecycleObserver(observer_);
 }
 
+FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle::
+    SchedulingAffectingFeatureHandle(
+        SchedulingPolicy::Feature feature,
+        SchedulingPolicy policy,
+        base::WeakPtr<FrameOrWorkerScheduler> scheduler)
+    : feature_(feature), policy_(policy), scheduler_(std::move(scheduler)) {
+  DCHECK(scheduler_);
+  scheduler_->OnStartedUsingFeature(feature_, policy_);
+}
+
+FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle::
+    SchedulingAffectingFeatureHandle(SchedulingAffectingFeatureHandle&& other)
+    : feature_(other.feature_), scheduler_(std::move(other.scheduler_)) {
+  other.scheduler_ = nullptr;
+}
+
+FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle&
+FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle::operator=(
+    SchedulingAffectingFeatureHandle&& other) {
+  feature_ = other.feature_;
+  policy_ = std::move(other.policy_);
+  scheduler_ = std::move(other.scheduler_);
+  other.scheduler_ = nullptr;
+  return *this;
+}
+
 FrameOrWorkerScheduler::FrameOrWorkerScheduler() : weak_factory_(this) {}
 
 FrameOrWorkerScheduler::~FrameOrWorkerScheduler() {
   weak_factory_.InvalidateWeakPtrs();
 }
 
+FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
+FrameOrWorkerScheduler::RegisterFeature(SchedulingPolicy::Feature feature,
+                                        SchedulingPolicy policy) {
+  return SchedulingAffectingFeatureHandle(feature, policy, GetWeakPtr());
+}
+
 std::unique_ptr<FrameOrWorkerScheduler::LifecycleObserverHandle>
 FrameOrWorkerScheduler::AddLifecycleObserver(ObserverType type,
                                              Observer* observer) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index 5f7ce86..fa9dabe 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -118,19 +118,6 @@
 
 }  // namespace
 
-FrameSchedulerImpl::ActiveConnectionHandleImpl::ActiveConnectionHandleImpl(
-    FrameSchedulerImpl* frame_scheduler)
-    : frame_scheduler_(frame_scheduler->GetWeakPtr()) {
-  frame_scheduler->DidOpenActiveConnection();
-}
-
-FrameSchedulerImpl::ActiveConnectionHandleImpl::~ActiveConnectionHandleImpl() {
-  if (frame_scheduler_) {
-    static_cast<FrameSchedulerImpl*>(frame_scheduler_.get())
-        ->DidCloseActiveConnection();
-  }
-}
-
 FrameSchedulerImpl::PauseSubresourceLoadingHandleImpl::
     PauseSubresourceLoadingHandleImpl(
         base::WeakPtr<FrameSchedulerImpl> frame_scheduler)
@@ -622,6 +609,22 @@
   return WebScopedVirtualTimePauser(main_thread_scheduler_, duration, name);
 }
 
+void FrameSchedulerImpl::OnStartedUsingFeature(
+    SchedulingPolicy::Feature feature,
+    const SchedulingPolicy& policy) {
+  // TODO(altimin): Rename *ActiveConnection to
+  // Enable/DisableAggressiveThrottling.
+  if (policy.disable_aggressive_throttling)
+    DidOpenActiveConnection();
+}
+
+void FrameSchedulerImpl::OnStoppedUsingFeature(
+    SchedulingPolicy::Feature feature,
+    const SchedulingPolicy& policy) {
+  if (policy.disable_aggressive_throttling)
+    DidCloseActiveConnection();
+}
+
 void FrameSchedulerImpl::DidOpenActiveConnection() {
   ++active_connection_count_;
   has_active_connection_ = static_cast<bool>(active_connection_count_);
@@ -766,11 +769,6 @@
   main_thread_scheduler_->OnFirstMeaningfulPaint();
 }
 
-std::unique_ptr<FrameScheduler::ActiveConnectionHandle>
-FrameSchedulerImpl::OnActiveConnectionCreated() {
-  return std::make_unique<FrameSchedulerImpl::ActiveConnectionHandleImpl>(this);
-}
-
 bool FrameSchedulerImpl::ShouldThrottleTaskQueues() const {
   if (!RuntimeEnabledFeatures::TimerThrottlingForBackgroundTabsEnabled())
     return false;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index 887ab89..5207abb 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -107,12 +107,16 @@
       const WTF::String& name,
       WebScopedVirtualTimePauser::VirtualTaskDuration duration) override;
   void OnFirstMeaningfulPaint() override;
-  std::unique_ptr<ActiveConnectionHandle> OnActiveConnectionCreated() override;
   void AsValueInto(base::trace_event::TracedValue* state) const;
   bool IsExemptFromBudgetBasedThrottling() const override;
   std::unique_ptr<blink::mojom::blink::PauseSubresourceLoadingHandle>
   GetPauseSubresourceLoadingHandle() override;
 
+  void OnStartedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override;
+  void OnStoppedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override;
+
   scoped_refptr<base::SingleThreadTaskRunner> ControlTaskRunner();
 
   void UpdatePolicy();
@@ -180,17 +184,6 @@
   friend class page_scheduler_impl_unittest::PageSchedulerImplTest;
   friend class ResourceLoadingTaskRunnerHandleImpl;
 
-  class ActiveConnectionHandleImpl : public ActiveConnectionHandle {
-   public:
-    ActiveConnectionHandleImpl(FrameSchedulerImpl* frame_scheduler);
-    ~ActiveConnectionHandleImpl() override;
-
-   private:
-    base::WeakPtr<FrameOrWorkerScheduler> frame_scheduler_;
-
-    DISALLOW_COPY_AND_ASSIGN(ActiveConnectionHandleImpl);
-  };
-
   // A class that adds and removes itself from the passed in weak pointer. While
   // one exists, resource loading is paused.
   class PauseSubresourceLoadingHandleImpl
@@ -224,12 +217,12 @@
   void UpdateTaskQueueThrottling(MainThreadTaskQueue* task_queue,
                                  bool should_throttle);
 
-  void DidOpenActiveConnection();
-  void DidCloseActiveConnection();
-
   void AddPauseSubresourceLoadingHandle();
   void RemovePauseSubresourceLoadingHandle();
 
+  void DidOpenActiveConnection();
+  void DidCloseActiveConnection();
+
   std::unique_ptr<ResourceLoadingTaskRunnerHandleImpl>
   CreateResourceLoadingTaskRunnerHandleImpl();
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 56f1745..4a16b91467 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -2313,7 +2313,7 @@
     const base::sequence_manager::Task& task,
     const TaskQueue::TaskTiming& task_timing) {
   main_thread_only().running_queues.push(queue);
-  queueing_time_estimator_.OnExecutionStarted(task_timing.start_time(), queue);
+  queueing_time_estimator_.OnExecutionStarted(task_timing.start_time());
   if (main_thread_only().nested_runloop)
     return;
 
@@ -2485,8 +2485,7 @@
 
 void MainThreadSchedulerImpl::OnExitNestedRunLoop() {
   DCHECK(!main_thread_only().running_queues.empty());
-  queueing_time_estimator_.OnExecutionStarted(
-      real_time_domain()->Now(), main_thread_only().running_queues.top().get());
+  queueing_time_estimator_.OnExecutionStarted(real_time_domain()->Now());
   main_thread_only().nested_runloop = false;
   ApplyVirtualTimePolicy();
 }
@@ -2557,20 +2556,6 @@
   }
 }
 
-void MainThreadSchedulerImpl::OnReportFineGrainedExpectedQueueingTime(
-    const char* split_description,
-    base::TimeDelta queueing_time) {
-  if (!ContainsLocalMainFrame())
-    return;
-
-  base::UmaHistogramCustomCounts(
-      split_description,
-      base::saturated_cast<base::HistogramBase::Sample>(
-          queueing_time.InMicroseconds()),
-      kMinExpectedQueueingTimeBucket, kMaxExpectedQueueingTimeBucket,
-      kNumberExpectedQueueingTimeBuckets);
-}
-
 AutoAdvancingVirtualTimeDomain*
 MainThreadSchedulerImpl::GetVirtualTimeDomain() {
   return virtual_time_domain_.get();
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 2ba7eca..72fbf47 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -244,9 +244,6 @@
   // QueueingTimeEstimator::Client implementation:
   void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time,
                                         bool is_disjoint_window) override;
-  void OnReportFineGrainedExpectedQueueingTime(
-      const char* split_description,
-      base::TimeDelta queueing_time) override;
 
   // ThreadSchedulerImpl implementation:
   scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
index ea609fb..f718d03 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
@@ -1159,8 +1159,10 @@
                   base::TimeTicks() + base::TimeDelta::FromSeconds(51)));
   run_times.clear();
 
-  std::unique_ptr<FrameScheduler::ActiveConnectionHandle> websocket_connection =
-      frame_scheduler1->OnActiveConnectionCreated();
+  FrameScheduler::SchedulingAffectingFeatureHandle websocket_feature =
+      frame_scheduler1->RegisterFeature(
+          SchedulingPolicy::Feature::kWebSocket,
+          {SchedulingPolicy::DisableAggressiveThrottling()});
 
   for (size_t i = 0; i < 3; ++i) {
     ThrottleableTaskQueueForScheduler(frame_scheduler1.get())
@@ -1203,7 +1205,7 @@
           base::TimeTicks() + base::TimeDelta::FromMilliseconds(59500)));
   run_times.clear();
 
-  websocket_connection.reset();
+  websocket_feature.reset();
 
   // Wait for 10s to enable throttling back.
   FastForwardTo(base::TimeTicks() + base::TimeDelta::FromMilliseconds(70500));
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc
index 0ee47f42..bd8588b2 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc
@@ -6,17 +6,11 @@
 
 #include <algorithm>
 
-#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-
 namespace blink {
 namespace scheduler {
 
 namespace {
 
-#define FRAME_STATUS_PREFIX \
-  "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-
 // On Windows, when a computer sleeps, we may end up getting extremely long
 // tasks or idling. We'll ignore tasks longer than |kInvalidPeriodThreshold|.
 constexpr base::TimeDelta kInvalidPeriodThreshold =
@@ -72,13 +66,11 @@
   DCHECK_GE(steps_per_window, 1);
 }
 
-void QueueingTimeEstimator::OnExecutionStarted(base::TimeTicks now,
-                                               MainThreadTaskQueue* queue) {
+void QueueingTimeEstimator::OnExecutionStarted(base::TimeTicks now) {
   DCHECK(!busy_);
   AdvanceTime(now);
   busy_ = true;
   busy_period_start_time_ = now;
-  calculator_.UpdateStatusFromTaskQueue(queue);
 }
 
 void QueueingTimeEstimator::OnExecutionStopped(base::TimeTicks now) {
@@ -142,18 +134,9 @@
 QueueingTimeEstimator::Calculator::Calculator(int steps_per_window)
     : steps_per_window_(steps_per_window), sliding_window_(steps_per_window) {}
 
-void QueueingTimeEstimator::Calculator::UpdateStatusFromTaskQueue(
-    MainThreadTaskQueue* queue) {
-  FrameScheduler* scheduler = queue ? queue->GetFrameScheduler() : nullptr;
-  current_frame_status_ =
-      scheduler ? GetFrameStatus(scheduler) : FrameStatus::kNone;
-}
-
 void QueueingTimeEstimator::Calculator::AddQueueingTime(
     base::TimeDelta queueing_time) {
   step_expected_queueing_time_ += queueing_time;
-  eqt_by_frame_status_[static_cast<int>(current_frame_status_)] +=
-      queueing_time;
 }
 
 void QueueingTimeEstimator::Calculator::EndStep(Client* client) {
@@ -169,44 +152,6 @@
   client->OnQueueingTimeForWindowEstimated(sliding_window_.GetAverage(),
                                            sliding_window_.IndexIsZero());
   ResetStep();
-  if (!sliding_window_.IndexIsZero())
-    return;
-
-// Report splits by frame status.
-#define REPORT_BY_FRAME_TYPE(frame)                                            \
-  client->OnReportFineGrainedExpectedQueueingTime(                             \
-      FRAME_STATUS_PREFIX #frame "Visible",                                    \
-      (eqt_by_frame_status_[static_cast<int>(                                  \
-           FrameStatus::k##frame##Visible)] +                                  \
-       eqt_by_frame_status_[static_cast<int>(                                  \
-           FrameStatus::k##frame##VisibleService)]) /                          \
-          steps_per_window_);                                                  \
-  client->OnReportFineGrainedExpectedQueueingTime(                             \
-      FRAME_STATUS_PREFIX #frame "Hidden",                                     \
-      (eqt_by_frame_status_[static_cast<int>(FrameStatus::k##frame##Hidden)] + \
-       eqt_by_frame_status_[static_cast<int>(                                  \
-           FrameStatus::k##frame##HiddenService)]) /                           \
-          steps_per_window_);                                                  \
-  client->OnReportFineGrainedExpectedQueueingTime(                             \
-      FRAME_STATUS_PREFIX #frame "Background",                                 \
-      (eqt_by_frame_status_[static_cast<int>(                                  \
-           FrameStatus::k##frame##Background)] +                               \
-       eqt_by_frame_status_[static_cast<int>(                                  \
-           FrameStatus::k##frame##BackgroundExemptSelf)] +                     \
-       eqt_by_frame_status_[static_cast<int>(                                  \
-           FrameStatus::k##frame##BackgroundExemptOther)]) /                   \
-          steps_per_window_);
-  REPORT_BY_FRAME_TYPE(MainFrame)
-  REPORT_BY_FRAME_TYPE(SameOrigin)
-  REPORT_BY_FRAME_TYPE(CrossOrigin)
-#undef REPORT_BY_FRAME_TYPE
-  client->OnReportFineGrainedExpectedQueueingTime(
-      FRAME_STATUS_PREFIX "Other",
-      (eqt_by_frame_status_[static_cast<int>(FrameStatus::kNone)] +
-       eqt_by_frame_status_[static_cast<int>(FrameStatus::kDetached)]) /
-          steps_per_window_);
-  std::fill(eqt_by_frame_status_.begin(), eqt_by_frame_status_.end(),
-            base::TimeDelta());
 }
 
 void QueueingTimeEstimator::Calculator::ResetStep() {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h
index 9bc8bc589..59f2dca3 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h
@@ -12,7 +12,6 @@
 #include "base/time/time.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
@@ -28,9 +27,6 @@
    public:
     virtual void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time,
                                                   bool is_disjoint_window) = 0;
-    virtual void OnReportFineGrainedExpectedQueueingTime(
-        const char* split_description,
-        base::TimeDelta queueing_time) = 0;
     Client() = default;
     virtual ~Client() = default;
 
@@ -60,7 +56,6 @@
    public:
     explicit Calculator(int steps_per_window);
 
-    void UpdateStatusFromTaskQueue(MainThreadTaskQueue* queue);
     void AddQueueingTime(base::TimeDelta queuing_time);
     void EndStep(Client* client);
     void ResetStep();
@@ -98,11 +93,6 @@
     // |steps_per_window_| = 3, because each window is the length of 3 steps.
     base::TimeDelta step_expected_queueing_time_;
     RunningAverage sliding_window_;
-
-    // Variables to split Expected Queueing Time by frame type.
-    std::array<base::TimeDelta, static_cast<int>(FrameStatus::kCount)>
-        eqt_by_frame_status_;
-    FrameStatus current_frame_status_ = FrameStatus::kNone;
   };
 
   QueueingTimeEstimator(Client* client,
@@ -110,7 +100,7 @@
                         int steps_per_window,
                         bool start_disabled);
 
-  void OnExecutionStarted(base::TimeTicks now, MainThreadTaskQueue* queue);
+  void OnExecutionStarted(base::TimeTicks now);
   void OnExecutionStopped(base::TimeTicks now);
   void OnRecordingStateChanged(bool disabled, base::TimeTicks transition_time);
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator_unittest.cc
index 2706ac2..5c7b0475 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator_unittest.cc
@@ -14,7 +14,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/page/launching_process_state.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.h"
 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
 
@@ -52,19 +51,6 @@
     EXPECT_EQ(total, sum);
   }
 
-  void TestSplitSumsTotal(base::TimeDelta* expected_sums, int num_windows) {
-    for (int window = 1; window < num_windows; ++window) {
-      base::TimeDelta sum;
-      // Add up the reported split EQTs for that window.
-      for (const auto& entry : client.split_eqts())
-        sum += entry.second[window - 1];
-      // Compare the split sum and the reported EQT for the disjoint window.
-      EXPECT_EQ(expected_sums[window - 1], sum);
-      EXPECT_EQ(expected_sums[window - 1],
-                client.expected_queueing_times()[5 * window - 1]);
-    }
-  }
-
   HistogramTester histogram_tester;
   base::TimeTicks time;
   TestQueueingTimeEstimatorClient client;
@@ -80,14 +66,14 @@
   QueueingTimeEstimatorForTest estimator(
       &client, base::TimeDelta::FromSeconds(5), 1, time);
   for (int i = 0; i < 3; ++i) {
-    estimator.OnExecutionStarted(time, nullptr);
+    estimator.OnExecutionStarted(time);
     time += base::TimeDelta::FromMilliseconds(1000);
     estimator.OnExecutionStopped(time);
   }
 
   // Flush the data by adding a task in the next window.
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(500);
   estimator.OnExecutionStopped(time);
 
@@ -111,18 +97,18 @@
   QueueingTimeEstimatorForTest estimator(
       &client, base::TimeDelta::FromSeconds(5), 1, time);
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(3000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(20000);
   estimator.OnExecutionStopped(time);
 
   // Flush the data by adding a task in the next window.
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(500);
   estimator.OnExecutionStopped(time);
 
@@ -150,37 +136,37 @@
       &client, base::TimeDelta::FromSeconds(5), 1, time);
   time += base::TimeDelta::FromMilliseconds(5000);
   // Start with a 1 second task.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
   time += base::TimeDelta::FromMilliseconds(4000);
 
   // Now perform an invalid task. This will cause the windows involving this
   // task to be ignored.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(35000);
   estimator.OnExecutionStopped(time);
 
   // Perform another 1 second task.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
 
   // Add a task in the next window.
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(500);
   estimator.OnExecutionStopped(time);
 
   // Now perform another invalid task. This will cause the windows involving
   // this task to be ignored. Therefore, the previous task is ignored.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(35000);
   estimator.OnExecutionStopped(time);
 
   // Flush by adding a task.
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   EXPECT_THAT(client.expected_queueing_times(),
@@ -200,12 +186,12 @@
       &client, base::TimeDelta::FromSeconds(5), 1, time);
   time += base::TimeDelta::FromMilliseconds(5000);
   // Start with a 1 second task.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
   time += base::TimeDelta::FromMilliseconds(4000);
   // Dummy task to ensure this window is reported.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   // Now go idle for long. This will cause the windows involving this
@@ -213,13 +199,13 @@
   time += base::TimeDelta::FromMilliseconds(35000);
 
   // Perform another 1 second task.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
 
   // Add a task in the next window.
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(500);
   estimator.OnExecutionStopped(time);
 
@@ -229,7 +215,7 @@
 
   // Flush by adding a task.
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   EXPECT_THAT(client.expected_queueing_times(),
@@ -260,13 +246,13 @@
       &client, base::TimeDelta::FromSeconds(5), 5, time);
   time += base::TimeDelta::FromMilliseconds(1000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(5000);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(6000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   std::vector<base::TimeDelta> expected_durations = {
@@ -306,19 +292,19 @@
       &client, base::TimeDelta::FromSeconds(5), 5, time);
   time += base::TimeDelta::FromMilliseconds(1000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(2500);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(500);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(6000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   std::vector<base::TimeDelta> expected_durations = {
@@ -359,22 +345,22 @@
   QueueingTimeEstimatorForTest estimator(
       &client, base::TimeDelta::FromSeconds(5), 5, time);
   time += base::TimeDelta::FromMilliseconds(1000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(4000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(2500);
   estimator.OnExecutionStopped(time);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(6000);
 
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   std::vector<base::TimeDelta> expected_durations = {
@@ -409,13 +395,13 @@
   QueueingTimeEstimatorForTest estimator(
       &client, base::TimeDelta::FromSeconds(1), 1, time);
   time += base::TimeDelta::FromMilliseconds(1000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
   time += base::TimeDelta::FromMilliseconds(1001);
 
   // Second window should not be reported.
   estimator.OnRecordingStateChanged(true, time);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(456);
   estimator.OnExecutionStopped(time);
   time += base::TimeDelta::FromMilliseconds(200);
@@ -423,19 +409,19 @@
   time += base::TimeDelta::FromMilliseconds(343);
 
   // Third, fourth windows should be reported
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1500);
   estimator.OnExecutionStopped(time);
   time += base::TimeDelta::FromMilliseconds(501);
 
   // Fifth, sixth task should not be reported
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(800);
   estimator.OnExecutionStopped(time);
   estimator.OnRecordingStateChanged(true, time);
   time += base::TimeDelta::FromMilliseconds(200);
   estimator.OnRecordingStateChanged(false, time);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(999);
 
   // Seventh task should be reported.
@@ -443,7 +429,7 @@
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(1000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   EXPECT_THAT(client.expected_queueing_times(),
@@ -482,23 +468,23 @@
   QueueingTimeEstimatorForTest estimator(
       &client, base::TimeDelta::FromSeconds(5), 5, time);
   time += base::TimeDelta::FromMilliseconds(5000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(500);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(500);
   estimator.OnExecutionStopped(time);
 
   estimator.OnRecordingStateChanged(true, time);
   // This task should be ignored.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(800);
   estimator.OnExecutionStopped(time);
   estimator.OnRecordingStateChanged(false, time);
 
   time += base::TimeDelta::FromMilliseconds(400);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1000);
   estimator.OnExecutionStopped(time);
 
@@ -506,28 +492,28 @@
   estimator.OnRecordingStateChanged(true, time);
   time += base::TimeDelta::FromMilliseconds(2000);
   // These tasks should be ignored.
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(2000);
   estimator.OnExecutionStopped(time);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(3400);
   estimator.OnExecutionStopped(time);
   estimator.OnRecordingStateChanged(false, time);
 
   time += base::TimeDelta::FromMilliseconds(2000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(1500);
   estimator.OnExecutionStopped(time);
 
   time += base::TimeDelta::FromMilliseconds(800);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   time += base::TimeDelta::FromMilliseconds(2500);
   estimator.OnExecutionStopped(time);
 
   // Window with last step should not be reported.
   estimator.OnRecordingStateChanged(true, time);
   time += base::TimeDelta::FromMilliseconds(1000);
-  estimator.OnExecutionStarted(time, nullptr);
+  estimator.OnExecutionStarted(time);
   estimator.OnExecutionStopped(time);
 
   EXPECT_THAT(client.expected_queueing_times(),
@@ -541,271 +527,5 @@
                                    base::TimeDelta::FromMilliseconds(801)));
 }
 
-// Split ExpectedQueueingTime only reports once per disjoint window. The
-// following is a detailed explanation of EQT per window and frame type:
-// Window 1: A 3000ms task in a background main frame contributes 900 to that
-// EQT.
-// Window 2: Two 2000ms tasks in a visible main frame: 400 each, total 800
-// EQT.
-// Window 3: 3000ms task in a visible main frame: 900 EQT for that type. Also,
-// the first 2000ms from a 3000ms task in a background main frame: 800 EQT for
-// that.
-// Window 4: The remaining 100 EQT for background main frame. Also 1000ms
-// tasks (which contribute 100) for kSameOriginVisible, kSameOriginHidden,
-// and kCrossOriginVisible.
-// Window 5: 400 ms tasks (which contribute 16) for each of the buckets except
-// other. Two 300 ms (each contributing 9) and one 800 ms tasks (contributes
-// 64) for the other bucket.
-TEST_F(QueueingTimeEstimatorTest, SplitEQTByFrameStatus) {
-  QueueingTimeEstimatorForTest estimator(
-      &client, base::TimeDelta::FromSeconds(5), 5, time);
-  time += base::TimeDelta::FromMilliseconds(5000);
-  // Dummy task to initialize the estimator.
-  estimator.OnExecutionStarted(time, nullptr);
-  estimator.OnExecutionStopped(time);
-  scoped_refptr<MainThreadTaskQueueForTest> queue1(
-      new MainThreadTaskQueueForTest(MainThreadTaskQueue::QueueType::kTest));
-
-  // Beginning of window 1.
-  time += base::TimeDelta::FromMilliseconds(500);
-  // Scheduler with frame type: MAIN_FRAME_BACKGROUND.
-  std::unique_ptr<FakeFrameScheduler> frame1 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kMainFrame)
-          .Build();
-  queue1->SetFrameSchedulerForTest(frame1.get());
-  estimator.OnExecutionStarted(time, queue1.get());
-  time += base::TimeDelta::FromMilliseconds(3000);
-  estimator.OnExecutionStopped(time);
-
-  time += base::TimeDelta::FromMilliseconds(1500);
-  // Beginning of window 2.
-  // Scheduler with frame type: MAIN_FRAME_VISIBLE.
-  std::unique_ptr<FakeFrameScheduler> frame2 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kMainFrame)
-          .SetIsPageVisible(true)
-          .SetIsFrameVisible(true)
-          .Build();
-  queue1->SetFrameSchedulerForTest(frame2.get());
-  estimator.OnExecutionStarted(time, queue1.get());
-  time += base::TimeDelta::FromMilliseconds(2000);
-  estimator.OnExecutionStopped(time);
-
-  scoped_refptr<MainThreadTaskQueueForTest> queue2(
-      new MainThreadTaskQueueForTest(MainThreadTaskQueue::QueueType::kTest));
-  queue2->SetFrameSchedulerForTest(frame2.get());
-  time += base::TimeDelta::FromMilliseconds(1000);
-  estimator.OnExecutionStarted(time, queue2.get());
-  time += base::TimeDelta::FromMilliseconds(2000);
-  estimator.OnExecutionStopped(time);
-
-  // Beginning of window 3.
-  // Scheduler with frame type: MAIN_FRAME_VISIBLE.
-  std::unique_ptr<FakeFrameScheduler> frame3 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kMainFrame)
-          .SetIsPageVisible(true)
-          .SetIsFrameVisible(true)
-          .SetIsExemptFromThrottling(true)
-          .Build();
-  queue1->SetFrameSchedulerForTest(frame3.get());
-  estimator.OnExecutionStarted(time, queue1.get());
-  time += base::TimeDelta::FromMilliseconds(3000);
-  estimator.OnExecutionStopped(time);
-
-  // Scheduler with frame type: MAIN_FRAME_BACKGROUND.
-  std::unique_ptr<FakeFrameScheduler> frame4 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kMainFrame)
-          .SetIsFrameVisible(true)
-          .SetIsExemptFromThrottling(true)
-          .Build();
-  queue1->SetFrameSchedulerForTest(frame4.get());
-  estimator.OnExecutionStarted(time, queue1.get());
-  time += base::TimeDelta::FromMilliseconds(3000);
-  // 1000 ms after beginning of window 4.
-  estimator.OnExecutionStopped(time);
-
-  time += base::TimeDelta::FromMilliseconds(1000);
-  // Scheduler with frame type: SAME_ORIGIN_VISIBLE.
-  std::unique_ptr<FakeFrameScheduler> frame5 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kSubframe)
-          .SetIsPageVisible(true)
-          .SetIsFrameVisible(true)
-          .Build();
-  // Scheduler with frame type: SAME_ORIGIN_HIDDEN.
-  std::unique_ptr<FakeFrameScheduler> frame6 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kSubframe)
-          .SetIsPageVisible(true)
-          .Build();
-  // Scheduler with frame type: CROSS_ORIGIN_VISIBLE.
-  std::unique_ptr<FakeFrameScheduler> frame7 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kSubframe)
-          .SetIsPageVisible(true)
-          .SetIsFrameVisible(true)
-          .SetIsCrossOrigin(true)
-          .Build();
-  FakeFrameScheduler* schedulers_for_thousand[] = {frame5.get(), frame6.get(),
-                                                   frame7.get()};
-  for (auto* scheduler : schedulers_for_thousand) {
-    queue1->SetFrameSchedulerForTest(scheduler);
-    estimator.OnExecutionStarted(time, queue1.get());
-    time += base::TimeDelta::FromMilliseconds(1000);
-    estimator.OnExecutionStopped(time);
-  }
-
-  // Beginning of window 5.
-  // Scheduler with frame type: MAIN_FRAME_HIDDEN.
-  std::unique_ptr<FakeFrameScheduler> frame8 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kMainFrame)
-          .SetIsPageVisible(true)
-          .Build();
-  // Scheduler with frame type: SAME_ORIGIN_BACKGROUND.
-  std::unique_ptr<FakeFrameScheduler> frame9 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kSubframe)
-          .Build();
-  // Scheduler with frame type: CROSS_ORIGIN_HIDDEN.
-  std::unique_ptr<FakeFrameScheduler> frame10 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kSubframe)
-          .SetIsPageVisible(true)
-          .SetIsCrossOrigin(true)
-          .Build();
-  // Scheduler with frame type: CROSS_ORIGIN_BACKGROUND.
-  std::unique_ptr<FakeFrameScheduler> frame11 =
-      FakeFrameScheduler::Builder()
-          .SetFrameType(FrameScheduler::FrameType::kSubframe)
-          .SetIsCrossOrigin(true)
-          .Build();
-  // One scheduler per supported frame type, excluding "Other".
-  FakeFrameScheduler* schedulers_for_four_hundred[] = {
-      frame2.get(), frame1.get(), frame8.get(),  frame5.get(), frame6.get(),
-      frame9.get(), frame7.get(), frame10.get(), frame11.get()};
-  for (auto* scheduler : schedulers_for_four_hundred) {
-    queue1->SetFrameSchedulerForTest(scheduler);
-    estimator.OnExecutionStarted(time, queue1.get());
-    time += base::TimeDelta::FromMilliseconds(400);
-    estimator.OnExecutionStopped(time);
-  }
-
-  // The following tasks contribute to "Other" because there is no frame.
-  estimator.OnExecutionStarted(time, nullptr);
-  time += base::TimeDelta::FromMilliseconds(300);
-  estimator.OnExecutionStopped(time);
-
-  queue1->DetachFromFrameScheduler();
-  estimator.OnExecutionStarted(time, queue1.get());
-  time += base::TimeDelta::FromMilliseconds(300);
-  estimator.OnExecutionStopped(time);
-
-  estimator.OnExecutionStarted(time, nullptr);
-  time += base::TimeDelta::FromMilliseconds(800);
-  estimator.OnExecutionStopped(time);
-
-  // End of window 5. Now check the vectors per frame type.
-  EXPECT_THAT(client.FrameStatusValues(FrameStatus::kMainFrameBackground),
-              testing::ElementsAre(base::TimeDelta::FromMilliseconds(900),
-                                   base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(800),
-                                   base::TimeDelta::FromMilliseconds(100),
-                                   base::TimeDelta::FromMilliseconds(16)));
-  std::vector<BucketExpectation> expected = {
-      {0, 1}, {16, 1}, {100, 1}, {800, 2}};
-  TestHistogram(
-      "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-      "MainFrameBackground",
-      5, GetFineGrained(expected));
-
-  EXPECT_THAT(client.FrameStatusValues(FrameStatus::kMainFrameVisible),
-              testing::ElementsAre(base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(800),
-                                   base::TimeDelta::FromMilliseconds(900),
-                                   base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(16)));
-  expected = {{0, 2}, {16, 1}, {800, 2}};
-  TestHistogram(
-      "RendererScheduler.ExpectedQueueingTimeByFrameStatus2.MainFrameVisible",
-      5, GetFineGrained(expected));
-
-  struct FrameExpectation {
-    FrameStatus frame_status;
-    std::string name;
-  };
-  FrameExpectation three_expected[] = {
-      {FrameStatus::kSameOriginVisible,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-       "SameOriginVisible"},
-      {FrameStatus::kSameOriginHidden,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2.SameOriginHidden"},
-      {FrameStatus::kCrossOriginVisible,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-       "CrossOriginVisible"},
-  };
-  for (const auto& frame_expectation : three_expected) {
-    EXPECT_THAT(client.FrameStatusValues(frame_expectation.frame_status),
-                testing::ElementsAre(base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(100),
-                                     base::TimeDelta::FromMilliseconds(16)));
-    expected = {{0, 3}, {16, 1}, {100, 1}};
-    TestHistogram(frame_expectation.name, 5, GetFineGrained(expected));
-  }
-
-  FrameExpectation more_expected[] = {
-      {FrameStatus::kMainFrameHidden,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-       "MainFrameHidden"},
-      {FrameStatus::kSameOriginBackground,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-       "SameOriginBackground"},
-      {FrameStatus::kCrossOriginHidden,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-       "CrossOriginHidden"},
-      {FrameStatus::kCrossOriginBackground,
-       "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-       "CrossOriginBackground"}};
-  for (const auto& frame_expectation : more_expected) {
-    EXPECT_THAT(client.FrameStatusValues(frame_expectation.frame_status),
-                testing::ElementsAre(base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(0),
-                                     base::TimeDelta::FromMilliseconds(16)));
-    expected = {{0, 4}, {16, 1}};
-    TestHistogram(frame_expectation.name, 5, GetFineGrained(expected));
-  }
-
-  EXPECT_THAT(client.FrameStatusValues(FrameStatus::kNone),
-              testing::ElementsAre(base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(0),
-                                   base::TimeDelta::FromMilliseconds(82)));
-  expected = {{0, 4}, {82, 1}};
-  TestHistogram("RendererScheduler.ExpectedQueueingTimeByFrameStatus2.Other", 5,
-                GetFineGrained(expected));
-
-  expected = {{226, 1}, {400, 1}, {800, 1}, {900, 1}, {1700, 1}};
-  std::vector<BucketExpectation> fine_grained = {
-      {226 * 1000, 1}, {400 * 1000, 1}, {800 * 1000, 2}, {1700 * 1000, 1}};
-  TestHistogram("RendererScheduler.ExpectedTaskQueueingDuration", 5, expected);
-  TestHistogram("RendererScheduler.ExpectedTaskQueueingDuration3", 5,
-                fine_grained);
-  // Check that the sum of split EQT equals the total EQT for each window.
-  base::TimeDelta expected_sums[] = {base::TimeDelta::FromMilliseconds(900),
-                                     base::TimeDelta::FromMilliseconds(800),
-                                     base::TimeDelta::FromMilliseconds(1700),
-                                     base::TimeDelta::FromMilliseconds(400),
-                                     base::TimeDelta::FromMilliseconds(226)};
-  TestSplitSumsTotal(expected_sums, 6);
-}
-
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
index 94c1c1ca..f9eeaa4 100644
--- a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
@@ -10,6 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/public/scheduling_lifecycle_state.h"
+#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
@@ -47,22 +48,49 @@
     DISALLOW_COPY_AND_ASSIGN(LifecycleObserverHandle);
   };
 
-  virtual ~FrameOrWorkerScheduler();
-
-  class ActiveConnectionHandle {
+  // RAII handle which should be kept alive as long as the feature is active
+  // and the policy should be applied.
+  class PLATFORM_EXPORT SchedulingAffectingFeatureHandle {
    public:
-    ActiveConnectionHandle() = default;
-    virtual ~ActiveConnectionHandle() = default;
+    SchedulingAffectingFeatureHandle() = default;
+    SchedulingAffectingFeatureHandle(SchedulingAffectingFeatureHandle&&);
+    inline ~SchedulingAffectingFeatureHandle() { reset(); }
+
+    SchedulingAffectingFeatureHandle& operator=(
+        SchedulingAffectingFeatureHandle&&);
+
+    inline void reset() {
+      if (scheduler_)
+        scheduler_->OnStoppedUsingFeature(feature_, policy_);
+      scheduler_ = nullptr;
+    }
 
    private:
-    DISALLOW_COPY_AND_ASSIGN(ActiveConnectionHandle);
+    friend class FrameOrWorkerScheduler;
+
+    SchedulingAffectingFeatureHandle(SchedulingPolicy::Feature feature,
+                                     SchedulingPolicy policy,
+                                     base::WeakPtr<FrameOrWorkerScheduler>);
+
+    SchedulingPolicy::Feature feature_ = SchedulingPolicy::Feature::kCount;
+    SchedulingPolicy policy_;
+    base::WeakPtr<FrameOrWorkerScheduler> scheduler_;
+
+    DISALLOW_COPY_AND_ASSIGN(SchedulingAffectingFeatureHandle);
   };
 
-  // Notifies scheduler that this execution context has established an active
-  // real time connection (websocket, webrtc, etc). When connection is closed
-  // this handle must be destroyed.
-  virtual std::unique_ptr<ActiveConnectionHandle>
-  OnActiveConnectionCreated() = 0;
+  virtual ~FrameOrWorkerScheduler();
+
+  // Notifies scheduler that this execution context has started using a feature
+  // which impacts scheduling decisions.
+  // When the feature stops being used, this handle should be destroyed.
+  //
+  // Usage:
+  // handle = scheduler->RegisterFeature(
+  //     kYourFeature, { SchedulingPolicy::DisableSomething() });
+  SchedulingAffectingFeatureHandle RegisterFeature(
+      SchedulingPolicy::Feature feature,
+      SchedulingPolicy policy) WARN_UNUSED_RESULT;
 
   // Adds an Observer instance to be notified on scheduling policy changed.
   // When an Observer is added, the initial state will be notified synchronously
@@ -70,7 +98,8 @@
   // A RAII handle is returned and observer is unregistered when the handle is
   // destroyed.
   std::unique_ptr<LifecycleObserverHandle> AddLifecycleObserver(ObserverType,
-                                                                Observer*);
+                                                                Observer*)
+      WARN_UNUSED_RESULT;
 
   virtual FrameScheduler* ToFrameScheduler() { return nullptr; }
 
@@ -84,6 +113,11 @@
     return scheduler::SchedulingLifecycleState::kNotThrottled;
   }
 
+  virtual void OnStartedUsingFeature(SchedulingPolicy::Feature feature,
+                                     const SchedulingPolicy& policy) = 0;
+  virtual void OnStoppedUsingFeature(SchedulingPolicy::Feature feature,
+                                     const SchedulingPolicy& policy) = 0;
+
   base::WeakPtr<FrameOrWorkerScheduler> GetWeakPtr();
 
  private:
diff --git a/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h b/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h
new file mode 100644
index 0000000..b2ed405a
--- /dev/null
+++ b/third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h
@@ -0,0 +1,48 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_SCHEDULING_POLICY_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_SCHEDULING_POLICY_H_
+
+#include "base/traits_bag.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+// A list of things a feature can opt out from on the behalf of the page
+// if the page is using this feature.
+// See FrameOrWorkerScheduler::RegisterFeature.
+struct PLATFORM_EXPORT SchedulingPolicy {
+  // List of features which can trigger the policy changes.
+  enum class Feature {
+    kWebSocket = 0,
+    kWebRTC = 1,
+
+    kCount = 2
+  };
+
+  // List of opt-outs which form a policy.
+  struct DisableAggressiveThrottling {};
+
+  struct ValidPolicies {
+    ValidPolicies(DisableAggressiveThrottling);
+  };
+
+  template <class... ArgTypes,
+            class CheckArgumentsAreValid = std::enable_if_t<
+                base::trait_helpers::AreValidTraits<ValidPolicies,
+                                                    ArgTypes...>::value>>
+  constexpr SchedulingPolicy(ArgTypes... args)
+      : disable_aggressive_throttling(
+            base::trait_helpers::HasTrait<DisableAggressiveThrottling>(
+                args...)) {}
+
+  SchedulingPolicy() {}
+
+  bool disable_aggressive_throttling = false;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_SCHEDULING_POLICY_H_
diff --git a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
index 63ef7485..c41615b 100644
--- a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
@@ -44,8 +44,6 @@
 
   std::unique_ptr<PauseHandle> Pause() WARN_UNUSED_RESULT;
 
-  std::unique_ptr<ActiveConnectionHandle> OnActiveConnectionCreated() override;
-
   // Unregisters the task queues and cancels tasks in them.
   void Dispose();
 
@@ -63,6 +61,11 @@
 
   SchedulingLifecycleState CalculateLifecycleState(ObserverType) const override;
 
+  void OnStartedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override;
+  void OnStoppedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override;
+
  protected:
   scoped_refptr<NonMainThreadTaskQueue> ThrottleableTaskQueue();
   scoped_refptr<NonMainThreadTaskQueue> UnpausableTaskQueue();
diff --git a/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h
index b4ee855..eb6660b 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h
@@ -141,9 +141,10 @@
       bool is_web_history_inert_commit,
       FrameScheduler::NavigationType navigation_type) override {}
   void OnFirstMeaningfulPaint() override {}
-  std::unique_ptr<ActiveConnectionHandle> OnActiveConnectionCreated() override {
-    return nullptr;
-  }
+  void OnStartedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override {}
+  void OnStoppedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override {}
   bool IsExemptFromBudgetBasedThrottling() const override {
     return is_exempt_from_throttling_;
   }
diff --git a/third_party/blink/renderer/platform/scheduler/test/queueing_time_estimator_perf_test.cc b/third_party/blink/renderer/platform/scheduler/test/queueing_time_estimator_perf_test.cc
index 59a75ee..eed45db 100644
--- a/third_party/blink/renderer/platform/scheduler/test/queueing_time_estimator_perf_test.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/queueing_time_estimator_perf_test.cc
@@ -41,7 +41,7 @@
     time += base::TimeDelta::FromSeconds(1);
     timer_.Reset();
     do {
-      estimator.OnExecutionStarted(time, nullptr);
+      estimator.OnExecutionStarted(time);
       time += task_lengths[i];
       estimator.OnExecutionStopped(time);
       timer_.NextLap();
diff --git a/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc b/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc
index d2158d8..e68586c 100644
--- a/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc
@@ -81,15 +81,16 @@
   GetPauseSubresourceLoadingHandle() override {
     return nullptr;
   }
-  std::unique_ptr<ActiveConnectionHandle> OnActiveConnectionCreated() override {
-    return nullptr;
-  }
   std::unique_ptr<WebResourceLoadingTaskRunnerHandle>
   CreateResourceLoadingTaskRunnerHandle() override {
     return WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
         base::ThreadTaskRunnerHandle::Get());
   }
   ukm::SourceId GetUkmSourceId() override { return ukm::kInvalidSourceId; }
+  void OnStartedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override {}
+  void OnStoppedUsingFeature(SchedulingPolicy::Feature feature,
+                             const SchedulingPolicy& policy) override {}
 
  private:
   PageScheduler* page_scheduler_;
diff --git a/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.cc b/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.cc
index 22489f2..5bfcc65 100644
--- a/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.cc
@@ -13,53 +13,6 @@
 namespace blink {
 namespace scheduler {
 
-// This is a duplicate of the defines in queueing_time_estimator.cc.
-#define FRAME_STATUS_PREFIX \
-  "RendererScheduler.ExpectedQueueingTimeByFrameStatus2."
-
-const char* GetReportingMessageFromFrameStatus(FrameStatus frame_status) {
-  switch (frame_status) {
-    case FrameStatus::kMainFrameVisible:
-    case FrameStatus::kMainFrameVisibleService:
-      return FRAME_STATUS_PREFIX "MainFrameVisible";
-    case FrameStatus::kMainFrameHidden:
-    case FrameStatus::kMainFrameHiddenService:
-      return FRAME_STATUS_PREFIX "MainFrameHidden";
-    case FrameStatus::kMainFrameBackground:
-    case FrameStatus::kMainFrameBackgroundExemptSelf:
-    case FrameStatus::kMainFrameBackgroundExemptOther:
-      return FRAME_STATUS_PREFIX "MainFrameBackground";
-    case FrameStatus::kSameOriginVisible:
-    case FrameStatus::kSameOriginVisibleService:
-      return FRAME_STATUS_PREFIX "SameOriginVisible";
-    case FrameStatus::kSameOriginHidden:
-    case FrameStatus::kSameOriginHiddenService:
-      return FRAME_STATUS_PREFIX "SameOriginHidden";
-    case FrameStatus::kSameOriginBackground:
-    case FrameStatus::kSameOriginBackgroundExemptSelf:
-    case FrameStatus::kSameOriginBackgroundExemptOther:
-      return FRAME_STATUS_PREFIX "SameOriginBackground";
-    case FrameStatus::kCrossOriginVisible:
-    case FrameStatus::kCrossOriginVisibleService:
-      return FRAME_STATUS_PREFIX "CrossOriginVisible";
-    case FrameStatus::kCrossOriginHidden:
-    case FrameStatus::kCrossOriginHiddenService:
-      return FRAME_STATUS_PREFIX "CrossOriginHidden";
-    case FrameStatus::kCrossOriginBackground:
-    case FrameStatus::kCrossOriginBackgroundExemptSelf:
-    case FrameStatus::kCrossOriginBackgroundExemptOther:
-      return FRAME_STATUS_PREFIX "CrossOriginBackground";
-    case FrameStatus::kNone:
-    case FrameStatus::kDetached:
-      return FRAME_STATUS_PREFIX "Other";
-    case FrameStatus::kCount:
-      NOTREACHED();
-      return "";
-  }
-  NOTREACHED();
-  return "";
-}
-
 void TestQueueingTimeEstimatorClient::OnQueueingTimeForWindowEstimated(
     base::TimeDelta queueing_time,
     bool is_disjoint_window) {
@@ -78,27 +31,6 @@
   }
 }
 
-void TestQueueingTimeEstimatorClient::OnReportFineGrainedExpectedQueueingTime(
-    const char* split_description,
-    base::TimeDelta queueing_time) {
-  if (split_eqts_.find(split_description) == split_eqts_.end())
-    split_eqts_[split_description] = std::vector<base::TimeDelta>();
-  split_eqts_[split_description].push_back(queueing_time);
-  // Mimic MainThreadSchedulerImpl::OnReportFineGrainedExpectedQueueingTime.
-  base::UmaHistogramCustomCounts(
-      split_description,
-      base::saturated_cast<base::HistogramBase::Sample>(
-          queueing_time.InMicroseconds()),
-      MainThreadSchedulerImpl::kMinExpectedQueueingTimeBucket,
-      MainThreadSchedulerImpl::kMaxExpectedQueueingTimeBucket,
-      MainThreadSchedulerImpl::kNumberExpectedQueueingTimeBuckets);
-}
-
-const std::vector<base::TimeDelta>&
-TestQueueingTimeEstimatorClient::FrameStatusValues(FrameStatus frame_status) {
-  return split_eqts_[GetReportingMessageFromFrameStatus(frame_status)];
-}
-
 QueueingTimeEstimatorForTest::QueueingTimeEstimatorForTest(
     TestQueueingTimeEstimatorClient* client,
     base::TimeDelta window_duration,
diff --git a/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.h b/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.h
index a37aa3d..1fc32d4 100644
--- a/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.h
+++ b/third_party/blink/renderer/platform/scheduler/test/test_queueing_time_estimator_client.h
@@ -18,22 +18,13 @@
   // QueueingTimeEstimator::Client implementation:
   void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time,
                                         bool is_disjoint_window) override;
-  void OnReportFineGrainedExpectedQueueingTime(
-      const char* split_description,
-      base::TimeDelta queueing_time) override;
 
   const std::vector<base::TimeDelta>& expected_queueing_times() {
     return expected_queueing_times_;
   }
-  const std::map<std::string, std::vector<base::TimeDelta>>& split_eqts() {
-    return split_eqts_;
-  }
-  const std::vector<base::TimeDelta>& FrameStatusValues(
-      FrameStatus frame_status);
 
  private:
   std::vector<base::TimeDelta> expected_queueing_times_;
-  std::map<std::string, std::vector<base::TimeDelta>> split_eqts_;
 };
 
 class QueueingTimeEstimatorForTest : public QueueingTimeEstimator {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
index ab90e8e..9cddec03 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
@@ -97,11 +97,6 @@
   }
 }
 
-std::unique_ptr<FrameOrWorkerScheduler::ActiveConnectionHandle>
-WorkerScheduler::OnActiveConnectionCreated() {
-  return nullptr;
-}
-
 SchedulingLifecycleState WorkerScheduler::CalculateLifecycleState(
     ObserverType) const {
   return thread_scheduler_->lifecycle_state();
@@ -232,5 +227,11 @@
   return throttleable_task_queue_.get();
 }
 
+void WorkerScheduler::OnStartedUsingFeature(SchedulingPolicy::Feature feature,
+                                            const SchedulingPolicy& policy) {}
+
+void WorkerScheduler::OnStoppedUsingFeature(SchedulingPolicy::Feature feature,
+                                            const SchedulingPolicy& policy) {}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index a0385d6..f8dfa2d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -407,6 +407,9 @@
 crbug.com/921105 virtual/disable-blink-gen-property-trees/animations/skew-notsequential-compositor.html [ Skip ]
 # Occasionally timeout, but the test coverage is still good
 crbug.com/919789 paint/invalidation/window-resize/ [ Timeout Pass ]
+# Extra raster invalidation on start/end of animation.
+crbug.com/942681 paint/invalidation/animation/opacity-animation.html [ Failure ]
+crbug.com/942681 paint/invalidation/animation/transform-animation.html [ Failure ]
 
 # ====== Paint team owned tests to here ======
 
@@ -5757,6 +5760,7 @@
 crbug.com/912821 [ Mac ] http/tests/devtools/tracing/user-timing.js [ Pass Failure ]
 crbug.com/912821 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/tracing/user-timing.js [ Pass Failure ]
 
+crbug.com/913170 compositing/layer-creation/fixed-position-in-fixed-overflow.html [ Crash Pass ]
 crbug.com/913173 fast/backgrounds/background-svg-scaling-zoom.html [ Failure Pass ]
 
 # Sheriff 2018-12-13
@@ -6031,7 +6035,7 @@
 crbug.com/934768 [ Mac ] http/tests/devtools/tracing/worker-events.js [ Failure Pass ]
 crbug.com/934768 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/tracing/worker-events.js [ Failure Pass ]
 crbug.com/934768 [ Mac ] virtual/threaded/http/tests/devtools/tracing/worker-events.js [ Failure Pass ]
-crbug.com/934818 [ Mac Debug ] virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Failure Pass ]
+crbug.com/934818 virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Failure Pass ]
 crbug.com/935027 http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Crash Pass ]
 crbug.com/935027 virtual/binary-for-devtools/http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Crash Pass ]
 
@@ -6048,7 +6052,6 @@
 # Sheriff 2019-02-26
 crbug.com/936083 external/wpt/import-maps/builtin-import-scheme.tentative.html [ Failure Pass ]
 crbug.com/936095 fast/css-intrinsic-dimensions/height-tables-collapsed.html [ Failure Pass ]
-crbug.com/934818 [ Linux ] virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Failure Pass ]
 crbug.com/936165 media/autoplay-muted.html [ Timeout Pass ]
 crbug.com/936165 virtual/video-surface-layer/media/autoplay-muted.html [ Timeout Pass ]
 crbug.com/936108 virtual/streams-native/http/tests/streams/transferable/readable-stream.html [ Failure Pass ]
@@ -6149,3 +6152,10 @@
 
 crbug.com/943095 external/wpt/fetch/stale-while-revalidate/fetch.tentative.html [ Pass Timeout ]
 crbug.com/943095 virtual/outofblink-cors/external/wpt/fetch/stale-while-revalidate/fetch.tentative.html [ Pass Timeout ]
+
+# Trooper 2019-03-19
+crbug.com/941482 [ Win ] virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations.html [ Pass Failure ]
+crbug.com/943390 [ Win ] http/tests/security/mixedContent/empty-url-plugin-in-frame.html [ Pass Failure ]
+crbug.com/943390 [ Win ] virtual/outofblink-cors/http/tests/security/mixedContent/empty-url-plugin-in-frame.html [ Pass Failure ]
+crbug.com/943388 [ Win ] http/tests/devtools/network/network-recording-after-reload-with-screenshots-enabled.js [ Pass Failure ]
+crbug.com/943388 [ Win ] virtual/binary-for-devtools/http/tests/devtools/network/network-recording-after-reload-with-screenshots-enabled.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_pointercancel_touch.html
similarity index 86%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_pointercancel_touch.html
index 70a65ee..a645033 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_pointercancel_touch.html
@@ -5,6 +5,9 @@
         <meta name="viewport" content="width=device-width">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <!-- Additional helper script for common checks across event types -->
         <script type="text/javascript" src="pointerevent_support.js"></script>
@@ -28,6 +31,7 @@
 
             var pointerdown_event = null;
             var pointercancel_event = null;
+            var received_pointerleave = false;
 
             function run() {
                 var target0 = document.getElementById("target0");
@@ -64,6 +68,14 @@
                         assert_equals(event.pointerType, pointerdown_event.pointerType, "pointerType should be the same for pointerleave and pointercancel");
                         assert_equals(event.isPrimary, pointerdown_event.isPrimary, "isPrimary should be the same for pointerleave and pointercancel");
                     });
+                    received_pointerleave = true;
+                });
+
+                // Inject touch inputs and wait for all the actions finish to end the test.
+                touchScrollInTarget(target0, 'down').then(function() {
+                    test_pointerEvent.step(function () {
+                        assert_true(received_pointerleave, "pointerleave should be received before the test finished");
+                    });
                     test_pointerEvent.done();
                 });
             }
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
index 5c35e016..e8c847b 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
@@ -252,3 +252,36 @@
 function checkPointerEventType(event) {
     assert_equals(event.pointerType, expectedPointerType, "pointerType should be the same as the requested device.");
 }
+
+function touchScrollInTarget(target, direction) {
+    var x_delta = 0;
+    var y_delta = 0;
+    if (direction == "down") {
+        x_delta = 0;
+        y_delta = -10;
+    } else if (direction == "up") {
+        x_delta = 0;
+        y_delta = 10;
+    } else if (direction == "right") {
+        x_delta = -10;
+        y_delta = 0;
+    } else if (direction == "left") {
+        x_delta = 10;
+        y_delta = 0;
+    } else {
+        throw("scroll direction '" + direction + "' is not expected, direction should be 'down', 'up', 'left' or 'right'");
+    }
+    return new test_driver.Actions()
+                   .addPointer("pointer1", "touch")
+                   .pointerMove(0, 0, {origin: target})
+                   .pointerDown()
+                   .pointerMove(x_delta, y_delta, {origin: target})
+                   .pointerMove(2 * x_delta, 2 * y_delta, {origin: target})
+                   .pointerMove(3 * x_delta, 3 * y_delta, {origin: target})
+                   .pointerMove(4 * x_delta, 4 * y_delta, {origin: target})
+                   .pointerMove(5 * x_delta, 5 * y_delta, {origin: target})
+                   .pointerMove(6 * x_delta, 6 * y_delta, {origin: target})
+                   .pause(100)
+                   .pointerUp()
+                   .send();
+}
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html
index 7280d040..6c93aec 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html
@@ -19,7 +19,7 @@
   caller.addTrack(track, stream);
   exchangeIceCandidates(caller, callee);
   await doSignalingHandshake(caller, callee);
-  await listenToIceConnected(t, caller);
+  await listenToIceConnected(caller);
 
   const report = await caller.getStats();
   let succeededPairFound = false;
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_pointercancel_touch-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_pointercancel_touch-manual-automation.js
deleted file mode 100644
index c46cb0a..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_pointercancel_touch-manual-automation.js
+++ /dev/null
@@ -1,7 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return touchScrollInTarget('#target0', 'down');
-}
-
-
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-keyboard-scrollers-search-origin-bug.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-keyboard-scrollers-search-origin-bug.html
new file mode 100644
index 0000000..0e2d962
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-keyboard-scrollers-search-origin-bug.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    margin: 5px;
+    margin-top: 400px;
+    border: 1px solid black;
+  }
+  span {
+    position: absolute;
+    left: 300px;
+    overflow: hidden;
+    width: 1px;
+    height: 1px;
+    clip: rect(1px 1px 1px 1px);
+  }
+</style>
+
+<div id="first" tabindex="0"></div>
+<a id="link" href="https://example.com">
+  <!-- Because this span comes first in DOM order, but is positioned to the
+  right of the text node below, some bounding box calculations return an empty
+  rect. Make spatial-navigation behaves correctly in this case. -->
+  <span>
+    Invisible Text
+  </span>
+  Visible Text
+</a>
+
+<div id="offscreen" tabindex="0"></div>
+
+<script>
+  test(function(t) {
+    assert_true(internals.runtimeFlags.keyboardFocusableScrollersEnabled);
+  }, "Make sure KeyboardFocusableScrollers is set.");
+
+  // This test checks that focusless mode allows entering focus into an element
+  // with the enter key and exiting it with the escape key.
+  const first = document.getElementById("first");
+  const link = document.getElementById("link");
+
+  snav.assertSnavEnabledAndTestable();
+
+  test(() => {
+    assert_equals(window.scrollY, 0, "Start at 0 scroll offset.")
+
+    // Move interest onto the link.
+    snav.triggerMove('Down');
+    snav.triggerMove('Down');
+
+    assert_equals(window.internals.interestedElement,
+                  link,
+                  "link should start off interested.");
+
+    // Move interest down from the link. Since the bottom div is offscreen, we
+    // should scroll down rather than moving interest. In particular, make sure
+    // interest doesn't move back to the upper box.
+    snav.triggerMove('Down');
+    assert_greater_than(window.scrollY, 0, "Start at 0 scroll offset.")
+    assert_not_equals(document.activeElement,
+                      first,
+                      "Interest must not move up.");
+  }, "Clipped anchor doesn't caused looped-navigation bug.");
+</script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-create-basics.html b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-create-basics.html
index e35cef1..e3e5220 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-create-basics.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-create-basics.html
@@ -3,7 +3,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-basics.html b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-basics.html
index 104d7b9..f50637c 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-basics.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-basics.html
@@ -3,7 +3,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-errors.html b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-errors.html
index dae4d01..9a3ae8a 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-errors.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-errors.html
@@ -2,7 +2,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-origins.html b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-origins.html
index f0bcc6c..f21ad60 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-origins.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-get-origins.html
@@ -3,7 +3,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-preventsilentaccess-basics.html b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-preventsilentaccess-basics.html
index 3baccabe..2f185fb 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-preventsilentaccess-basics.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-preventsilentaccess-basics.html
@@ -3,7 +3,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-store-basics.html b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-store-basics.html
index dfd0da1..15e07fc1 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-store-basics.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/credentialscontainer-store-basics.html
@@ -3,7 +3,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/credentialmanager/mock-authenticator.html b/third_party/blink/web_tests/http/tests/credentialmanager/mock-authenticator.html
index cf30545..57f6445 100644
--- a/third_party/blink/web_tests/http/tests/credentialmanager/mock-authenticator.html
+++ b/third_party/blink/web_tests/http/tests/credentialmanager/mock-authenticator.html
@@ -2,7 +2,7 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom.js"></script>
+<script src="/gen/third_party/blink/public/mojom/credentialmanager/credential_manager.mojom.js"></script>
 <script src="/gen/third_party/blink/public/platform/modules/webauthn/authenticator.mojom.js"></script>
 <script src="resources/test-inputs.js"></script>
 <script src="resources/mock-navigator-credentials.js"></script>
diff --git a/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation-expected.html b/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation-expected.html
new file mode 100644
index 0000000..b351f67
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background: gray; will-change: opacity; opacity: 0.5"></div>
diff --git a/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation-expected.txt b/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation-expected.txt
new file mode 100644
index 0000000..e96a999c
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation-expected.txt
@@ -0,0 +1,30 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='target'",
+      "position": [8, 8],
+      "bounds": [100, 100],
+      "opacity": 0.5,
+      "contentsOpaque": true,
+      "backgroundColor": "#808080"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation.html b/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation.html
new file mode 100644
index 0000000..b768924
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/animation/opacity-animation.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="../resources/text-based-repaint.js"></script>
+<div id="target" style="width: 100px; height: 100px; background: gray;
+                        will-change: opacity; transition: 0.2s">
+</div>
+<script>
+window.testIsAsync = true;
+function repaintTest() {
+  target.addEventListener('transitionend', finishRepaintTest);
+  target.style.opacity = 0.5;
+}
+onload = runRepaintAndPixelTest;
+</script>
diff --git a/third_party/blink/web_tests/paint/invalidation/animation/transform-animation-expected.html b/third_party/blink/web_tests/paint/invalidation/animation/transform-animation-expected.html
new file mode 100644
index 0000000..3631cdd3
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/animation/transform-animation-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background: gray; transform: translateX(100px)"></div>
diff --git a/third_party/blink/web_tests/paint/invalidation/animation/transform-animation-expected.txt b/third_party/blink/web_tests/paint/invalidation/animation/transform-animation-expected.txt
new file mode 100644
index 0000000..df740aa
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/animation/transform-animation-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='target'",
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "backgroundColor": "#808080",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [100, 0, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/animation/transform-animation.html b/third_party/blink/web_tests/paint/invalidation/animation/transform-animation.html
new file mode 100644
index 0000000..0ed11eb2
--- /dev/null
+++ b/third_party/blink/web_tests/paint/invalidation/animation/transform-animation.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script src="../resources/text-based-repaint.js"></script>
+<div id="target" style="width: 100px; height: 100px; background: gray;
+                        will-change: transform; transition: 0.2s">
+</div>
+<script>
+window.testIsAsync = true;
+function repaintTest() {
+  target.addEventListener('transitionend', finishRepaintTest);
+  target.style.transform = 'translateX(100px)';
+}
+onload = runRepaintAndPixelTest;
+</script>
diff --git a/third_party/custom_tabs_client/OWNERS b/third_party/custom_tabs_client/OWNERS
index 51bc468..f728cfa 100644
--- a/third_party/custom_tabs_client/OWNERS
+++ b/third_party/custom_tabs_client/OWNERS
@@ -1,5 +1,4 @@
 lizeb@chromium.org
-pasko@chromium.org
 peconn@chromium.org
 yusufo@chromium.org
 
diff --git a/third_party/custom_tabs_client/README.chromium b/third_party/custom_tabs_client/README.chromium
index fac3ac3..95d433cc 100644
--- a/third_party/custom_tabs_client/README.chromium
+++ b/third_party/custom_tabs_client/README.chromium
@@ -16,4 +16,4 @@
 The example applicaton also presents how to use Browser Actions, including
 creating request intent and adding custom items.
 
-Local Modifications: none
+Local Modifications: None
diff --git a/third_party/googletest/README.chromium b/third_party/googletest/README.chromium
index 4e785d9..19b0ed7 100644
--- a/third_party/googletest/README.chromium
+++ b/third_party/googletest/README.chromium
@@ -1,7 +1,7 @@
 Name: Google Test: Google's C++ Testing Framework
 Short Name: googletest
 URL: https://github.com/google/googletest.git
-Version: 1.8.0.git-efecb0bfa687cf87836494f5d62868485c00fb66
+Version: 8b6d3f9c4a774bef3081195d422993323b6bb2e0
 License: BSD
 License File: NOT_SHIPPED
 Security critical: no
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index bf22f7b..5c4ffa0 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -429,3 +429,73 @@
     }
   }
 }
+
+# Convert a protocol buffer between text and binary formats.
+# This can be used to run protoc with the --encode or --decode options.
+# Parameters:
+#
+#   sources: list of string
+#       The sources to loop over and run protoc on
+#
+#   inputs: list of string
+#       The file dependencies for the action. This should be the list of .proto
+#       files involved in the conversion operation.
+#
+#   output_pattern: string
+#       A path pattern with source expansion variables (like source_name_part)
+#       for where the result of conversion should be placed.
+#
+#   deps: (optional) list of label
+#       Additional dependencies for the target.
+#
+#   args: list of string
+#       Arguments to pass to the protoc tool. This could include -I for include
+#       paths, as well as the name of the proto file.
+#
+#
+# Example to convert a .textproto to a .binarybp:
+#   protoc_convert("convert_foo") {
+#     sources = [
+#       "test/data/example1.textproto",
+#       "test/data/example2.textproto",
+#     ]
+#     inputs = [
+#       "//component/core/foo.proto",
+#     ]
+#     output_pattern = "$target_gen_dir/foo_data/{{source_name_part}}.binarypb"
+#     args = [
+#       "--encode=foo.FooMessage",
+#       "-I",
+#       rebase_path("//component/core"),
+#       "foo.proto",
+#     ]
+#   }
+template("protoc_convert") {
+  action_foreach(target_name) {
+    script = "//tools/protoc_wrapper/protoc_convert.py"
+
+    sources = invoker.sources
+
+    inputs = invoker.inputs
+
+    deps = [
+      "//third_party/protobuf:protoc",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
+    outputs = [
+      invoker.output_pattern,
+    ]
+
+    args = [
+             "--protoc",
+             rebase_path("$root_out_dir/protoc"),
+             "--infile",
+             "{{source}}",
+             "--outfile",
+             rebase_path(invoker.output_pattern),
+           ] + invoker.args
+  }
+}
diff --git a/third_party/sqlite/amalgamation/rename_exports.h b/third_party/sqlite/amalgamation/rename_exports.h
index 904ac258..7bcad0f0 100644
--- a/third_party/sqlite/amalgamation/rename_exports.h
+++ b/third_party/sqlite/amalgamation/rename_exports.h
@@ -106,7 +106,7 @@
   chrome_sqlite3_create_window_function                       // Lines 4868-4879
 #define sqlite3_data_count chrome_sqlite3_data_count          // Line 4418
 #define sqlite3_data_directory chrome_sqlite3_data_directory  // Line 5712
-#define sqlite3_db_cacheflush chrome_sqlite3_db_cacheflush    // Line 8941
+#define sqlite3_db_cacheflush chrome_sqlite3_db_cacheflush    // Line 8918
 #define sqlite3_db_config chrome_sqlite3_db_config            // Line 1569
 #define sqlite3_db_filename chrome_sqlite3_db_filename        // Line 5801
 #define sqlite3_db_handle chrome_sqlite3_db_handle            // Line 5784
@@ -115,7 +115,7 @@
 #define sqlite3_db_release_memory chrome_sqlite3_db_release_memory  // Line 5999
 #define sqlite3_db_status chrome_sqlite3_db_status                  // Line 7606
 #define sqlite3_declare_vtab chrome_sqlite3_declare_vtab            // Line 6610
-#define sqlite3_deserialize chrome_sqlite3_deserialize  // Lines 9335-9342
+#define sqlite3_deserialize chrome_sqlite3_deserialize  // Lines 9312-9319
 #define sqlite3_enable_load_extension \
   chrome_sqlite3_enable_load_extension  // Line 6223
 #define sqlite3_enable_shared_cache \
@@ -150,7 +150,7 @@
 #define sqlite3_libversion_number chrome_sqlite3_libversion_number  // Line 165
 #define sqlite3_limit chrome_sqlite3_limit                          // Line 3564
 #define sqlite3_load_extension chrome_sqlite3_load_extension  // Lines 6191-6196
-#define sqlite3_log chrome_sqlite3_log                        // Line 8477
+#define sqlite3_log chrome_sqlite3_log                        // Line 8454
 #define sqlite3_malloc chrome_sqlite3_malloc                  // Line 2767
 #define sqlite3_malloc64 chrome_sqlite3_malloc64              // Line 2768
 #define sqlite3_memory_alarm chrome_sqlite3_memory_alarm      // Lines 4920-4921
@@ -179,11 +179,11 @@
 #define sqlite3_prepare16_v3 chrome_sqlite3_prepare16_v3  // Lines 3810-3817
 #define sqlite3_prepare_v2 chrome_sqlite3_prepare_v2      // Lines 3781-3787
 #define sqlite3_prepare_v3 chrome_sqlite3_prepare_v3      // Lines 3788-3795
-#define sqlite3_preupdate_count chrome_sqlite3_preupdate_count  // Line 9040
-#define sqlite3_preupdate_depth chrome_sqlite3_preupdate_depth  // Line 9041
-#define sqlite3_preupdate_hook chrome_sqlite3_preupdate_hook  // Lines 9026-9038
-#define sqlite3_preupdate_new chrome_sqlite3_preupdate_new    // Line 9042
-#define sqlite3_preupdate_old chrome_sqlite3_preupdate_old    // Line 9039
+#define sqlite3_preupdate_count chrome_sqlite3_preupdate_count  // Line 9017
+#define sqlite3_preupdate_depth chrome_sqlite3_preupdate_depth  // Line 9018
+#define sqlite3_preupdate_hook chrome_sqlite3_preupdate_hook  // Lines 9003-9015
+#define sqlite3_preupdate_new chrome_sqlite3_preupdate_new    // Line 9019
+#define sqlite3_preupdate_old chrome_sqlite3_preupdate_old    // Line 9016
 #define sqlite3_profile chrome_sqlite3_profile                // Lines 3022-3023
 #define sqlite3_progress_handler chrome_sqlite3_progress_handler  // Line 3150
 #define sqlite3_randomness chrome_sqlite3_randomness              // Line 2821
@@ -220,21 +220,21 @@
 #define sqlite3_result_zeroblob64 chrome_sqlite3_result_zeroblob64  // Line 5387
 #define sqlite3_rollback_hook chrome_sqlite3_rollback_hook          // Line 5877
 #define sqlite3_rtree_geometry_callback \
-  chrome_sqlite3_rtree_geometry_callback  // Lines 9422-9427
+  chrome_sqlite3_rtree_geometry_callback  // Lines 9399-9404
 #define sqlite3_rtree_query_callback \
-  chrome_sqlite3_rtree_query_callback                         // Lines 9448-9454
-#define sqlite3_serialize chrome_sqlite3_serialize            // Lines 9283-9288
+  chrome_sqlite3_rtree_query_callback                         // Lines 9425-9431
+#define sqlite3_serialize chrome_sqlite3_serialize            // Lines 9260-9265
 #define sqlite3_set_authorizer chrome_sqlite3_set_authorizer  // Lines 2912-2916
 #define sqlite3_set_auxdata chrome_sqlite3_set_auxdata        // Line 5219
 #define sqlite3_set_last_insert_rowid \
   chrome_sqlite3_set_last_insert_rowid                      // Line 2297
 #define sqlite3_shutdown chrome_sqlite3_shutdown            // Line 1515
 #define sqlite3_sleep chrome_sqlite3_sleep                  // Line 5617
-#define sqlite3_snapshot_cmp chrome_sqlite3_snapshot_cmp    // Lines 9217-9220
-#define sqlite3_snapshot_free chrome_sqlite3_snapshot_free  // Line 9190
-#define sqlite3_snapshot_get chrome_sqlite3_snapshot_get    // Lines 9124-9128
-#define sqlite3_snapshot_open chrome_sqlite3_snapshot_open  // Lines 9173-9177
-#define sqlite3_snapshot_recover chrome_sqlite3_snapshot_recover    // Line 9245
+#define sqlite3_snapshot_cmp chrome_sqlite3_snapshot_cmp    // Lines 9194-9197
+#define sqlite3_snapshot_free chrome_sqlite3_snapshot_free  // Line 9167
+#define sqlite3_snapshot_get chrome_sqlite3_snapshot_get    // Lines 9101-9105
+#define sqlite3_snapshot_open chrome_sqlite3_snapshot_open  // Lines 9150-9154
+#define sqlite3_snapshot_recover chrome_sqlite3_snapshot_recover    // Line 9222
 #define sqlite3_snprintf chrome_sqlite3_snprintf                    // Line 2676
 #define sqlite3_soft_heap_limit chrome_sqlite3_soft_heap_limit      // Line 6063
 #define sqlite3_soft_heap_limit64 chrome_sqlite3_soft_heap_limit64  // Line 6052
@@ -246,9 +246,9 @@
 #define sqlite3_stmt_busy chrome_sqlite3_stmt_busy          // Line 3916
 #define sqlite3_stmt_readonly chrome_sqlite3_stmt_readonly  // Line 3895
 #define sqlite3_stmt_scanstatus \
-  chrome_sqlite3_stmt_scanstatus  // Lines 8893-8898
+  chrome_sqlite3_stmt_scanstatus  // Lines 8870-8875
 #define sqlite3_stmt_scanstatus_reset \
-  chrome_sqlite3_stmt_scanstatus_reset                        // Line 8909
+  chrome_sqlite3_stmt_scanstatus_reset                        // Line 8886
 #define sqlite3_stmt_status chrome_sqlite3_stmt_status        // Line 7759
 #define sqlite3_str_append chrome_sqlite3_str_append          // Line 7432
 #define sqlite3_str_appendall chrome_sqlite3_str_appendall    // Line 7433
@@ -263,9 +263,9 @@
 #define sqlite3_str_vappendf chrome_sqlite3_str_vappendf      // Line 7431
 #define sqlite3_strglob chrome_sqlite3_strglob                // Line 8408
 #define sqlite3_stricmp chrome_sqlite3_stricmp                // Line 8390
-#define sqlite3_strlike chrome_sqlite3_strlike                // Line 8454
+#define sqlite3_strlike chrome_sqlite3_strlike                // Line 8431
 #define sqlite3_strnicmp chrome_sqlite3_strnicmp              // Line 8391
-#define sqlite3_system_errno chrome_sqlite3_system_errno      // Line 9055
+#define sqlite3_system_errno chrome_sqlite3_system_errno      // Line 9032
 #define sqlite3_table_column_metadata \
   chrome_sqlite3_table_column_metadata                        // Lines 6135-6145
 #define sqlite3_temp_directory chrome_sqlite3_temp_directory  // Line 5675
@@ -306,91 +306,91 @@
 #define sqlite3_vfs_unregister chrome_sqlite3_vfs_unregister      // Line 6914
 #define sqlite3_vmprintf chrome_sqlite3_vmprintf                  // Line 2675
 #define sqlite3_vsnprintf chrome_sqlite3_vsnprintf                // Line 2677
-#define sqlite3_vtab_collation chrome_sqlite3_vtab_collation      // Line 8788
-#define sqlite3_vtab_config chrome_sqlite3_vtab_config            // Line 8700
-#define sqlite3_vtab_nochange chrome_sqlite3_vtab_nochange        // Line 8773
-#define sqlite3_vtab_on_conflict chrome_sqlite3_vtab_on_conflict  // Line 8754
+#define sqlite3_vtab_collation chrome_sqlite3_vtab_collation      // Line 8765
+#define sqlite3_vtab_config chrome_sqlite3_vtab_config            // Line 8677
+#define sqlite3_vtab_nochange chrome_sqlite3_vtab_nochange        // Line 8750
+#define sqlite3_vtab_on_conflict chrome_sqlite3_vtab_on_conflict  // Line 8731
 #define sqlite3_wal_autocheckpoint \
-  chrome_sqlite3_wal_autocheckpoint                           // Line 8548
-#define sqlite3_wal_checkpoint chrome_sqlite3_wal_checkpoint  // Line 8570
+  chrome_sqlite3_wal_autocheckpoint                           // Line 8525
+#define sqlite3_wal_checkpoint chrome_sqlite3_wal_checkpoint  // Line 8547
 #define sqlite3_wal_checkpoint_v2 \
-  chrome_sqlite3_wal_checkpoint_v2                // Lines 8664-8670
-#define sqlite3_wal_hook chrome_sqlite3_wal_hook  // Lines 8513-8517
+  chrome_sqlite3_wal_checkpoint_v2                // Lines 8641-8647
+#define sqlite3_wal_hook chrome_sqlite3_wal_hook  // Lines 8490-8494
 #define sqlite3_win32_set_directory \
   chrome_sqlite3_win32_set_directory  // Lines 5733-5736
 #define sqlite3_win32_set_directory16 \
   chrome_sqlite3_win32_set_directory16  // Line 5738
 #define sqlite3_win32_set_directory8 \
   chrome_sqlite3_win32_set_directory8                         // Line 5737
-#define sqlite3changegroup_add chrome_sqlite3changegroup_add  // Line 10435
+#define sqlite3changegroup_add chrome_sqlite3changegroup_add  // Line 10412
 #define sqlite3changegroup_add_strm \
-  chrome_sqlite3changegroup_add_strm  // Lines 11097-11100
+  chrome_sqlite3changegroup_add_strm  // Lines 11074-11077
 #define sqlite3changegroup_delete \
-  chrome_sqlite3changegroup_delete                            // Line 10472
-#define sqlite3changegroup_new chrome_sqlite3changegroup_new  // Line 10357
+  chrome_sqlite3changegroup_delete                            // Line 10449
+#define sqlite3changegroup_new chrome_sqlite3changegroup_new  // Line 10334
 #define sqlite3changegroup_output \
-  chrome_sqlite3changegroup_output  // Lines 10462-10466
+  chrome_sqlite3changegroup_output  // Lines 10439-10443
 #define sqlite3changegroup_output_strm \
-  chrome_sqlite3changegroup_output_strm  // Lines 11101-11104
+  chrome_sqlite3changegroup_output_strm  // Lines 11078-11081
 #define sqlite3changeset_apply \
-  chrome_sqlite3changeset_apply  // Lines 10632-10646
+  chrome_sqlite3changeset_apply  // Lines 10609-10623
 #define sqlite3changeset_apply_strm \
-  chrome_sqlite3changeset_apply_strm  // Lines 11030-11044
+  chrome_sqlite3changeset_apply_strm  // Lines 11007-11021
 #define sqlite3changeset_apply_v2 \
-  chrome_sqlite3changeset_apply_v2  // Lines 10647-10663
+  chrome_sqlite3changeset_apply_v2  // Lines 10624-10640
 #define sqlite3changeset_apply_v2_strm \
-  chrome_sqlite3changeset_apply_v2_strm  // Lines 11045-11061
+  chrome_sqlite3changeset_apply_v2_strm  // Lines 11022-11038
 #define sqlite3changeset_concat \
-  chrome_sqlite3changeset_concat  // Lines 10303-10310
+  chrome_sqlite3changeset_concat  // Lines 10280-10287
 #define sqlite3changeset_concat_strm \
-  chrome_sqlite3changeset_concat_strm  // Lines 11062-11069
+  chrome_sqlite3changeset_concat_strm  // Lines 11039-11046
 #define sqlite3changeset_conflict \
-  chrome_sqlite3changeset_conflict  // Lines 10189-10193
+  chrome_sqlite3changeset_conflict  // Lines 10166-10170
 #define sqlite3changeset_finalize \
-  chrome_sqlite3changeset_finalize  // Line 10242
+  chrome_sqlite3changeset_finalize  // Line 10219
 #define sqlite3changeset_fk_conflicts \
-  chrome_sqlite3changeset_fk_conflicts  // Lines 10206-10209
+  chrome_sqlite3changeset_fk_conflicts  // Lines 10183-10186
 #define sqlite3changeset_invert \
-  chrome_sqlite3changeset_invert  // Lines 10272-10275
+  chrome_sqlite3changeset_invert  // Lines 10249-10252
 #define sqlite3changeset_invert_strm \
-  chrome_sqlite3changeset_invert_strm                       // Lines 11070-11075
-#define sqlite3changeset_new chrome_sqlite3changeset_new    // Lines 10161-10165
-#define sqlite3changeset_next chrome_sqlite3changeset_next  // Line 10033
-#define sqlite3changeset_old chrome_sqlite3changeset_old    // Lines 10127-10131
-#define sqlite3changeset_op chrome_sqlite3changeset_op      // Lines 10062-10068
-#define sqlite3changeset_pk chrome_sqlite3changeset_pk      // Lines 10096-10100
-#define sqlite3changeset_start chrome_sqlite3changeset_start  // Lines 9984-9988
+  chrome_sqlite3changeset_invert_strm                       // Lines 11047-11052
+#define sqlite3changeset_new chrome_sqlite3changeset_new    // Lines 10138-10142
+#define sqlite3changeset_next chrome_sqlite3changeset_next  // Line 10010
+#define sqlite3changeset_old chrome_sqlite3changeset_old    // Lines 10104-10108
+#define sqlite3changeset_op chrome_sqlite3changeset_op      // Lines 10039-10045
+#define sqlite3changeset_pk chrome_sqlite3changeset_pk      // Lines 10073-10077
+#define sqlite3changeset_start chrome_sqlite3changeset_start  // Lines 9961-9965
 #define sqlite3changeset_start_strm \
-  chrome_sqlite3changeset_start_strm  // Lines 11076-11080
+  chrome_sqlite3changeset_start_strm  // Lines 11053-11057
 #define sqlite3changeset_start_v2 \
-  chrome_sqlite3changeset_start_v2  // Lines 9989-9994
+  chrome_sqlite3changeset_start_v2  // Lines 9966-9971
 #define sqlite3changeset_start_v2_strm \
-  chrome_sqlite3changeset_start_v2_strm  // Lines 11081-11086
+  chrome_sqlite3changeset_start_v2_strm  // Lines 11058-11063
 #define sqlite3rebaser_configure \
-  chrome_sqlite3rebaser_configure                           // Lines 10905-10908
-#define sqlite3rebaser_create chrome_sqlite3rebaser_create  // Line 10894
-#define sqlite3rebaser_delete chrome_sqlite3rebaser_delete  // Line 10938
-#define sqlite3rebaser_rebase chrome_sqlite3rebaser_rebase  // Lines 10924-10928
+  chrome_sqlite3rebaser_configure                           // Lines 10882-10885
+#define sqlite3rebaser_create chrome_sqlite3rebaser_create  // Line 10871
+#define sqlite3rebaser_delete chrome_sqlite3rebaser_delete  // Line 10915
+#define sqlite3rebaser_rebase chrome_sqlite3rebaser_rebase  // Lines 10901-10905
 #define sqlite3rebaser_rebase_strm \
-  chrome_sqlite3rebaser_rebase_strm                         // Lines 11105-11111
-#define sqlite3session_attach chrome_sqlite3session_attach  // Lines 9691-9694
+  chrome_sqlite3rebaser_rebase_strm                         // Lines 11082-11088
+#define sqlite3session_attach chrome_sqlite3session_attach  // Lines 9668-9671
 #define sqlite3session_changeset \
-  chrome_sqlite3session_changeset  // Lines 9820-9824
+  chrome_sqlite3session_changeset  // Lines 9797-9801
 #define sqlite3session_changeset_strm \
-  chrome_sqlite3session_changeset_strm                      // Lines 11087-11091
-#define sqlite3session_config chrome_sqlite3session_config  // Line 11146
-#define sqlite3session_create chrome_sqlite3session_create  // Lines 9561-9565
-#define sqlite3session_delete chrome_sqlite3session_delete  // Line 9580
-#define sqlite3session_diff chrome_sqlite3session_diff      // Lines 9883-9888
-#define sqlite3session_enable chrome_sqlite3session_enable  // Line 9601
-#define sqlite3session_indirect chrome_sqlite3session_indirect  // Line 9631
-#define sqlite3session_isempty chrome_sqlite3session_isempty    // Line 9941
+  chrome_sqlite3session_changeset_strm                      // Lines 11064-11068
+#define sqlite3session_config chrome_sqlite3session_config  // Line 11123
+#define sqlite3session_create chrome_sqlite3session_create  // Lines 9538-9542
+#define sqlite3session_delete chrome_sqlite3session_delete  // Line 9557
+#define sqlite3session_diff chrome_sqlite3session_diff      // Lines 9860-9865
+#define sqlite3session_enable chrome_sqlite3session_enable  // Line 9578
+#define sqlite3session_indirect chrome_sqlite3session_indirect  // Line 9608
+#define sqlite3session_isempty chrome_sqlite3session_isempty    // Line 9918
 #define sqlite3session_patchset \
-  chrome_sqlite3session_patchset  // Lines 9920-9924
+  chrome_sqlite3session_patchset  // Lines 9897-9901
 #define sqlite3session_patchset_strm \
-  chrome_sqlite3session_patchset_strm  // Lines 11092-11096
+  chrome_sqlite3session_patchset_strm  // Lines 11069-11073
 #define sqlite3session_table_filter \
-  chrome_sqlite3session_table_filter  // Lines 9706-9713
+  chrome_sqlite3session_table_filter  // Lines 9683-9690
 
 #endif  // THIRD_PARTY_SQLITE_AMALGAMATION_RENAME_EXPORTS_H_
 
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 55060d4..62273a1 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -9446,29 +9446,6 @@
 */
 SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
 
-/* Begin WebDatabase patch for Chromium */
-/* Expose some SQLite internals for the WebDatabase vfs.
-** DO NOT EXTEND THE USE OF THIS.
-*/
-#ifndef CHROMIUM_SQLITE_API
-#define CHROMIUM_SQLITE_API SQLITE_API
-#endif
-#if defined(CHROMIUM_SQLITE_INTERNALS)
-#ifdef _WIN32
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
-#else  /* _WIN32 */
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-                                               int fd,
-                                               sqlite3_file* pFile,
-                                               const char* zPath,
-                                               int noLock,
-                                               int flags);
-#endif  /* _WIN32 */
-#endif  /* CHROMIUM_SQLITE_INTERNALS */
-/* End WebDatabase patch for Chromium */
-
 /*
 ** CAPI3REF: String LIKE Matching
 *
@@ -33846,12 +33823,6 @@
   return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId;
 #else
   struct stat buf;
-
-  /* TODO(shess): This check doesn't work when the Chromium's WebDB code is
-  ** running in the sandbox.
-  */
-  return 0;
-
   return pFile->pInode!=0 &&
       (osStat(pFile->zPath, &buf)!=0
          || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
@@ -38295,45 +38266,6 @@
 }
 
 /*
-** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
-** WebDatabase SQLiteFileSystemPosix.cpp.  Function is a subset of unixOpen(),
-** each duplicated piece is marked by "Duplicated in" comment in unixOpen().
-*/
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-                                               int fd,
-                                               sqlite3_file* pFile,
-                                               const char* zPath,
-                                               int noLock,
-                                               int flags) {
-  unixFile *p = (unixFile *)pFile;
-  const int eType = flags&0xFFFFFF00;  /* Type of file to open */
-  const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
-  int rc;
-
-  memset(p, 0, sizeof(unixFile));
-
-  /* osStat() will not work in the sandbox, so findReusableFd() will always
-  ** fail, so directly include the failure-case setup then initialize
-  ** pPreallocatedUnused.
-  */
-  if( eType==SQLITE_OPEN_MAIN_DB ){
-    p->pPreallocatedUnused = sqlite3_malloc(sizeof(*p->pPreallocatedUnused));
-    if (!p->pPreallocatedUnused) {
-      return SQLITE_NOMEM_BKPT;
-    }
-    p->pPreallocatedUnused->fd = fd;
-    p->pPreallocatedUnused->flags = flags;
-  }
-
-  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
-  if( rc!=SQLITE_OK ){
-    sqlite3_free(p->pPreallocatedUnused);
-  }
-  return rc;
-}
-
-/*
 ** Open the file zPath.
 **
 ** Previously, the SQLite OS layer used three functions in place of this
@@ -38433,8 +38365,6 @@
     randomnessPid = osGetpid(0);
     sqlite3_randomness(0,0);
   }
-
-  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
   memset(p, 0, sizeof(unixFile));
 
   if( eType==SQLITE_OPEN_MAIN_DB ){
@@ -38443,7 +38373,6 @@
     if( pUnused ){
       fd = pUnused->fd;
     }else{
-      /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
       pUnused = sqlite3_malloc64(sizeof(*pUnused));
       if( !pUnused ){
         return SQLITE_NOMEM_BKPT;
@@ -38528,7 +38457,6 @@
   }
 
   if( p->pPreallocatedUnused ){
-    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
     p->pPreallocatedUnused->fd = fd;
     p->pPreallocatedUnused->flags = flags;
   }
@@ -38610,12 +38538,10 @@
   assert( zPath==0 || zPath[0]=='/'
       || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
   );
-  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
 
 open_finished:
   if( rc!=SQLITE_OK ){
-    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
     sqlite3_free(p->pPreallocatedUnused);
   }
   return rc;
@@ -46663,14 +46589,6 @@
   return SQLITE_OK;
 }
 
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) {
-  winFile* winSQLite3File = (winFile*)file;
-  memset(file, 0, sizeof(*file));
-  winSQLite3File->pMethod = &winIoMethod;
-  winSQLite3File->h = handle;
-}
-
 #endif /* SQLITE_OS_WIN */
 
 /************** End of os_win.c **********************************************/
@@ -221520,7 +221438,7 @@
 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
 
 /************** End of stmt.c ************************************************/
-#if __LINE__!=221523
+#if __LINE__!=221441
 #undef SQLITE_SOURCE_ID
 #define SQLITE_SOURCE_ID      "2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0alt2"
 #endif
diff --git a/third_party/sqlite/amalgamation/sqlite3.h b/third_party/sqlite/amalgamation/sqlite3.h
index ab59817..36d16e7 100644
--- a/third_party/sqlite/amalgamation/sqlite3.h
+++ b/third_party/sqlite/amalgamation/sqlite3.h
@@ -8407,29 +8407,6 @@
 */
 SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
 
-/* Begin WebDatabase patch for Chromium */
-/* Expose some SQLite internals for the WebDatabase vfs.
-** DO NOT EXTEND THE USE OF THIS.
-*/
-#ifndef CHROMIUM_SQLITE_API
-#define CHROMIUM_SQLITE_API SQLITE_API
-#endif
-#if defined(CHROMIUM_SQLITE_INTERNALS)
-#ifdef _WIN32
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
-#else  /* _WIN32 */
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-                                               int fd,
-                                               sqlite3_file* pFile,
-                                               const char* zPath,
-                                               int noLock,
-                                               int flags);
-#endif  /* _WIN32 */
-#endif  /* CHROMIUM_SQLITE_INTERNALS */
-/* End WebDatabase patch for Chromium */
-
 /*
 ** CAPI3REF: String LIKE Matching
 *
diff --git a/third_party/sqlite/patches/0001-Modify-default-VFS-to-support-WebDatabase.patch b/third_party/sqlite/patches/0001-Modify-default-VFS-to-support-WebDatabase.patch
deleted file mode 100644
index 1fb9032..0000000
--- a/third_party/sqlite/patches/0001-Modify-default-VFS-to-support-WebDatabase.patch
+++ /dev/null
@@ -1,179 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: dumi <dumi@chromium.org>
-Date: Mon, 20 Jul 2009 23:40:51 +0000
-Subject: [PATCH 01/10] Modify default VFS to support WebDatabase.
-
-The renderer WebDatabase implementation needs to broker certain requests
-to the browser.  This modifies SQLite to allow monkey-patching the VFS
-to support this.
-
-NOTE(shess): This patch relies on core SQLite implementation details
-remaining unchanged.  When importing a new version of SQLite, pay very
-close attention to whether the change is still doing what is intended.
-
-Original review URLs:
-https://codereview.chromium.org/159044
-https://codereview.chromium.org/384075
-https://codereview.chromium.org/377039
-[Possibly not a complete list.]
----
- third_party/sqlite/src/src/os_unix.c   | 51 ++++++++++++++++++++++++++
- third_party/sqlite/src/src/os_win.c    |  8 ++++
- third_party/sqlite/src/src/sqlite.h.in | 23 ++++++++++++
- 3 files changed, 82 insertions(+)
-
-diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
-index 52ef64116444..d0e1c39bc4b8 100644
---- a/third_party/sqlite/src/src/os_unix.c
-+++ b/third_party/sqlite/src/src/os_unix.c
-@@ -1437,6 +1437,12 @@ static int fileHasMoved(unixFile *pFile){
-   return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId;
- #else
-   struct stat buf;
-+
-+  /* TODO(shess): This check doesn't work when the Chromium's WebDB code is
-+  ** running in the sandbox.
-+  */
-+  return 0;
-+
-   return pFile->pInode!=0 &&
-       (osStat(pFile->zPath, &buf)!=0
-          || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
-@@ -5879,6 +5885,45 @@ static int findCreateFileMode(
-   return rc;
- }
- 
-+/*
-+** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
-+** WebDatabase SQLiteFileSystemPosix.cpp.  Function is a subset of unixOpen(),
-+** each duplicated piece is marked by "Duplicated in" comment in unixOpen().
-+*/
-+CHROMIUM_SQLITE_API
-+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-+                                               int fd,
-+                                               sqlite3_file* pFile,
-+                                               const char* zPath,
-+                                               int noLock,
-+                                               int flags) {
-+  unixFile *p = (unixFile *)pFile;
-+  const int eType = flags&0xFFFFFF00;  /* Type of file to open */
-+  const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
-+  int rc;
-+
-+  memset(p, 0, sizeof(unixFile));
-+
-+  /* osStat() will not work in the sandbox, so findReusableFd() will always
-+  ** fail, so directly include the failure-case setup then initialize
-+  ** pPreallocatedUnused.
-+  */
-+  if( eType==SQLITE_OPEN_MAIN_DB ){
-+    p->pPreallocatedUnused = sqlite3_malloc(sizeof(*p->pPreallocatedUnused));
-+    if (!p->pPreallocatedUnused) {
-+      return SQLITE_NOMEM_BKPT;
-+    }
-+    p->pPreallocatedUnused->fd = fd;
-+    p->pPreallocatedUnused->flags = flags;
-+  }
-+
-+  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
-+  if( rc!=SQLITE_OK ){
-+    sqlite3_free(p->pPreallocatedUnused);
-+  }
-+  return rc;
-+}
-+
- /*
- ** Open the file zPath.
- **
-@@ -5979,6 +6024,8 @@ static int unixOpen(
-     randomnessPid = osGetpid(0);
-     sqlite3_randomness(0,0);
-   }
-+
-+  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
-   memset(p, 0, sizeof(unixFile));
- 
-   if( eType==SQLITE_OPEN_MAIN_DB ){
-@@ -5987,6 +6034,7 @@ static int unixOpen(
-     if( pUnused ){
-       fd = pUnused->fd;
-     }else{
-+      /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
-       pUnused = sqlite3_malloc64(sizeof(*pUnused));
-       if( !pUnused ){
-         return SQLITE_NOMEM_BKPT;
-@@ -6071,6 +6119,7 @@ static int unixOpen(
-   }
- 
-   if( p->pPreallocatedUnused ){
-+    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
-     p->pPreallocatedUnused->fd = fd;
-     p->pPreallocatedUnused->flags = flags;
-   }
-@@ -6152,10 +6201,12 @@ static int unixOpen(
-   assert( zPath==0 || zPath[0]=='/'
-       || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
-   );
-+  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
-   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
- 
- open_finished:
-   if( rc!=SQLITE_OK ){
-+    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
-     sqlite3_free(p->pPreallocatedUnused);
-   }
-   return rc;
-diff --git a/third_party/sqlite/src/src/os_win.c b/third_party/sqlite/src/src/os_win.c
-index aafc89f7d2d5..76743781a019 100644
---- a/third_party/sqlite/src/src/os_win.c
-+++ b/third_party/sqlite/src/src/os_win.c
-@@ -6130,4 +6130,12 @@ int sqlite3_os_end(void){
-   return SQLITE_OK;
- }
- 
-+CHROMIUM_SQLITE_API
-+void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) {
-+  winFile* winSQLite3File = (winFile*)file;
-+  memset(file, 0, sizeof(*file));
-+  winSQLite3File->pMethod = &winIoMethod;
-+  winSQLite3File->h = handle;
-+}
-+
- #endif /* SQLITE_OS_WIN */
-diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src/sqlite.h.in
-index e279e21a8cb2..0c566e8f557e 100644
---- a/third_party/sqlite/src/src/sqlite.h.in
-+++ b/third_party/sqlite/src/src/sqlite.h.in
-@@ -8407,6 +8407,29 @@ int sqlite3_strnicmp(const char *, const char *, int);
- */
- int sqlite3_strglob(const char *zGlob, const char *zStr);
- 
-+/* Begin WebDatabase patch for Chromium */
-+/* Expose some SQLite internals for the WebDatabase vfs.
-+** DO NOT EXTEND THE USE OF THIS.
-+*/
-+#ifndef CHROMIUM_SQLITE_API
-+#define CHROMIUM_SQLITE_API SQLITE_API
-+#endif
-+#if defined(CHROMIUM_SQLITE_INTERNALS)
-+#ifdef _WIN32
-+CHROMIUM_SQLITE_API
-+void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
-+#else  /* _WIN32 */
-+CHROMIUM_SQLITE_API
-+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-+                                               int fd,
-+                                               sqlite3_file* pFile,
-+                                               const char* zPath,
-+                                               int noLock,
-+                                               int flags);
-+#endif  /* _WIN32 */
-+#endif  /* CHROMIUM_SQLITE_INTERNALS */
-+/* End WebDatabase patch for Chromium */
-+
- /*
- ** CAPI3REF: String LIKE Matching
- *
--- 
-2.21.0.225.g810b269d1ac-goog
-
diff --git a/third_party/sqlite/patches/0002-Virtual-table-supporting-recovery-of-corrupted-datab.patch b/third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch
similarity index 99%
rename from third_party/sqlite/patches/0002-Virtual-table-supporting-recovery-of-corrupted-datab.patch
rename to third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch
index d50a4e1..fb110f8 100644
--- a/third_party/sqlite/patches/0002-Virtual-table-supporting-recovery-of-corrupted-datab.patch
+++ b/third_party/sqlite/patches/0001-Virtual-table-supporting-recovery-of-corrupted-datab.patch
@@ -1,8 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Scott Hess <shess@chromium.org>
 Date: Sat, 20 Jul 2013 11:42:21 -0700
-Subject: [PATCH 02/10] Virtual table supporting recovery of corrupted
- databases.
+Subject: [PATCH 1/9] Virtual table supporting recovery of corrupted databases.
 
 "recover" implements a virtual table which uses the SQLite pager layer
 to read table pages and pull out the data which is structurally sound
@@ -3901,5 +3900,5 @@
 +
 +finish_test
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0003-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch b/third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
similarity index 97%
rename from third_party/sqlite/patches/0003-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
rename to third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
index fc45018f..748b596 100644
--- a/third_party/sqlite/patches/0003-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
+++ b/third_party/sqlite/patches/0002-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: "tc@google.com" <tc@google.com>
 Date: Tue, 6 Jan 2009 22:39:41 +0000
-Subject: [PATCH 03/10] Custom shell.c helpers to load Chromium's ICU data.
+Subject: [PATCH 2/9] Custom shell.c helpers to load Chromium's ICU data.
 
 History uses fts3 with an icu-based segmenter.  These changes allow building a
 sqlite3 binary for Linux or Windows which can read those files.
@@ -141,5 +141,5 @@
 +  return 1;
 +}
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0004-fts3-Disable-fts3_tokenizer-and-fts4.patch b/third_party/sqlite/patches/0003-fts3-Disable-fts3_tokenizer-and-fts4.patch
similarity index 95%
rename from third_party/sqlite/patches/0004-fts3-Disable-fts3_tokenizer-and-fts4.patch
rename to third_party/sqlite/patches/0003-fts3-Disable-fts3_tokenizer-and-fts4.patch
index 989564a..7b59fb07 100644
--- a/third_party/sqlite/patches/0004-fts3-Disable-fts3_tokenizer-and-fts4.patch
+++ b/third_party/sqlite/patches/0003-fts3-Disable-fts3_tokenizer-and-fts4.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Scott Hess <shess@chromium.org>
 Date: Tue, 16 Dec 2014 13:02:27 -0800
-Subject: [PATCH 04/10] [fts3] Disable fts3_tokenizer and fts4.
+Subject: [PATCH 3/9] [fts3] Disable fts3_tokenizer and fts4.
 
 fts3_tokenizer allows a SQLite user to specify a pointer to call as a
 function, which has obvious sercurity implications.  Disable fts4 until
@@ -56,5 +56,5 @@
    }
  
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0005-Fix-compilation-with-SQLITE_OMIT_WINDOWFUNC.patch b/third_party/sqlite/patches/0004-Fix-compilation-with-SQLITE_OMIT_WINDOWFUNC.patch
similarity index 90%
rename from third_party/sqlite/patches/0005-Fix-compilation-with-SQLITE_OMIT_WINDOWFUNC.patch
rename to third_party/sqlite/patches/0004-Fix-compilation-with-SQLITE_OMIT_WINDOWFUNC.patch
index 1b13c52e..e1b0940 100644
--- a/third_party/sqlite/patches/0005-Fix-compilation-with-SQLITE_OMIT_WINDOWFUNC.patch
+++ b/third_party/sqlite/patches/0004-Fix-compilation-with-SQLITE_OMIT_WINDOWFUNC.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Victor Costan <pwnall@chromium.org>
 Date: Sun, 10 Feb 2019 13:12:57 -0800
-Subject: [PATCH 05/10] Fix compilation with SQLITE_OMIT_WINDOWFUNC.
+Subject: [PATCH 4/9] Fix compilation with SQLITE_OMIT_WINDOWFUNC.
 
 ---
  third_party/sqlite/src/src/resolve.c | 2 ++
@@ -28,5 +28,5 @@
      /* If this is part of a compound SELECT, check that it has the right
      ** number of expressions in the select list. */
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0006-Fix-dbfuzz2.c-compilation-errors-on-Windows.patch b/third_party/sqlite/patches/0005-Fix-dbfuzz2.c-compilation-errors-on-Windows.patch
similarity index 92%
rename from third_party/sqlite/patches/0006-Fix-dbfuzz2.c-compilation-errors-on-Windows.patch
rename to third_party/sqlite/patches/0005-Fix-dbfuzz2.c-compilation-errors-on-Windows.patch
index c4b3ff6..dd8c0a16 100644
--- a/third_party/sqlite/patches/0006-Fix-dbfuzz2.c-compilation-errors-on-Windows.patch
+++ b/third_party/sqlite/patches/0005-Fix-dbfuzz2.c-compilation-errors-on-Windows.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Victor Costan <pwnall@chromium.org>
 Date: Sun, 10 Feb 2019 15:18:43 -0800
-Subject: [PATCH 06/10] Fix dbfuzz2.c compilation errors on Windows.
+Subject: [PATCH 5/9] Fix dbfuzz2.c compilation errors on Windows.
 
 ---
  third_party/sqlite/src/test/dbfuzz2.c | 4 ++++
@@ -39,5 +39,5 @@
      argv[j++] = argv[i];
    }
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0007-Fix-Heap-buffer-overflow-in-vdbeRecordCompareInt.patch b/third_party/sqlite/patches/0006-Fix-Heap-buffer-overflow-in-vdbeRecordCompareInt.patch
similarity index 89%
rename from third_party/sqlite/patches/0007-Fix-Heap-buffer-overflow-in-vdbeRecordCompareInt.patch
rename to third_party/sqlite/patches/0006-Fix-Heap-buffer-overflow-in-vdbeRecordCompareInt.patch
index 4e0eaca..422e603 100644
--- a/third_party/sqlite/patches/0007-Fix-Heap-buffer-overflow-in-vdbeRecordCompareInt.patch
+++ b/third_party/sqlite/patches/0006-Fix-Heap-buffer-overflow-in-vdbeRecordCompareInt.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Tue, 5 Mar 2019 13:49:51 -0800
-Subject: [PATCH 07/10] Fix Heap-buffer-overflow in vdbeRecordCompareInt
+Subject: [PATCH 6/9] Fix Heap-buffer-overflow in vdbeRecordCompareInt
 
 This backports https://www.sqlite.org/src/info/c1ac00706bae45fe
 
@@ -24,5 +24,5 @@
          }
          assert(
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0008-fix-heap-buffer-overflow-in-cellsizeptr.patch b/third_party/sqlite/patches/0007-fix-heap-buffer-overflow-in-cellsizeptr.patch
similarity index 92%
rename from third_party/sqlite/patches/0008-fix-heap-buffer-overflow-in-cellsizeptr.patch
rename to third_party/sqlite/patches/0007-fix-heap-buffer-overflow-in-cellsizeptr.patch
index dda29f0..f80f372 100644
--- a/third_party/sqlite/patches/0008-fix-heap-buffer-overflow-in-cellsizeptr.patch
+++ b/third_party/sqlite/patches/0007-fix-heap-buffer-overflow-in-cellsizeptr.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Tue, 5 Mar 2019 14:13:19 -0800
-Subject: [PATCH 08/10] fix heap-buffer-overflow in cellsizeptr
+Subject: [PATCH 7/9] fix heap-buffer-overflow in cellsizeptr
 
 This backports https://www.sqlite.org/src/info/e7aca0714bc475e0
 
@@ -32,5 +32,5 @@
  
      if( rc==SQLITE_OK ){
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0009-fix-integer-overflow-in-checkList.patch b/third_party/sqlite/patches/0008-fix-integer-overflow-in-checkList.patch
similarity index 94%
rename from third_party/sqlite/patches/0009-fix-integer-overflow-in-checkList.patch
rename to third_party/sqlite/patches/0008-fix-integer-overflow-in-checkList.patch
index 795f704..3ed874b 100644
--- a/third_party/sqlite/patches/0009-fix-integer-overflow-in-checkList.patch
+++ b/third_party/sqlite/patches/0008-fix-integer-overflow-in-checkList.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Tue, 5 Mar 2019 14:17:05 -0800
-Subject: [PATCH 09/10] fix integer overflow in checkList
+Subject: [PATCH 8/9] fix integer overflow in checkList
 
 This backports https://www.sqlite.org/src/info/05b87e0755638d31
 
@@ -37,5 +37,5 @@
        assert( pc + info.nSize - 4 <= usableSize );
        nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4);
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/patches/0010-Fix-Heap-use-after-free-in-releasePageNotNull.patch b/third_party/sqlite/patches/0009-Fix-Heap-use-after-free-in-releasePageNotNull.patch
similarity index 91%
rename from third_party/sqlite/patches/0010-Fix-Heap-use-after-free-in-releasePageNotNull.patch
rename to third_party/sqlite/patches/0009-Fix-Heap-use-after-free-in-releasePageNotNull.patch
index ad9d4aa..998d3864 100644
--- a/third_party/sqlite/patches/0010-Fix-Heap-use-after-free-in-releasePageNotNull.patch
+++ b/third_party/sqlite/patches/0009-Fix-Heap-use-after-free-in-releasePageNotNull.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Tue, 12 Mar 2019 17:30:33 -0700
-Subject: [PATCH 10/10] Fix Heap-use-after-free in releasePageNotNull
+Subject: [PATCH 9/9] Fix Heap-use-after-free in releasePageNotNull
 
 This backports https://www.sqlite.org/src/info/b0d5cf40bba34e45
 
@@ -29,5 +29,5 @@
      if( pPager->tempFile ){
        /* Do not discard pages from an in-memory database since we might
 -- 
-2.21.0.225.g810b269d1ac-goog
+2.20.1
 
diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
index d0e1c39..52ef641 100644
--- a/third_party/sqlite/src/src/os_unix.c
+++ b/third_party/sqlite/src/src/os_unix.c
@@ -1437,12 +1437,6 @@
   return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId;
 #else
   struct stat buf;
-
-  /* TODO(shess): This check doesn't work when the Chromium's WebDB code is
-  ** running in the sandbox.
-  */
-  return 0;
-
   return pFile->pInode!=0 &&
       (osStat(pFile->zPath, &buf)!=0
          || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
@@ -5886,45 +5880,6 @@
 }
 
 /*
-** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
-** WebDatabase SQLiteFileSystemPosix.cpp.  Function is a subset of unixOpen(),
-** each duplicated piece is marked by "Duplicated in" comment in unixOpen().
-*/
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-                                               int fd,
-                                               sqlite3_file* pFile,
-                                               const char* zPath,
-                                               int noLock,
-                                               int flags) {
-  unixFile *p = (unixFile *)pFile;
-  const int eType = flags&0xFFFFFF00;  /* Type of file to open */
-  const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0);
-  int rc;
-
-  memset(p, 0, sizeof(unixFile));
-
-  /* osStat() will not work in the sandbox, so findReusableFd() will always
-  ** fail, so directly include the failure-case setup then initialize
-  ** pPreallocatedUnused.
-  */
-  if( eType==SQLITE_OPEN_MAIN_DB ){
-    p->pPreallocatedUnused = sqlite3_malloc(sizeof(*p->pPreallocatedUnused));
-    if (!p->pPreallocatedUnused) {
-      return SQLITE_NOMEM_BKPT;
-    }
-    p->pPreallocatedUnused->fd = fd;
-    p->pPreallocatedUnused->flags = flags;
-  }
-
-  rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
-  if( rc!=SQLITE_OK ){
-    sqlite3_free(p->pPreallocatedUnused);
-  }
-  return rc;
-}
-
-/*
 ** Open the file zPath.
 **
 ** Previously, the SQLite OS layer used three functions in place of this
@@ -6024,8 +5979,6 @@
     randomnessPid = osGetpid(0);
     sqlite3_randomness(0,0);
   }
-
-  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
   memset(p, 0, sizeof(unixFile));
 
   if( eType==SQLITE_OPEN_MAIN_DB ){
@@ -6034,7 +5987,6 @@
     if( pUnused ){
       fd = pUnused->fd;
     }else{
-      /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
       pUnused = sqlite3_malloc64(sizeof(*pUnused));
       if( !pUnused ){
         return SQLITE_NOMEM_BKPT;
@@ -6119,7 +6071,6 @@
   }
 
   if( p->pPreallocatedUnused ){
-    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
     p->pPreallocatedUnused->fd = fd;
     p->pPreallocatedUnused->flags = flags;
   }
@@ -6201,12 +6152,10 @@
   assert( zPath==0 || zPath[0]=='/'
       || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
   );
-  /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
   rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
 
 open_finished:
   if( rc!=SQLITE_OK ){
-    /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
     sqlite3_free(p->pPreallocatedUnused);
   }
   return rc;
diff --git a/third_party/sqlite/src/src/os_win.c b/third_party/sqlite/src/src/os_win.c
index 76743781..aafc89f 100644
--- a/third_party/sqlite/src/src/os_win.c
+++ b/third_party/sqlite/src/src/os_win.c
@@ -6130,12 +6130,4 @@
   return SQLITE_OK;
 }
 
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) {
-  winFile* winSQLite3File = (winFile*)file;
-  memset(file, 0, sizeof(*file));
-  winSQLite3File->pMethod = &winIoMethod;
-  winSQLite3File->h = handle;
-}
-
 #endif /* SQLITE_OS_WIN */
diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src/sqlite.h.in
index 0c566e8..e279e21 100644
--- a/third_party/sqlite/src/src/sqlite.h.in
+++ b/third_party/sqlite/src/src/sqlite.h.in
@@ -8407,29 +8407,6 @@
 */
 int sqlite3_strglob(const char *zGlob, const char *zStr);
 
-/* Begin WebDatabase patch for Chromium */
-/* Expose some SQLite internals for the WebDatabase vfs.
-** DO NOT EXTEND THE USE OF THIS.
-*/
-#ifndef CHROMIUM_SQLITE_API
-#define CHROMIUM_SQLITE_API SQLITE_API
-#endif
-#if defined(CHROMIUM_SQLITE_INTERNALS)
-#ifdef _WIN32
-CHROMIUM_SQLITE_API
-void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle);
-#else  /* _WIN32 */
-CHROMIUM_SQLITE_API
-int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
-                                               int fd,
-                                               sqlite3_file* pFile,
-                                               const char* zPath,
-                                               int noLock,
-                                               int flags);
-#endif  /* _WIN32 */
-#endif  /* CHROMIUM_SQLITE_INTERNALS */
-/* End WebDatabase patch for Chromium */
-
 /*
 ** CAPI3REF: String LIKE Matching
 *
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath
index bf4a45b4..a4aa307 100644
--- a/tools/android/eclipse/.classpath
+++ b/tools/android/eclipse/.classpath
@@ -230,19 +230,19 @@
     <classpathentry kind="src" path="out/Debug/java_proto/test_support_proto_java/src"/>
     <classpathentry kind="src" path="out/Debug/remoting_apk/gen"/>
     <classpathentry kind="src" path="out/Debug/webview_instrumentation_test_apk/gen"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/google/gcm/gcm-client/dist/gcm.jar" sourcepath="third_party/android_tools/sdk/extras/google/gcm/gcm-client/src"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-28/android.jar" sourcepath="third_party/android_tools/sdk/sources/">
+    <classpathentry kind="lib" path="third_party/android_sdk/public/extras/google/gcm/gcm-client/dist/gcm.jar" sourcepath="third_party/android_sdk/public/extras/google/gcm/gcm-client/src"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-28/android.jar" sourcepath="third_party/android_sdk/public/sources/">
         <attributes>
             <attribute name="javadoc_location" value="http://developer.android.com/reference/"/>
         </attributes>
     </classpathentry>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-25/data/layoutlib.jar" sourcepath="third_party/android_tools/sdk/sources/"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/platforms/android-25/uiautomator.jar" sourcepath="third_party/android_tools/sdk/sources"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/design/libs/android-support-design.jar" sourcepath="third_party/android_tools/sdk/sources"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar" sourcepath="third_party/android_tools/sdk/sources"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/v7/recyclerview/libs/android-support-v7-recyclerview.jar" sourcepath="third_party/android_tools/sdk/sources"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/v13/android-support-v13.jar" sourcepath="third_party/android_tools/sdk/sources"/>
-    <classpathentry kind="lib" path="third_party/android_tools/sdk/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" sourcepath="third_party/android_tools/sdk/sources"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-25/data/layoutlib.jar" sourcepath="third_party/android_sdk/public/sources/"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/platforms/android-25/uiautomator.jar" sourcepath="third_party/android_sdk/public/sources"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/extras/android/support/design/libs/android-support-design.jar" sourcepath="third_party/android_sdk/public/sources"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar" sourcepath="third_party/android_sdk/public/sources"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/extras/android/support/v7/recyclerview/libs/android-support-v7-recyclerview.jar" sourcepath="third_party/android_sdk/public/sources"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/extras/android/support/v13/android-support-v13.jar" sourcepath="third_party/android_sdk/public/sources"/>
+    <classpathentry kind="lib" path="third_party/android_sdk/public/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" sourcepath="third_party/android_sdk/public/sources"/>
     <classpathentry kind="lib" path="third_party/bouncycastle/lib/bcprov-jdk16-1.46.jar"/>
     <classpathentry kind="lib" path="third_party/byte_buddy/lib/byte-buddy-1.4.17.jar"/>
     <classpathentry kind="lib" path="third_party/hamcrest/lib/hamcrest-library-1.3.jar"/>
diff --git a/tools/android/sdk_updater/update_sdk.py b/tools/android/sdk_updater/update_sdk.py
index 8d4cbb06..b71d423 100755
--- a/tools/android/sdk_updater/update_sdk.py
+++ b/tools/android/sdk_updater/update_sdk.py
@@ -55,11 +55,8 @@
 _SDK_SOURCES_ROOT = os.path.join(_SRC_ROOT, 'third_party', 'android_sdk',
                                  'sources')
 
-
-# TODO(shenghuazhang): Update sdkmanager path when gclient can download SDK
-# via CIPD: crug/789809
-_SDKMANAGER_PATH = os.path.join(_SRC_ROOT, 'third_party', 'android_tools',
-                                'sdk', 'tools', 'bin', 'sdkmanager')
+_SDKMANAGER_PATH = os.path.join(_SRC_ROOT, 'third_party', 'android_sdk',
+                                'public', 'tools', 'bin', 'sdkmanager')
 
 _ANDROID_CONFIG_GNI_PATH = os.path.join(_SRC_ROOT, 'build', 'config',
                                         'android', 'config.gni')
diff --git a/tools/binary_size/generate_milestone_reports.py b/tools/binary_size/generate_milestone_reports.py
index 5030849a..f0c66d4 100755
--- a/tools/binary_size/generate_milestone_reports.py
+++ b/tools/binary_size/generate_milestone_reports.py
@@ -58,7 +58,8 @@
     '70.0.3538.64',
     '71.0.3578.99',
     '72.0.3626.105',
-    '73.0.3683.41',  # Beta
+    '73.0.3683.75',
+    '74.0.3729.11',  # Beta
 ]
 
 
diff --git a/tools/binary_size/libsupersize/describe.py b/tools/binary_size/libsupersize/describe.py
index 13b49dd..f4b37d0 100644
--- a/tools/binary_size/libsupersize/describe.py
+++ b/tools/binary_size/libsupersize/describe.py
@@ -546,6 +546,8 @@
 
     syms = in_section.Filter(lambda s: s.source_path)
     yield '* {} have source paths. {}'.format(len(syms), size_msg(syms))
+    syms = in_section.WhereHasComponent()
+    yield '* {} have a component assigned. {}'.format(len(syms), size_msg(syms))
 
     syms = in_section.WhereNameMatches(r'^\*')
     if len(syms):
diff --git a/tools/binary_size/libsupersize/path_util.py b/tools/binary_size/libsupersize/path_util.py
index 9ef38105..aaf44b4 100644
--- a/tools/binary_size/libsupersize/path_util.py
+++ b/tools/binary_size/libsupersize/path_util.py
@@ -171,7 +171,7 @@
   if os.path.exists(sdk_analyzer):
     return sdk_analyzer
   # Older SDKs do not contain the tool, so fall back to the one we know exists.
-  return os.path.join(SRC_ROOT, 'third_party', 'android_tools', 'sdk',
+  return os.path.join(SRC_ROOT, 'third_party', 'android_sdk', 'public',
                       'tools', 'bin', 'apkanalyzer')
 
 
diff --git a/tools/binary_size/libsupersize/testdata/Archive.golden b/tools/binary_size/libsupersize/testdata/Archive.golden
index dc5f4f1a..a3a772f 100644
--- a/tools/binary_size/libsupersize/testdata/Archive.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive.golden
@@ -1,6 +1,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 16 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 0 symbols have shared ownership.
 * 1 symbols are marked as "hot". Accounts for 12 bytes (0.0%).
@@ -10,40 +11,49 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 9 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637935 bytes (99.9%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 4 placeholders exist (symbols that start with **). Accounts for 1965412 bytes (74.4%).
 * 0 string literals exist. Accounts for 0 bytes (0.0%) padding is 0 bytes.
 * 0 symbols have shared ownership.
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .dex: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .dex.method: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.nontranslated: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=,flags={},num_aliases=1,component=)
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/WebKit.a/sub/ContiguousContainer.o,source_path=,flags={},num_aliases=1,component=)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
index 8fd9e75..fd12edaf 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
@@ -12,6 +12,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
+* 16 have a component assigned. Accounts for 73986 bytes (88.3%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 8 aliases exist, mapped to 3 unique addresses (100 bytes saved)
 * 0 symbols have shared ownership.
@@ -22,6 +23,7 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 11 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637946 bytes (99.9%)
 * 8 have source paths. Accounts for 676149 bytes (25.6%).
+* 8 have a component assigned. Accounts for 676149 bytes (25.6%).
 * 3 placeholders exist (symbols that start with **). Accounts for 1965391 bytes (74.4%).
 * 3 string literals exist. Accounts for 21 bytes (0.0%) padding is 0 bytes.
 * 2 aliases exist, mapped to 1 unique addresses (5 bytes saved)
@@ -30,38 +32,46 @@
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 3 have source paths. Accounts for 92 bytes (100.0%).
+* 3 have a component assigned. Accounts for 92 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 5 have source paths. Accounts for 168 bytes (100.0%).
+* 5 have a component assigned. Accounts for 168 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 6 have source paths. Accounts for 524520 bytes (100.0%).
+* 6 have a component assigned. Accounts for 524520 bytes (100.0%).
 * 0 symbols have shared ownership.
 * 3 symbols are from generated sources. Accounts for 232 bytes (0.0%).
 Section .dex: has 100.0% of 8365003 bytes accounted for from 93 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 83 have source paths. Accounts for 926 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 1 placeholders exist (symbols that start with **). Accounts for 4616803 bytes (55.2%).
 * 0 symbols have shared ownership.
 Section .dex.method: has 100.0% of 23605 bytes accounted for from 100 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 90 have source paths. Accounts for 21154 bytes (89.6%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: has 100.0% of 6821 bytes accounted for from 208 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 18 bytes (0.3%)
 * 3 have source paths. Accounts for 23 bytes (0.3%).
+* 3 have a component assigned. Accounts for 23 bytes (0.3%).
 * 2 aliases exist, mapped to 1 unique addresses (9 bytes saved)
 * 0 symbols have shared ownership.
 * 2 symbols are from generated sources. Accounts for 23 bytes (0.3%).
 Section .pak.nontranslated: has 100.0% of 737 bytes accounted for from 3 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 18 bytes (2.4%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: has 100.0% of 39228839 bytes accounted for from 5 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 33984935 bytes (86.6%)
 * 3 have source paths. Accounts for 5243904 bytes (13.4%).
+* 1 have a component assigned. Accounts for 1048576 bytes (2.7%).
 * 0 symbols have shared ownership.
 * 1 symbols are from generated sources. Accounts for 4194304 bytes (10.7%).
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1,component=Blink>Internal)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
index 2a1a4979..ea16782 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
@@ -10,6 +10,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
+* 16 have a component assigned. Accounts for 73986 bytes (88.3%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 8 aliases exist, mapped to 3 unique addresses (100 bytes saved)
 * 0 symbols have shared ownership.
@@ -20,6 +21,7 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 11 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637946 bytes (99.9%)
 * 8 have source paths. Accounts for 676149 bytes (25.6%).
+* 8 have a component assigned. Accounts for 676149 bytes (25.6%).
 * 3 placeholders exist (symbols that start with **). Accounts for 1965391 bytes (74.4%).
 * 3 string literals exist. Accounts for 21 bytes (0.0%) padding is 0 bytes.
 * 2 aliases exist, mapped to 1 unique addresses (5 bytes saved)
@@ -28,35 +30,43 @@
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 3 have source paths. Accounts for 92 bytes (100.0%).
+* 3 have a component assigned. Accounts for 92 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 5 have source paths. Accounts for 168 bytes (100.0%).
+* 5 have a component assigned. Accounts for 168 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 6 have source paths. Accounts for 524520 bytes (100.0%).
+* 6 have a component assigned. Accounts for 524520 bytes (100.0%).
 * 0 symbols have shared ownership.
 * 3 symbols are from generated sources. Accounts for 232 bytes (0.0%).
 Section .dex: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .dex.method: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.nontranslated: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 33984171 bytes (100.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1,component=Blink>Internal)
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/sub/ContiguousContainer.o,source_path=third_party/container/container.c,flags={},num_aliases=1,component=UI>Browser)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
index 12371d0..4905e58 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
@@ -13,6 +13,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
+* 16 have a component assigned. Accounts for 73986 bytes (88.3%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 8 aliases exist, mapped to 3 unique addresses (100 bytes saved)
 * 0 symbols have shared ownership.
@@ -23,6 +24,7 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 11 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637946 bytes (99.9%)
 * 8 have source paths. Accounts for 676149 bytes (25.6%).
+* 8 have a component assigned. Accounts for 676149 bytes (25.6%).
 * 3 placeholders exist (symbols that start with **). Accounts for 1965391 bytes (74.4%).
 * 3 string literals exist. Accounts for 21 bytes (0.0%) padding is 0 bytes.
 * 2 aliases exist, mapped to 1 unique addresses (5 bytes saved)
@@ -31,38 +33,46 @@
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 3 have source paths. Accounts for 92 bytes (100.0%).
+* 3 have a component assigned. Accounts for 92 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 5 have source paths. Accounts for 168 bytes (100.0%).
+* 5 have a component assigned. Accounts for 168 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 6 have source paths. Accounts for 524520 bytes (100.0%).
+* 6 have a component assigned. Accounts for 524520 bytes (100.0%).
 * 0 symbols have shared ownership.
 * 3 symbols are from generated sources. Accounts for 232 bytes (0.0%).
 Section .dex: has 100.0% of 8365003 bytes accounted for from 93 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 83 have source paths. Accounts for 926 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 1 placeholders exist (symbols that start with **). Accounts for 4616803 bytes (55.2%).
 * 0 symbols have shared ownership.
 Section .dex.method: has 100.0% of 23605 bytes accounted for from 100 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 90 have source paths. Accounts for 21154 bytes (89.6%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: has 100.0% of 6821 bytes accounted for from 208 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 18 bytes (0.3%)
 * 3 have source paths. Accounts for 23 bytes (0.3%).
+* 3 have a component assigned. Accounts for 23 bytes (0.3%).
 * 2 aliases exist, mapped to 1 unique addresses (9 bytes saved)
 * 0 symbols have shared ownership.
 * 2 symbols are from generated sources. Accounts for 23 bytes (0.3%).
 Section .pak.nontranslated: has 100.0% of 737 bytes accounted for from 3 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 18 bytes (2.4%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: has 100.0% of 39228839 bytes accounted for from 5 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 33984935 bytes (86.6%)
 * 3 have source paths. Accounts for 5243904 bytes (13.4%).
+* 1 have a component assigned. Accounts for 1048576 bytes (2.7%).
 * 0 symbols have shared ownership.
 * 1 symbols are from generated sources. Accounts for 4194304 bytes (10.7%).
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1,component=Blink>Internal)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
index 604590f..da8b6cf 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
@@ -1,6 +1,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 16 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 14 have source paths. Accounts for 74034 bytes (88.4%).
+* 14 have a component assigned. Accounts for 74034 bytes (88.4%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 0 symbols have shared ownership.
 * 1 symbols are marked as "hot". Accounts for 12 bytes (0.0%).
@@ -11,41 +12,50 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 9 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637935 bytes (99.9%)
 * 5 have source paths. Accounts for 676128 bytes (25.6%).
+* 5 have a component assigned. Accounts for 676128 bytes (25.6%).
 * 4 placeholders exist (symbols that start with **). Accounts for 1965412 bytes (74.4%).
 * 0 string literals exist. Accounts for 0 bytes (0.0%) padding is 0 bytes.
 * 0 symbols have shared ownership.
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 3 have source paths. Accounts for 92 bytes (100.0%).
+* 3 have a component assigned. Accounts for 92 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 5 have source paths. Accounts for 168 bytes (100.0%).
+* 5 have a component assigned. Accounts for 168 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 6 have source paths. Accounts for 524520 bytes (100.0%).
+* 6 have a component assigned. Accounts for 524520 bytes (100.0%).
 * 0 symbols have shared ownership.
 * 3 symbols are from generated sources. Accounts for 232 bytes (0.0%).
 Section .dex: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .dex.method: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.nontranslated: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1,component=Blink>Internal)
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/sub/ContiguousContainer.o,source_path=third_party/container/container.c,flags={},num_aliases=1,component=UI>Browser)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden b/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
index da10f07..c53bb05 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
@@ -10,6 +10,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
+* 16 have a component assigned. Accounts for 73986 bytes (88.3%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 8 aliases exist, mapped to 3 unique addresses (100 bytes saved)
 * 0 symbols have shared ownership.
@@ -20,6 +21,7 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 11 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637946 bytes (99.9%)
 * 8 have source paths. Accounts for 676149 bytes (25.6%).
+* 8 have a component assigned. Accounts for 676149 bytes (25.6%).
 * 3 placeholders exist (symbols that start with **). Accounts for 1965391 bytes (74.4%).
 * 3 string literals exist. Accounts for 21 bytes (0.0%) padding is 0 bytes.
 * 2 aliases exist, mapped to 1 unique addresses (5 bytes saved)
@@ -28,37 +30,45 @@
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 3 have source paths. Accounts for 92 bytes (100.0%).
+* 3 have a component assigned. Accounts for 92 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 5 have source paths. Accounts for 168 bytes (100.0%).
+* 5 have a component assigned. Accounts for 168 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 6 have source paths. Accounts for 524520 bytes (100.0%).
+* 6 have a component assigned. Accounts for 524520 bytes (100.0%).
 * 0 symbols have shared ownership.
 * 3 symbols are from generated sources. Accounts for 232 bytes (0.0%).
 Section .dex: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .dex.method: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: has 100.0% of 6821 bytes accounted for from 208 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 18 bytes (0.3%)
 * 3 have source paths. Accounts for 23 bytes (0.3%).
+* 3 have a component assigned. Accounts for 23 bytes (0.3%).
 * 2 aliases exist, mapped to 1 unique addresses (9 bytes saved)
 * 0 symbols have shared ownership.
 * 2 symbols are from generated sources. Accounts for 23 bytes (0.3%).
 Section .pak.nontranslated: has 100.0% of 737 bytes accounted for from 3 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 18 bytes (2.4%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 33984171 bytes (100.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 .data@2de7000(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelCmpxchg,object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=1,component=Blink>Internal)
 .data@2de7004(size_without_padding=4,padding=0,full_name=google::protobuf::internal::pLinuxKernelMemoryBarrier,object_path=third_party/sub/ContiguousContainer.o,source_path=third_party/container/container.c,flags={},num_aliases=1,component=UI>Browser)
diff --git a/tools/binary_size/libsupersize/testdata/FullDescription.golden b/tools/binary_size/libsupersize/testdata/FullDescription.golden
index 9d9b5a9..34918d4 100644
--- a/tools/binary_size/libsupersize/testdata/FullDescription.golden
+++ b/tools/binary_size/libsupersize/testdata/FullDescription.golden
@@ -45,6 +45,7 @@
 Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
+* 16 have a component assigned. Accounts for 73986 bytes (88.3%).
 * 4 placeholders exist (symbols that start with **). Accounts for 13840 bytes (16.5%).
 * 8 aliases exist, mapped to 3 unique addresses (100 bytes saved)
 * 0 symbols have shared ownership.
@@ -55,6 +56,7 @@
 Section .rodata: has 44.6% of 2641540 bytes accounted for from 11 symbols. 3286112 bytes are unaccounted for.
 * Padding accounts for 2637946 bytes (99.9%)
 * 8 have source paths. Accounts for 676149 bytes (25.6%).
+* 8 have a component assigned. Accounts for 676149 bytes (25.6%).
 * 3 placeholders exist (symbols that start with **). Accounts for 1965391 bytes (74.4%).
 * 3 string literals exist. Accounts for 21 bytes (0.0%) padding is 0 bytes.
 * 2 aliases exist, mapped to 1 unique addresses (5 bytes saved)
@@ -63,35 +65,43 @@
 Section .data.rel.ro: has 0.0% of 92 bytes accounted for from 3 symbols. 1065132 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 3 have source paths. Accounts for 92 bytes (100.0%).
+* 3 have a component assigned. Accounts for 92 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .data: has 0.2% of 168 bytes accounted for from 5 symbols. 101600 bytes are unaccounted for.
 * Padding accounts for 0 bytes (0.0%)
 * 5 have source paths. Accounts for 168 bytes (100.0%).
+* 5 have a component assigned. Accounts for 168 bytes (100.0%).
 * 0 symbols have shared ownership.
 Section .bss: has 40.3% of 524520 bytes accounted for from 6 symbols. 775936 bytes are unaccounted for.
 * Padding accounts for 196 bytes (0.0%)
 * 6 have source paths. Accounts for 524520 bytes (100.0%).
+* 6 have a component assigned. Accounts for 524520 bytes (100.0%).
 * 0 symbols have shared ownership.
 * 3 symbols are from generated sources. Accounts for 232 bytes (0.0%).
 Section .dex: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .dex.method: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.translations: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .pak.nontranslated: 0 bytes from 0 symbols.
 * Padding accounts for 0 bytes (0.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
 * Padding accounts for 33984171 bytes (100.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
+* 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 
 Showing 52 symbols (46 unique) with total pss: 37499787 bytes
diff --git a/tools/cr/cr/base/android.py b/tools/cr/cr/base/android.py
index 2ae48ce..7d0957d 100644
--- a/tools/cr/cr/base/android.py
+++ b/tools/cr/cr/base/android.py
@@ -13,7 +13,7 @@
   """The implementation of Platform for the android target."""
 
   ACTIVE = cr.Config.From(
-      CR_ADB=os.path.join('{CR_SRC}', 'third_party', 'android_tools', 'sdk',
+      CR_ADB=os.path.join('{CR_SRC}', 'third_party', 'android_sdk', 'public',
           'platform-tools', 'adb'),
       CR_TARGET_SUFFIX='_apk',
       CR_BINARY=os.path.join('{CR_BUILD_DIR}', 'apks', '{CR_TARGET_NAME}.apk'),
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py
index 3dc26cb..412fd7e 100755
--- a/tools/cygprofile/orderfile_generator_backend.py
+++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -348,9 +348,32 @@
     self._branch = branch
     self._netrc = netrc
 
-  def CommitFileHashes(self, unpatched_orderfile_filename, orderfile_filename):
+  def CommitStashedFileHashes(self, files):
+    """Commits unpatched and patched orderfiles hashes if changed.
+
+    The files are committed only if their associated sha1 hash files match, and
+    are modified in git. In normal operations the hash files are changed only
+    when a file is uploaded to cloud storage. If the hash file is not modified
+    in git, the file is skipped.
+
+    Args:
+      files: [str or None] specifies file paths. None items are ignored.
+
+    Raises:
+      Exception if the hash file does not match the file.
+      NotImplementedError when the commit logic hasn't been overridden.
+    """
+    files_to_commit = list(filter(None, files))
+    if files_to_commit:
+      self._CommitStashedFiles(files_to_commit)
+
+  def LegacyCommitFileHashes(self,
+                             unpatched_orderfile_filename,
+                             orderfile_filename):
     """Commits unpatched and patched orderfiles hashes, if provided.
 
+    DEPRECATED. Left in place during transition.
+
     Files must have been successfilly uploaded to cloud storage first.
 
     Args:
@@ -358,7 +381,7 @@
       orderfile_filename: (str or None) Orderfile path.
 
     Raises:
-      NotImplementedError when the commit logic hasn't been overriden.
+      NotImplementedError when the commit logic hasn't been overridden.
     """
     files_to_commit = []
     commit_message_lines = ['Update Orderfile.']
@@ -412,6 +435,31 @@
     """Commits a list of files, with a given message."""
     raise NotImplementedError
 
+  def _GitStash(self):
+    """Git stash the current clank tree.
+
+    Raises:
+      NotImplementedError when the stash logic hasn't been overridden.
+    """
+    raise NotImplementedError
+
+  def _CommitStashedFiles(self, expected_files_in_stash):
+    """Commits stashed files.
+
+    The local repository is updated and then the files to commit are taken from
+    modified files from the git stash. The modified files should be a subset of
+    |expected_files_in_stash|. If there are unexpected modified files, this
+    function may raise. This is meant to be paired with _GitStash().
+
+    Args:
+      expected_files_in_stash: [str] paths to a possible superset of files
+        expected to be stashed & committed.
+
+    Raises:
+      NotImplementedError when the commit logic hasn't been overridden.
+    """
+    raise NotImplementedError
+
 
 class OrderfileGenerator(object):
   """A utility for generating a new orderfile for Clank.
@@ -811,15 +859,17 @@
         _StashOutputDirectory(self._uninstrumented_out_dir)
       orderfile_uploaded = True
 
-    if (self._options.buildbot and self._options.netrc
-        and not self._step_recorder.ErrorRecorded()):
-      unpatched_orderfile_filename = (
-          self._GetUnpatchedOrderfileFilename() if profile_uploaded else None)
-      orderfile_filename = (
-          self._GetPathToOrderfile() if orderfile_uploaded else None)
-      self._orderfile_updater.CommitFileHashes(
-          unpatched_orderfile_filename, orderfile_filename)
-
+    if self._options._new_commit_flow:
+      self._orderfile_updater._GitStash()
+    else:
+      if (self._options.buildbot and self._options.netrc
+          and not self._step_recorder.ErrorRecorded()):
+        unpatched_orderfile_filename = (
+            self._GetUnpatchedOrderfileFilename() if profile_uploaded else None)
+        orderfile_filename = (
+            self._GetPathToOrderfile() if orderfile_uploaded else None)
+        self._orderfile_updater.LegacyCommitFileHashes(
+            unpatched_orderfile_filename, orderfile_filename)
     self._step_recorder.EndStep()
     return not self._step_recorder.ErrorRecorded()
 
@@ -828,6 +878,22 @@
     self._output_data['timings'] = self._step_recorder.timings
     return self._output_data
 
+  def CommitStashedOrderfileHashes(self):
+    """Commit any orderfile hash files in the current checkout.
+
+    Only possible if running on the buildbot.
+
+    Returns: true on success.
+    """
+    if not (self._options.buildbot and self._options.netrc):
+      logging.error('Trying to commit when not running on the buildbot')
+      return False
+    self._orderfile_updater._CommitStashedFiles([
+        filename + '.sha1'
+        for filename in (self._GetUnpatchedOrderfileFilename(),
+                         self._GetPathToOrderfile())])
+    return True
+
 
 def CreateArgumentParser():
   """Creates and returns the argument parser."""
@@ -906,6 +972,11 @@
                             'orderfiles (both patched and unpatched) from '
                             'their normal location in the tree to the cloud '
                             'storage. DANGEROUS! USE WITH CARE!'))
+  parser.add_argument('--commit-hashes', action='store_true',
+                      help=('Commit any orderfile hash files in the current '
+                            'checkout; performs no other action'))
+  parser.add_argument('--new-commit-flow', action='store_true',
+                      help='Use the new two-step commit flow.')
 
   profile_android_startup.AddProfileCollectionArguments(parser)
   return parser
@@ -928,6 +999,10 @@
   try:
     if options.verify:
       generator._VerifySymbolOrder()
+    elif options.commit_hashes:
+      if not options._new_commit_flow:
+        raise Exception('--commit-hashes requries --new-commit-flow')
+      return generator.CommitStashedOrderfileHashes()
     elif options.upload_ready_orderfiles:
       return generator.UploadReadyOrderfiles()
     else:
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index d8bcbbc..68a70e9 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -729,9 +729,6 @@
       # on the continuous builder.
       'linux_chromium_msan_rel_ng': 'msan_release_bot',
 
-      # TODO(crbug.com/888810): Remove this entry once bot named is switched
-      # source side.
-      'linux_chromium_rel_ng': 'gpu_tests_release_trybot_no_symbols_use_dummy_lastchange',
       'linux_chromium_tsan_rel_ng': 'tsan_disable_nacl_release_trybot',
       'linux_chromium_ubsan_rel_ng': 'ubsan_vptr_release_trybot',
       'linux_layout_tests_composite_after_paint': 'release_trybot',
@@ -759,9 +756,6 @@
       'mac_chromium_compile_dbg_ng': 'gpu_tests_debug_trybot',
       'mac_chromium_compile_rel_ng': 'gpu_tests_release_trybot',
       'mac_chromium_dbg_ng': 'gpu_tests_debug_trybot',
-      # TODO(crbug.com/888810): Remove this entry once bot named is switched
-      # source side.
-      'mac_chromium_rel_ng': 'gpu_tests_release_trybot',
       'mac_optional_gpu_tests_rel': 'gpu_fyi_tests_release_trybot',
       'mac_upload_clang': 'release_bot',
       'mac-rel': 'gpu_tests_release_trybot',
@@ -778,9 +772,6 @@
 
     'tryserver.chromium.win': {
       'gpu_manual_try_win7_nvidia_rel': 'gpu_fyi_tests_release_trybot_x86',
-      # TODO(crbug.com/888810): Remove this entry once bot named is switched
-      # source side.
-      'win7_chromium_rel_ng': 'gpu_tests_release_trybot_x86_minimal_symbols_resource_whitelisting',
       'win7_chromium_rel_loc_exp': 'gpu_tests_release_trybot_x86_minimal_symbols_resource_whitelisting',
       'win10_chromium_x64_dbg_ng': 'gpu_tests_debug_trybot',
       'win10_chromium_x64_rel_ng': 'gpu_tests_release_trybot_resource_whitelisting',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 7608af7f..55a9ba7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -13368,6 +13368,14 @@
   <int value="354" label="ppsm"/>
   <int value="355" label="pps"/>
   <int value="356" label="mobileconfig"/>
+  <int value="357" label="dylib"/>
+  <int value="358" label="service"/>
+  <int value="359" label="definition"/>
+  <int value="360" label="wflow"/>
+  <int value="361" label="caction"/>
+  <int value="362" label="configprofile"/>
+  <int value="363" label="internetconnect"/>
+  <int value="364" label="networkconnect"/>
 </enum>
 
 <enum name="DownloadItem.DangerType">
@@ -25569,6 +25577,7 @@
   <int value="7" label="Testing GC"/>
   <int value="8" label="Incremental idle GC"/>
   <int value="9" label="Incremental v8 follow-up GC"/>
+  <int value="10" label="Unified heap GC"/>
 </enum>
 
 <enum name="GDataAuthResult">
@@ -48243,6 +48252,14 @@
   <int value="354" label="PPSM"/>
   <int value="355" label="PPS"/>
   <int value="356" label="MOBILECONFIG"/>
+  <int value="357" label="DYLIB"/>
+  <int value="358" label="SERVICE"/>
+  <int value="359" label="DEFINITION"/>
+  <int value="360" label="WFLOW"/>
+  <int value="361" label="CACTION"/>
+  <int value="362" label="CONFIGPROFILE"/>
+  <int value="363" label="INTERNETCONNECT"/>
+  <int value="364" label="NETWORKCONNECT"/>
 </enum>
 
 <enum name="SBClientDownloadIsSignedBinary">
@@ -48739,6 +48756,9 @@
 </enum>
 
 <enum name="SendPasswordFormToBrowserProcess">
+  <obsolete>
+    Removed from code March 2019.
+  </obsolete>
   <int value="0" label="Wasn't sent"/>
   <int value="1" label="Sent, only_visible == true"/>
   <int value="2" label="Sent, newly added form"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3cf933f..0bf7bbc4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -19778,6 +19778,15 @@
   </summary>
 </histogram>
 
+<histogram name="Cryptohome.AsyncDBusRequest.Inqueue" units="ms"
+    expires_after="2020-01-01">
+  <owner>menghuan@chromium.org</owner>
+  <summary>
+    Records the total inqueue time of every async dbus calls of Cryptohome at
+    server side. Recorded when the first stage of this requests is served.
+  </summary>
+</histogram>
+
 <histogram name="Cryptohome.ChecksumStatus" enum="CryptohomeChecksumStatus">
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec@chromium.org</owner>
@@ -41286,6 +41295,9 @@
 
 <histogram name="HeavyPageCapping.BlacklistReason" enum="OptOutBlacklistReason"
     expires_after="M75">
+  <obsolete>
+    Deprecated 3/2019.
+  </obsolete>
   <owner>ryansturm@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -41298,6 +41310,9 @@
 
 <histogram name="HeavyPageCapping.InfoBarInteraction"
     enum="HeavyPageCappingInfoBarInteraction" expires_after="M75">
+  <obsolete>
+    Deprecated 3/2019.
+  </obsolete>
   <owner>ryansturm@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -41307,6 +41322,9 @@
 
 <histogram name="HeavyPageCapping.RecordedDataSavings" units="KB"
     expires_after="M75">
+  <obsolete>
+    Deprecated 3/2019.
+  </obsolete>
   <owner>ryansturm@chromium.org</owner>
   <summary>
     Records the data savings due to heavy page capping. This is recorded when
@@ -83778,6 +83796,9 @@
 
 <histogram name="PasswordManager.SendPasswordFormToBrowserProcess"
     enum="SendPasswordFormToBrowserProcess" expires_after="M74">
+  <obsolete>
+    Deprecated 03/2019.
+  </obsolete>
   <owner>dvadym@chromium.org</owner>
   <owner>miniailau@google.com</owner>
   <summary>
@@ -95694,6 +95715,9 @@
 <histogram base="true"
     name="RendererScheduler.ExpectedQueueingTimeByFrameStatus2"
     units="microseconds">
+  <obsolete>
+    Removed March 2019.
+  </obsolete>
   <owner>npm@chromium.org</owner>
   <owner>tdresser@chromium.org</owner>
   <summary>
@@ -136230,6 +136254,7 @@
   <suffix name="PreciseGC" label="Precise GC"/>
   <suffix name="Testing" label="Testing GC"/>
   <suffix name="ThreadTerminationGC" label="Thread termination GC"/>
+  <suffix name="UnifiedHeapGC" label="Unified heap GC"/>
   <affected-histogram name="BlinkGC.AtomicPhaseMarking"/>
   <affected-histogram name="BlinkGC.CollectionRate"/>
   <affected-histogram name="BlinkGC.TimeForTotalCollectGarbage"/>
@@ -137124,6 +137149,7 @@
   <suffix name="TpmAttestationSignEnterpriseVaChallenge"/>
   <suffix name="TpmAttestationSignSimpleChallenge"/>
   <affected-histogram name="Cryptohome.AsyncDBusRequest"/>
+  <affected-histogram name="Cryptohome.AsyncDBusRequest.Inqueue"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="CryptohomeClientDBusMethod" separator=".">
@@ -145848,6 +145874,9 @@
 
 <histogram_suffixes name="RendererScheduler.ExpectedQueueingTime.FrameSplit"
     separator=".">
+  <obsolete>
+    Removed March 2019.
+  </obsolete>
   <suffix name="CrossOriginBackground"
       label="Expected Queueing Time from cross-origin backgrounded frames."/>
   <suffix name="CrossOriginHidden"
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 09c67ae..ea7fe75e 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -4321,6 +4321,9 @@
 </event>
 
 <event name="PageLoadCapping" singular="True">
+  <obsolete>
+    Deprecated as of 3/2019.
+  </obsolete>
   <owner>ryansturm@chromium.org</owner>
   <summary>
     Metrics related to PageLoadCapping that are recorded using the same UKM IDs
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn
index 7996169..f5cc7c7a 100644
--- a/tools/perf/contrib/vr_benchmarks/BUILD.gn
+++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -4,14 +4,13 @@
 
 import("//chrome/browser/vr/features.gni")
 
-assert(is_android)
-
 group("vr_perf_tests") {
   testonly = true
   data = [
     "./data/",
+    "./desktop_runtimes/",
     "./__init__.py",
-    "./shared_android_vr_page_state.py",
+    "./shared_vr_page_state.py",
     "./vr_benchmarks.py",
     "./vr_browsing_mode_pages.py",
     "./vr_sample_page.py",
@@ -19,26 +18,33 @@
     "./webvr_sample_pages.py",
     "./webvr_wpr_pages.py",
     "./webxr_sample_pages.py",
-    "//chrome/android/shared_preference_files/test/",
-    "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-    "//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
     "//chrome/test/data/xr/webvr_info/samples/",
     "//third_party/webxr_test_pages/webxr-samples",
   ]
   data_deps = [
-    "//chrome/android:vr_nfc_simulator_apk",
     "//testing:run_perf_test",
   ]
 
-  # We'll only ever use the assets if it's a Chrome-branded build. We don't have
-  # a way of checking whether the files are actually present to copy, but the
-  # script will deal with that.
-  if (use_vr_assets_component) {
-    data_deps += [ ":generate_vr_assets_profile" ]
-  }
   deps = [
     "//tools/perf:perf",
   ]
+
+  if (is_android) {
+    data += [
+      "//chrome/android/shared_preference_files/test/",
+      "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+      "//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
+    ]
+
+    data_deps += [ "//chrome/android:vr_nfc_simulator_apk" ]
+
+    # We'll only ever use the assets if it's a Chrome-branded build. We don't have
+    # a way of checking whether the files are actually present to copy, but the
+    # script will deal with that.
+    if (use_vr_assets_component) {
+      data_deps += [ ":generate_vr_assets_profile" ]
+    }
+  }
 }
 
 # Copies files to the gen/ directory and creates a manifest so that the VR
diff --git a/tools/perf/contrib/vr_benchmarks/desktop_runtimes/__init__.py b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/__init__.py
diff --git a/tools/perf/contrib/vr_benchmarks/desktop_runtimes/base_runtime.py b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/base_runtime.py
new file mode 100644
index 0000000..a4db125
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/base_runtime.py
@@ -0,0 +1,39 @@
+# 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.
+
+class DesktopRuntimeBase(object):
+  """Interface for all desktop VR runtimes."""
+
+  def __init__(self, finder_options):
+    self._finder_options = finder_options
+
+  def Setup(self):
+    """Called once before any stories are run."""
+    self._finder_options.browser_options.AppendExtraBrowserArgs(
+        '--enable-features=%s' % self.GetFeatureName())
+    self._SetupInternal()
+
+  def _SetupInternal(self):
+    raise NotImplementedError(
+        'No runtime setup defined for %s' % self.__class__.__name__)
+
+  def WillRunStory(self):
+    """Called before each story is run."""
+    self._WillRunStoryInternal()
+
+  def _WillRunStoryInternal(self):
+    raise NotImplementedError(
+        'No runtime pre-story defined for %s' % self.__class__.__name__)
+
+  def TearDown(self):
+    """Called once after all stories are run."""
+    self._TearDownInternal()
+
+  def _TearDownInternal(self):
+    raise NotImplementedError(
+        'No runtime tear down defined for %s' % self.__class__.__name__)
+
+  def GetFeatureName(self):
+    raise NotImplementedError(
+        'No feature defined for %s' % self.__class__.__name__)
diff --git a/tools/perf/contrib/vr_benchmarks/desktop_runtimes/oculus_runtimes.py b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/oculus_runtimes.py
new file mode 100644
index 0000000..d4ae033
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/oculus_runtimes.py
@@ -0,0 +1,64 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import subprocess
+from contrib.vr_benchmarks.desktop_runtimes import base_runtime
+
+
+# pylint: disable=abstract-method
+class _BaseOculusRuntime(base_runtime.DesktopRuntimeBase):
+  """Base class for all Oculus runtimes."""
+
+  def __init__(self, *args, **kwargs):
+    super(_BaseOculusRuntime, self).__init__(*args, **kwargs)
+
+  def GetFeatureName(self):
+    return 'OculusVR'
+
+
+class OculusRuntimeReal(_BaseOculusRuntime):
+  """Class for using the real Oculus runtime for desktop tests."""
+
+  OCULUS_BASE_ENVIRONMENT_VARIABLE = 'OculusBase'
+
+  def __init__(self, *args, **kwargs):
+    super(OculusRuntimeReal, self).__init__(*args, **kwargs)
+    self._runtime_handle = None
+
+  def _SetupInternal(self):
+    # We need to launch the Oculus client before running any tests to ensure
+    # that the runtime is ready when we try to enter VR.
+    self._runtime_handle = subprocess.Popen([self._GetOculusClientPath()])
+
+  def _WillRunStoryInternal(self):
+    if not self._runtime_handle:
+      raise RuntimeError(
+          'Somehow called real Oculus pre-story without calling setup')
+    if self._runtime_handle.poll() != None:
+      logging.warning(
+          'Oculus client closed prematurely with code %d, restarting',
+          self._runtime_handle.returncode)
+      self._runtime_handle = subprocess.Popen([self._GetOculusClientPath()])
+
+  def _TearDownInternal(self):
+    if not self._runtime_handle:
+      raise RuntimeError(
+          'Somehow called real Oculus tear down without calling setup')
+    if self._runtime_handle.poll() is None:
+      self._runtime_handle.terminate()
+
+  def _GetOculusClientPath(self):
+    # The install location of the Oculus runtime is set in the OculusBase
+    # environment variable at install time.
+    if self.OCULUS_BASE_ENVIRONMENT_VARIABLE not in os.environ:
+      raise RuntimeError('Failed to find the Oculus install location. Are you '
+                         'sure it\'s installed?')
+    return os.path.join(os.environ[self.OCULUS_BASE_ENVIRONMENT_VARIABLE],
+                        'Support', 'oculus-client', 'OculusClient.exe')
+
+
+class OculusRuntimeMock(base_runtime.DesktopRuntimeBase):
+  """Class for using a mock Oculus runtime for desktop tests."""
diff --git a/tools/perf/contrib/vr_benchmarks/desktop_runtimes/openvr_runtimes.py b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/openvr_runtimes.py
new file mode 100644
index 0000000..340cbea
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/openvr_runtimes.py
@@ -0,0 +1,21 @@
+# 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.
+
+from contrib.vr_benchmarks.desktop_runtimes import base_runtime
+
+
+# pylint: disable=abstract-method
+class _OpenVRRuntimeBase(base_runtime.DesktopRuntimeBase):
+  """Base class for all OpenVR runtimes."""
+
+  def GetFeatureName(self):
+    return 'OpenVR'
+
+
+class OpenVRRuntimeReal(_OpenVRRuntimeBase):
+  """Class for using the real OpenVR runtime for desktop tests."""
+
+
+class OpenVRRuntimeMock(_OpenVRRuntimeBase):
+  """Class for using the mock OpenVR runtime for desktop tests."""
diff --git a/tools/perf/contrib/vr_benchmarks/desktop_runtimes/wmr_runtimes.py b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/wmr_runtimes.py
new file mode 100644
index 0000000..f36dfd168
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/desktop_runtimes/wmr_runtimes.py
@@ -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.
+
+from contrib.vr_benchmarks.desktop_runtimes import base_runtime
+
+
+# pylint: disable=abstract-method
+class _WMRRuntimeBase(base_runtime.DesktopRuntimeBase):
+  """Base class for all WMR runtimes."""
+
+  def GetFeatureName(self):
+    return 'WindowsMixedReality'
+
+
+class WMRRuntimeReal(_WMRRuntimeBase):
+  """Class for using the real Windows Mixed Reality runtime for desktop tests.
+  """
+
+
+class WMRRuntimeMock(_WMRRuntimeBase):
+  """Class for using the mock Windows Mixed Reality runtime for desktop tests.
+  """
diff --git a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
deleted file mode 100644
index fce84e74..0000000
--- a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
+++ /dev/null
@@ -1,206 +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.
-
-import os
-from core import path_util
-from devil.android.sdk import intent  # pylint: disable=import-error
-path_util.AddAndroidPylibToPath()
-from pylib.utils import shared_preference_utils
-from telemetry.core import android_platform
-from telemetry.core import platform
-from telemetry.core import util
-from telemetry.internal.platform import android_device
-from telemetry.page import shared_page_state
-
-
-CARDBOARD_PATH = os.path.join('chrome', 'android', 'shared_preference_files',
-                              'test', 'vr_cardboard_skipdon_setupcomplete.json')
-FAKE_TRACKER_COMPONENT = ('com.google.vr.vrcore/'
-                          '.tracking.HeadTrackingService')
-SUPPORTED_POSE_TRACKER_MODES = [
-    'frozen',          # Static pose looking straight forward.
-    'sweep',           # Moves head back and forth horizontally.
-    'rotate',          # Moves head continuously in a circle.
-    'circle_strafe',   # Moves head continuously in a circle (also changes
-                       # position if 6DoF supported?).
-    'motion_sickness', # Moves head in a sort of figure-eight pattern.
-]
-SUPPORTED_POSE_TRACKER_TYPES = [
-    'sensor',    # Standard sensor-fusion-based pose tracker.
-    'tango',     # Tango-based pose tracker.
-    'platform',  # ?
-    'fake',      # Fake pose tracker that can provide pre-defined pose sets.
-]
-
-
-class SharedAndroidVrPageState(shared_page_state.SharedPageState):
-  """SharedPageState for VR Telemetry tests.
-
-  Performs the same functionality as SharedPageState, but with three main
-  differences:
-  1. It is currently restricted to Android
-  2. It performs VR-specific setup such as installing and configuring
-     additional APKs that are necessary for testing
-  3. It cycles the screen off then on before each story, similar to how
-     AndroidScreenRestorationSharedState ensures that the screen is on. See
-     _CycleScreen() for an explanation on the reasoning behind this.
-  """
-  def __init__(self, test, finder_options, story_set, possible_browser=None):
-    # TODO(bsheedy): See about making this a cross-platform SharedVrPageState -
-    # Seems like we should be able to use SharedPageState's default platform
-    # property instead of specifying AndroidPlatform, and then just perform
-    # different setup based off the platform type
-    device = android_device.GetDevice(finder_options)
-    assert device, 'Android device is required for this story'
-    self._platform = platform.GetPlatformForDevice(device, finder_options)
-    assert self._platform, 'Unable to create Android platform'
-    assert isinstance(self._platform, android_platform.AndroidPlatform)
-
-    super(SharedAndroidVrPageState, self).__init__(
-        test, finder_options, story_set, possible_browser)
-    self._story_set = story_set
-    # Optimization so we're not doing redundant service starts before every
-    # story.
-    self._did_set_tracker = False
-    self._PerformAndroidVrSetup()
-
-  def _PerformAndroidVrSetup(self):
-    if not self._finder_options.disable_vrcore_install:
-      self._InstallVrCore()
-    self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(),
-                                       self._finder_options.shared_prefs_file))
-    self._InstallNfcApk()
-    if not self._finder_options.disable_keyboard_install:
-      self._InstallKeyboardApk()
-
-  def _InstallVrCore(self):
-    """Installs the VrCore APK."""
-    # TODO(bsheedy): Add support for temporarily replacing it if it's still
-    # installed as a system app on the test device
-    self._platform.InstallApplication(
-        os.path.join(path_util.GetChromiumSrcDir(), 'third_party',
-                     'gvr-android-sdk', 'test-apks', 'vr_services',
-                     'vr_services_current.apk'))
-
-  def _ConfigureVrCore(self, filepath):
-    """Configures VrCore using the provided settings file."""
-    settings = shared_preference_utils.ExtractSettingsFromJson(filepath)
-    for setting in settings:
-      shared_pref = self._platform.GetSharedPrefs(
-          setting['package'], setting['filename'],
-          use_encrypted_path=setting.get('supports_encrypted_path', False))
-      shared_preference_utils.ApplySharedPreferenceSetting(
-          shared_pref, setting)
-
-  def _InstallNfcApk(self):
-    """Installs the APK that allows VR tests to simulate a headset NFC scan."""
-    chromium_root = path_util.GetChromiumSrcDir()
-    # Find the most recently build APK
-    candidate_apks = []
-    for build_path in util.GetBuildDirectories(chromium_root):
-      apk_path = os.path.join(build_path, 'apks', 'VrNfcSimulator.apk')
-      if os.path.exists(apk_path):
-        last_changed = os.path.getmtime(apk_path)
-        candidate_apks.append((last_changed, apk_path))
-
-    if not candidate_apks:
-      raise RuntimeError(
-          'Could not find VrNfcSimulator.apk in a build output directory')
-    newest_apk_path = sorted(candidate_apks)[-1][1]
-    self._platform.InstallApplication(
-        os.path.join(chromium_root, newest_apk_path))
-
-  def _InstallKeyboardApk(self):
-    """Installs the VR Keyboard APK."""
-    self._platform.InstallApplication(
-        os.path.join(path_util.GetChromiumSrcDir(), 'third_party',
-                     'gvr-android-sdk', 'test-apks', 'vr_keyboard',
-                     'vr_keyboard_current.apk'))
-
-  def _SetFakePoseTrackerIfNotSet(self):
-    if self._story_set.use_fake_pose_tracker and not self._did_set_tracker:
-      self.SetPoseTrackerType('fake')
-      self.SetPoseTrackerMode('sweep')
-      self._did_set_tracker = True
-
-  def SetPoseTrackerType(self, tracker_type):
-    """Sets the VrCore pose tracker to the given type.
-
-    Only works if VrCore has been configured to use the VrCore-side tracker
-    by setting EnableVrCoreHeadTracking to true. This setting persists between
-    VR sessions and Chrome restarts.
-
-    Args:
-      tracker_type: A string corresponding to the tracker type to set.
-
-    Raises:
-      RuntimeError if the given |tracker_type| is not in the supported list.
-    """
-    if tracker_type not in SUPPORTED_POSE_TRACKER_TYPES:
-      raise RuntimeError('Given tracker %s is not supported.' % tracker_type)
-    self.platform.StartAndroidService(start_intent=intent.Intent(
-        action='com.google.vr.vrcore.SET_TRACKER_TYPE',
-        component=FAKE_TRACKER_COMPONENT,
-        extras={'com.google.vr.vrcore.TRACKER_TYPE': tracker_type}))
-
-  def SetPoseTrackerMode(self, tracker_mode):
-    """Sets the fake VrCore pose tracker to provide poses in the given mode.
-
-    Only works after SetPoseTrackerType has been set to 'fake'. This setting
-    persists between VR sessions and Chrome restarts.
-
-    Args:
-      tracker_mode: A string corresponding to the tracker mode to set.
-
-    Raises:
-      RuntimeError if the given |tracker_mode| is not in the supported list.
-    """
-    if tracker_mode not in SUPPORTED_POSE_TRACKER_MODES:
-      raise RuntimeError('Given mode %s is not supported.' % tracker_mode)
-    self.platform.StartAndroidService(start_intent=intent.Intent(
-        action='com.google.vr.vrcore.SET_FAKE_TRACKER_MODE',
-        component=FAKE_TRACKER_COMPONENT,
-        extras={'com.google.vr.vrcore.FAKE_TRACKER_MODE': tracker_mode}))
-
-  def WillRunStory(self, page):
-    super(SharedAndroidVrPageState, self).WillRunStory(page)
-    if not self._finder_options.disable_screen_reset:
-      self._CycleScreen()
-    self._SetFakePoseTrackerIfNotSet()
-
-  def TearDownState(self):
-    super(SharedAndroidVrPageState, self).TearDownState()
-    # Reset the tracker type to use the actual sensor if it's been changed. When
-    # run on the bots, this shouldn't matter since the service will be killed
-    # during the automatic restart, but this could persist when run locally.
-    if self._did_set_tracker:
-      self.SetPoseTrackerType('sensor')
-    # Re-apply Cardboard as the viewer to leave the device in a consistent
-    # state after a benchmark run
-    # TODO(bsheedy): Remove this after crbug.com/772969 is fixed
-    self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(),
-                                       CARDBOARD_PATH))
-
-  def _CycleScreen(self):
-    """Cycles the screen off then on.
-
-    This is because VR test devices are set to have normal screen brightness and
-    automatically turn off after several minutes instead of the usual approach
-    of having the screen always on at minimum brightness. This is due to the
-    motion-to-photon latency test being sensitive to screen brightness, and min
-    brightness does not work well for it.
-
-    Simply using TurnScreenOn does not actually reset the timer for turning off
-    the screen, so instead cycle the screen to refresh it periodically.
-    """
-    self.platform.android_action_runner.TurnScreenOff()
-    self.platform.android_action_runner.TurnScreenOn()
-
-  @property
-  def platform(self):
-    return self._platform
-
-  @property
-  def recording_wpr(self):
-    return self._finder_options.recording_wpr
diff --git a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
new file mode 100644
index 0000000..720a922
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
@@ -0,0 +1,210 @@
+# 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.
+
+import os
+from core import path_util
+path_util.AddAndroidPylibToPath()
+from pylib.utils import shared_preference_utils
+from telemetry.core import android_platform
+from telemetry.core import util
+from telemetry.page import shared_page_state
+from contrib.vr_benchmarks.desktop_runtimes import oculus_runtimes
+from contrib.vr_benchmarks.desktop_runtimes import openvr_runtimes
+from contrib.vr_benchmarks.desktop_runtimes import wmr_runtimes
+
+
+CARDBOARD_PATH = os.path.join('chrome', 'android', 'shared_preference_files',
+                              'test', 'vr_cardboard_skipdon_setupcomplete.json')
+
+
+class SharedVrPageStateFactory(shared_page_state.SharedPageState):
+  """"Factory" for picking the correct SharedVrPageState subclass.
+
+  This is a hacky way to automatically change the shared page state that's used
+  depending on which platform the benchmark is being run on. The
+  shared_page_state_class that gets passed to the Page constructor must be an
+  instance of SharedState, so we can't just pass a function pointer that returns
+  an instance of the correct subclass when called.
+
+  Additionally, we only really know what platform we're being run on after
+  SharedPageState's constructor is called, as we can't rely on the given
+  possible_browser to determine it.
+
+  So, we have to call SharedPageState's constructor, find out which platform
+  we're being run on, switch our class out for the correct one, and
+  re-construct ourselves.
+  """
+  def __init__(self, test, finder_options, story_set, possible_browser=None):
+    super(SharedVrPageStateFactory, self).__init__(
+        test, finder_options, story_set, possible_browser)
+
+    if isinstance(self.platform, android_platform.AndroidPlatform):
+      self.__class__ = AndroidSharedVrPageState
+    elif self.platform.GetOSName().lower() == 'win':
+      self.__class__ = WindowsSharedVrPageState
+    else:
+      raise NotImplementedError(
+          'No VR SharedPageState implemented for platform %s' %
+          self.platform.GetOSName())
+    # Use self._possible_browser to avoid duplicate computation if
+    # possible_browser is None.
+    self.__init__(test, finder_options, story_set, self._possible_browser)
+
+
+class _SharedVrPageState(shared_page_state.SharedPageState):
+  """Abstract, platform-independent SharedPageState for VR tests.
+
+  Must be subclassed for each platform, since VR setup and tear down differs
+  between each.
+  """
+  def __init__(self, test, finder_options, story_set, possible_browser=None):
+    super(_SharedVrPageState, self).__init__(
+        test, finder_options, story_set, possible_browser)
+    self._story_set = story_set
+
+  @property
+  def recording_wpr(self):
+    return self._finder_options.recording_wpr
+
+
+class AndroidSharedVrPageState(_SharedVrPageState):
+  """Android-specific VR SharedPageState.
+
+  Platform-specific functionality:
+  1. Performs Android VR-specific setup such as installing and configuring
+     additional APKs that are necessary for testing.
+  2. Cycles the screen off then on before each story, similar to how
+     AndroidScreenRestorationSharedState ensures that the screen is on. See
+     _CycleScreen() for an explanation on the reasoning behind this.
+  """
+  def __init__(self, test, finder_options, story_set, possible_browser=None):
+    super(AndroidSharedVrPageState, self).__init__(
+        test, finder_options, story_set, possible_browser)
+    if not self._finder_options.disable_vrcore_install:
+      self._InstallVrCore()
+    self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(),
+                                       self._finder_options.shared_prefs_file))
+    self._InstallNfcApk()
+    if not self._finder_options.disable_keyboard_install:
+      self._InstallKeyboardApk()
+
+  def _InstallVrCore(self):
+    """Installs the VrCore APK."""
+    self.platform.InstallApplication(
+        os.path.join(path_util.GetChromiumSrcDir(), 'third_party',
+                     'gvr-android-sdk', 'test-apks', 'vr_services',
+                     'vr_services_current.apk'))
+
+  def _ConfigureVrCore(self, filepath):
+    """Configures VrCore using the provided settings file."""
+    settings = shared_preference_utils.ExtractSettingsFromJson(filepath)
+    for setting in settings:
+      shared_pref = self.platform.GetSharedPrefs(
+          setting['package'], setting['filename'],
+          use_encrypted_path=setting.get('supports_encrypted_path', False))
+      shared_preference_utils.ApplySharedPreferenceSetting(
+          shared_pref, setting)
+
+  def _InstallNfcApk(self):
+    """Installs the APK that allows VR tests to simulate a headset NFC scan."""
+    chromium_root = path_util.GetChromiumSrcDir()
+    # Find the most recently build APK
+    candidate_apks = []
+    for build_path in util.GetBuildDirectories(chromium_root):
+      apk_path = os.path.join(build_path, 'apks', 'VrNfcSimulator.apk')
+      if os.path.exists(apk_path):
+        last_changed = os.path.getmtime(apk_path)
+        candidate_apks.append((last_changed, apk_path))
+
+    if not candidate_apks:
+      raise RuntimeError(
+          'Could not find VrNfcSimulator.apk in a build output directory')
+    newest_apk_path = sorted(candidate_apks)[-1][1]
+    self.platform.InstallApplication(
+        os.path.join(chromium_root, newest_apk_path))
+
+  def _InstallKeyboardApk(self):
+    """Installs the VR Keyboard APK."""
+    self.platform.InstallApplication(
+        os.path.join(path_util.GetChromiumSrcDir(), 'third_party',
+                     'gvr-android-sdk', 'test-apks', 'vr_keyboard',
+                     'vr_keyboard_current.apk'))
+
+  def WillRunStory(self, page):
+    super(AndroidSharedVrPageState, self).WillRunStory(page)
+    if not self._finder_options.disable_screen_reset:
+      self._CycleScreen()
+
+  def TearDownState(self):
+    super(AndroidSharedVrPageState, self).TearDownState()
+    # Re-apply Cardboard as the viewer to leave the device in a consistent
+    # state after a benchmark run
+    # TODO(bsheedy): Remove this after crbug.com/772969 is fixed
+    self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(),
+                                       CARDBOARD_PATH))
+
+  def _CycleScreen(self):
+    """Cycles the screen off then on.
+
+    This is because VR test devices are set to have normal screen brightness and
+    automatically turn off after several minutes instead of the usual approach
+    of having the screen always on at minimum brightness. This is due to the
+    motion-to-photon latency test being sensitive to screen brightness, and min
+    brightness does not work well for it.
+
+    Simply using TurnScreenOn does not actually reset the timer for turning off
+    the screen, so instead cycle the screen to refresh it periodically.
+    """
+    self.platform.android_action_runner.TurnScreenOff()
+    self.platform.android_action_runner.TurnScreenOn()
+
+
+class WindowsSharedVrPageState(_SharedVrPageState):
+  """Windows-specific VR SharedPageState.
+
+  Platform-specific functionality involves starting and stopping different
+  VR runtimes before and after all stories are run.
+  """
+
+  # Constants to make the below map more readable
+  MOCK_RUNTIME = False
+  REAL_RUNTIME = True
+  # Map of runtime names to runtime classes for both real and mock
+  # implementations. Real runtimes require specialized hardware and software
+  # to be installed, i.e. exactly how a real user would use VR. Mock runtimes
+  # avoid this, but can't necessarily be implemented.
+  DESKTOP_RUNTIMES = {
+    'oculus': {
+      MOCK_RUNTIME: oculus_runtimes.OculusRuntimeMock,
+      REAL_RUNTIME: oculus_runtimes.OculusRuntimeReal,
+    },
+    'openvr': {
+      MOCK_RUNTIME: openvr_runtimes.OpenVRRuntimeMock,
+      REAL_RUNTIME: openvr_runtimes.OpenVRRuntimeReal
+    },
+    'wmr': {
+      MOCK_RUNTIME: wmr_runtimes.WMRRuntimeMock,
+      REAL_RUNTIME: wmr_runtimes.WMRRuntimeReal,
+    },
+  }
+
+  def __init__(self, test, finder_options, story_set, possible_browser):
+    super(WindowsSharedVrPageState, self).__init__(
+        test, finder_options, story_set, possible_browser)
+
+    # Get the specific runtime implementation depending on runtime choice and
+    # whether we're using the real or mock one.
+    self._desktop_runtime = self.DESKTOP_RUNTIMES[
+        self._finder_options.desktop_runtime][
+            self._finder_options.use_real_runtime](self._finder_options)
+    # Enable the correct feature for the specified runtime.
+    self._desktop_runtime.Setup()
+
+  def WillRunStory(self, page):
+    super(WindowsSharedVrPageState, self).WillRunStory(page)
+    self._desktop_runtime.WillRunStory()
+
+  def TearDownState(self):
+    super(WindowsSharedVrPageState, self).TearDownState()
+    self._desktop_runtime.TearDown()
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
index b212fdf..ae56555 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
@@ -11,6 +11,7 @@
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.timeline import chrome_trace_config
 from telemetry.web_perf import timeline_based_measurement
+from contrib.vr_benchmarks import shared_vr_page_state as vr_state
 from contrib.vr_benchmarks import vr_browsing_mode_pages
 from contrib.vr_benchmarks import webvr_sample_pages
 from contrib.vr_benchmarks import webvr_wpr_pages
@@ -19,6 +20,16 @@
 
 class _BaseVRBenchmark(perf_benchmark.PerfBenchmark):
 
+  # Trace categories that should be enabled for all VR benchmarks.
+  COMMON_TRACE_CATEGORIES = [
+      '-*', # Remove all default categories.
+      'blink.console', # Necessary for memory measurements.
+      'disabled-by-default-memory-infra', # Necessary for memory measurements.
+      'gpu', # Necessary for various VR metrics.
+      'toplevel', # Debug category.
+      'viz', # Debug category.
+    ]
+
   @classmethod
   def AddBenchmarkCommandLineArgs(cls, parser):
     parser.add_option(
@@ -59,24 +70,37 @@
              'for it. This largely boils down to adding waits/sleeps in order '
              'to ensure that enough streaming data is recorded for the '
              'benchmark to run without issues.')
+    parser.add_option(
+        '--desktop-runtime',
+        default='openvr',
+        choices=vr_state.WindowsSharedVrPageState.DESKTOP_RUNTIMES.keys(),
+        help='Which VR runtime to use on Windows. Defaults to %default')
+    parser.add_option(
+        '--use-real-runtime',
+        action='store_true',
+        default=False,
+        help='Use the real runtime instead of a mock implementation. This '
+             'requires the runtime to be installed on the system.')
 
 
 class _BaseWebVRWebXRBenchmark(_BaseVRBenchmark):
 
-  SUPPORTED_PLATFORMS = [story.expectations.ALL_ANDROID]
+  SUPPORTED_PLATFORMS = [
+      story.expectations.ALL_ANDROID,
+      story.expectations.WIN_10
+  ]
 
   def CreateCoreTimelineBasedMeasurementOptions(self):
-    memory_categories = ['blink.console', 'disabled-by-default-memory-infra']
-    gpu_categories = ['gpu']
-    debug_categories = ['toplevel', 'viz']
-    category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
-        ','.join(['-*'] + memory_categories + gpu_categories
-            + debug_categories))
+    category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter()
+    for category in self.COMMON_TRACE_CATEGORIES:
+      category_filter.AddFilter(category)
+
     options = timeline_based_measurement.Options(category_filter)
     options.config.enable_android_graphics_memtrack = True
     options.config.enable_platform_display_trace = True
 
-    options.SetTimelineBasedMetrics(['memoryMetric', 'webvrMetric'])
+    options.SetTimelineBasedMetrics(
+        ['memoryMetric', 'webvrMetric', 'webxrMetric'])
     options.config.chrome_trace_config.SetMemoryDumpConfig(
         chrome_trace_config.MemoryDumpConfig())
     return options
@@ -172,12 +196,10 @@
   SUPPORTED_PLATFORMS = [story.expectations.ALL_ANDROID]
 
   def CreateTimelineBasedMeasurementOptions(self):
-    memory_categories = ['blink.console', 'disabled-by-default-memory-infra']
-    gpu_categories = ['gpu']
-    debug_categories = ['toplevel', 'viz']
-    category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
-        ','.join(['-*'] + memory_categories + gpu_categories
-            + debug_categories))
+    category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter()
+    for category in self.COMMON_TRACE_CATEGORIES:
+      category_filter.AddFilter(category)
+
     options = timeline_based_measurement.Options(category_filter)
     options.config.enable_android_graphics_memtrack = True
     options.config.enable_platform_display_trace = True
diff --git a/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py b/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
index c555e7f..6aa1616b 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
@@ -8,7 +8,7 @@
 from telemetry import story
 from telemetry.page import shared_page_state
 from devil.android.sdk import intent  # pylint: disable=import-error
-from contrib.vr_benchmarks import shared_android_vr_page_state as vr_state
+from contrib.vr_benchmarks import shared_vr_page_state as vr_state
 from contrib.vr_benchmarks.vr_sample_page import VrSamplePage
 from contrib.vr_benchmarks.vr_story_set import VrStorySet
 from page_sets import top_10_mobile
@@ -72,7 +72,7 @@
         page_set=page_set,
         name=name,
         extra_browser_args=extra_browser_args,
-        shared_page_state_class=vr_state.SharedAndroidVrPageState)
+        shared_page_state_class=vr_state.AndroidSharedVrPageState)
     self._shared_page_state = None
 
   def RunPageInteractions(self, action_runner):
diff --git a/tools/perf/contrib/vr_benchmarks/vr_sample_page.py b/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
index 73a5f08..54390c0 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
@@ -5,8 +5,7 @@
 import os
 import re
 from telemetry import page
-from contrib.vr_benchmarks import (shared_android_vr_page_state as
-                                   vr_state)
+from contrib.vr_benchmarks import shared_vr_page_state as vr_state
 
 WEBVR_SAMPLE_DIR = os.path.join(
     os.path.dirname(__file__), '..', '..', '..', '..', 'chrome', 'test',
@@ -40,7 +39,7 @@
         page_set=page_set,
         name=name,
         extra_browser_args=extra_browser_args,
-        shared_page_state_class=vr_state.SharedAndroidVrPageState)
+        shared_page_state_class=vr_state.SharedVrPageStateFactory)
     self._shared_page_state = None
 
   def Run(self, shared_state):
diff --git a/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py b/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
index 965ff811..78d0965 100644
--- a/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
+++ b/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
@@ -4,7 +4,7 @@
 
 from telemetry import story
 from telemetry import page
-from contrib.vr_benchmarks import (shared_android_vr_page_state as vr_state)
+from contrib.vr_benchmarks import (shared_vr_page_state as vr_state)
 from contrib.vr_benchmarks.vr_story_set import VrStorySet
 
 class WebVrWprPage(page.Page):
@@ -27,7 +27,7 @@
         page_set=page_set,
         name=name,
         extra_browser_args=extra_browser_args,
-        shared_page_state_class=vr_state.SharedAndroidVrPageState)
+        shared_page_state_class=vr_state.SharedVrPageStateFactory)
     self._shared_page_state = None
     self._interaction_function = interaction_function
 
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 958680c2..8962670 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -285,6 +285,7 @@
 crbug.com/924330 [ Linux ] system_health.memory_desktop/browse:media:pinterest:2018 [ Skip ]
 crbug.com/927758 [ Desktop ] system_health.memory_desktop/load:games:alphabetty [ Skip ]
 crbug.com/934270 [ Win ] system_health.memory_desktop/multitab:misc:typical24:2018 [ Skip ]
+crbug.com/942952 [ ChromeOS ] system_health.memory_desktop/browse:news:hackernews:2018 [ Skip ]
 
 # Benchmark: system_health.memory_mobile
 crbug.com/787001 [ Android_Webview ] system_health.memory_mobile/load:media:soundcloud [ Skip ]
diff --git a/tools/protoc_wrapper/protoc_convert.py b/tools/protoc_wrapper/protoc_convert.py
new file mode 100644
index 0000000..1da63e4
--- /dev/null
+++ b/tools/protoc_wrapper/protoc_convert.py
@@ -0,0 +1,30 @@
+# 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.
+
+"""Helper script for use by GN to encode/decode proto files. The protoc tool
+requires using stdin/stdout for the --encode/--decode options, but that form
+of processing is not supported by GN.
+"""
+
+import argparse
+import subprocess
+
+def Main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--protoc', help='Path to protoc compiler.')
+  parser.add_argument('--infile', required=True,
+                      help='Path to input file that will be used as stdin.')
+  parser.add_argument('--outfile', required=True,
+                      help='Path to output file that will be used as stdout.')
+  args, passthrough_args = parser.parse_known_args()
+
+  stdin = open(args.infile, 'r')
+  stdout = open(args.outfile, 'w')
+
+  subprocess.check_call([args.protoc] + passthrough_args, stdin=stdin,
+      stdout=stdout)
+
+
+if __name__ == '__main__':
+  Main()
diff --git a/ui/android/java/res/color/text_button_ripple_color.xml b/ui/android/java/res/color/text_button_ripple_color.xml
index 59b2385a..e2a52d1 100644
--- a/ui/android/java/res/color/text_button_ripple_color.xml
+++ b/ui/android/java/res/color/text_button_ripple_color.xml
@@ -8,12 +8,12 @@
     xmlns:tools="http://schemas.android.com/tools"
     tools:ignore="UnusedResources">
     <item android:alpha="@dimen/default_pressed_alpha"
-        android:color="@color/modern_blue_600" android:state_pressed="true"/>
+        android:color="@color/ripple_color_blue" android:state_pressed="true"/>
     <item android:alpha="@dimen/default_focused_hovered_alpha"
-        android:color="@color/modern_blue_600" android:state_focused="true" android:state_hovered="true"/>
+        android:color="@color/ripple_color_blue" android:state_focused="true" android:state_hovered="true"/>
     <item android:alpha="@dimen/default_focused_alpha"
-        android:color="@color/modern_blue_600" android:state_focused="true"/>
+        android:color="@color/ripple_color_blue" android:state_focused="true"/>
     <item android:alpha="@dimen/default_hovered_alpha"
-        android:color="@color/modern_blue_600" android:state_hovered="true"/>
+        android:color="@color/ripple_color_blue" android:state_hovered="true"/>
     <item android:color="@android:color/transparent" />
 </selector>
\ No newline at end of file
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml
index 983634c..b17c215 100644
--- a/ui/android/java/res/values/colors.xml
+++ b/ui/android/java/res/values/colors.xml
@@ -53,5 +53,8 @@
 
     <color name="dropdown_divider_color">#E5E5E5</color>
     <color name="dropdown_dark_divider_color">#C0C0C0</color>
+
+    <!-- Ripple colors for clickable widgets -->
+    <color name="ripple_color_blue">@color/modern_blue_600</color>
 </resources>
 
diff --git a/ui/android/java/res_night/values-night/colors.xml b/ui/android/java/res_night/values-night/colors.xml
index 754a258..b3d577ad9 100644
--- a/ui/android/java/res_night/values-night/colors.xml
+++ b/ui/android/java/res_night/values-night/colors.xml
@@ -24,4 +24,7 @@
     <color name="default_bg_color_elev_2">@color/default_bg_color_dark_elev_2</color>
     <color name="default_bg_color_elev_3">@color/default_bg_color_dark_elev_3</color>
     <color name="default_bg_color_elev_4">@color/default_bg_color_dark_elev_4</color>
+
+    <!-- Ripple colors for clickable widgets -->
+    <color name="ripple_color_blue">@color/modern_blue_300</color>
 </resources>
\ No newline at end of file
diff --git a/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java b/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java
index d6e8d90..7dbc7d8 100644
--- a/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java
+++ b/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java
@@ -4,7 +4,6 @@
 
 package org.chromium.ui;
 
-import android.net.Uri;
 import android.support.annotation.IntDef;
 
 import java.lang.annotation.Retention;
@@ -39,5 +38,5 @@
      *
      * @param photos The photos that were selected.
      */
-    void onPhotoPickerUserAction(@PhotoPickerAction int action, Uri[] photos);
+    void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos);
 }
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
index ed3466cf..1c773bb 100644
--- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
+++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -376,7 +376,7 @@
     }
 
     @Override
-    public void onPhotoPickerUserAction(@PhotoPickerAction int action, Uri[] photos) {
+    public void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos) {
         switch (action) {
             case PhotoPickerAction.CANCEL:
                 onFileNotSelected();
@@ -388,9 +388,21 @@
                     return;
                 }
 
-                GetDisplayNameTask task = new GetDisplayNameTask(
-                        ContextUtils.getApplicationContext(), photos.length > 1, photos);
-                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+                if (photos.length == 1) {
+                    GetDisplayNameTask task =
+                            new GetDisplayNameTask(ContextUtils.getApplicationContext(), false,
+                                    new Uri[] {Uri.parse(photos[0])});
+                    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+                    return;
+                } else {
+                    Uri[] filePathArray = new Uri[photos.length];
+                    for (int i = 0; i < photos.length; ++i) {
+                        filePathArray[i] = Uri.parse(photos[i]);
+                    }
+                    GetDisplayNameTask task = new GetDisplayNameTask(
+                            ContextUtils.getApplicationContext(), true, filePathArray);
+                    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+                }
                 break;
 
             case PhotoPickerAction.LAUNCH_GALLERY:
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index f0b667d..75b03f4 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -239,6 +239,7 @@
         mOutstandingIntents = new SparseArray<>();
         mIntentErrors = new HashMap<>();
         mDisplayAndroid = display;
+        mDisplayAndroid.addObserver(this);
         // Temporary solution for flaky tests, see https://crbug.com/767624 for context
         try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
             mVSyncMonitor =
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc
index 9182c6b..19bf5ce 100644
--- a/ui/aura/client/aura_constants.cc
+++ b/ui/aura/client/aura_constants.cc
@@ -49,7 +49,7 @@
 DEFINE_UI_CLASS_PROPERTY_KEY(int, kAppType, 0)
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::SizeF, kAspectRatio, nullptr)
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAvatarIconKey, nullptr)
-DEFINE_UI_CLASS_PROPERTY_KEY(bool, kClientWindowHasContent, false)
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kWindowLayerDrawn, false)
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kConstrainedWindowKey, false)
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kCreatedByUserGesture, false)
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false)
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index f3acf3f..93dbe871 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -73,12 +73,10 @@
 // frame to indicate the owner of the window when needed.
 AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kAvatarIconKey;
 
-// A property key to indicate if a client window has content. The value is
-// based on whether the window has a drawn layer (i.e. layer type !=
-// LAYER_NOT_DRAWN) and is opaque. It is passed to the Window Service side for
-// the occlusion tracker to process since the info is only available at the
-// client side.
-AURA_EXPORT extern const WindowProperty<bool>* const kClientWindowHasContent;
+// A property key to indicate if a client window's layer is drawn.
+// It is passed to the Window Service side for the occlusion tracker to process
+// since the info is only available at the client side.
+AURA_EXPORT extern const WindowProperty<bool>* const kWindowLayerDrawn;
 
 // A property key to store if a window is a constrained window or not.
 AURA_EXPORT extern const WindowProperty<bool>* const kConstrainedWindowKey;
diff --git a/ui/aura/local/window_port_local.cc b/ui/aura/local/window_port_local.cc
index e11dbb6..a027312c 100644
--- a/ui/aura/local/window_port_local.cc
+++ b/ui/aura/local/window_port_local.cc
@@ -112,6 +112,8 @@
 
 void WindowPortLocal::OnVisibilityChanged(bool visible) {}
 
+void WindowPortLocal::OnTransparentChanged(bool visible) {}
+
 void WindowPortLocal::OnDidChangeBounds(const gfx::Rect& old_bounds,
                                         const gfx::Rect& new_bounds) {
   if (!window_->IsRootWindow() && last_size_ != new_bounds.size() &&
diff --git a/ui/aura/local/window_port_local.h b/ui/aura/local/window_port_local.h
index d0744d6b..059b731 100644
--- a/ui/aura/local/window_port_local.h
+++ b/ui/aura/local/window_port_local.h
@@ -38,6 +38,7 @@
   void OnWillRemoveChild(Window* child) override;
   void OnWillMoveChild(size_t current_index, size_t dest_index) override;
   void OnVisibilityChanged(bool visible) override;
+  void OnTransparentChanged(bool transparent) override;
   void OnDidChangeBounds(const gfx::Rect& old_bounds,
                          const gfx::Rect& new_bounds) override;
   void OnDidChangeTransform(const gfx::Transform& old_transform,
diff --git a/ui/aura/mus/in_flight_change.cc b/ui/aura/mus/in_flight_change.cc
index 5e28c14..69287bf 100644
--- a/ui/aura/mus/in_flight_change.cc
+++ b/ui/aura/mus/in_flight_change.cc
@@ -58,6 +58,8 @@
       return "TRANSFORM";
     case ChangeType::VISIBLE:
       return "VISIBLE";
+    case ChangeType::SET_TRANSPARENT:
+      return "SET_TRANSPARENT";
   }
 }
 
diff --git a/ui/aura/mus/in_flight_change.h b/ui/aura/mus/in_flight_change.h
index b9ae823..2c3591f6 100644
--- a/ui/aura/mus/in_flight_change.h
+++ b/ui/aura/mus/in_flight_change.h
@@ -53,6 +53,7 @@
   REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
   REORDER,
   SET_MODAL,
+  SET_TRANSPARENT,
   TRANSFORM,
   VISIBLE,
 };
diff --git a/ui/aura/mus/property_converter.cc b/ui/aura/mus/property_converter.cc
index cee64d4..5517fb3 100644
--- a/ui/aura/mus/property_converter.cc
+++ b/ui/aura/mus/property_converter.cc
@@ -116,8 +116,8 @@
       client::kChildModalParentKey,
       ws::mojom::WindowManager::kChildModalParent_Property);
   RegisterPrimitiveProperty(
-      client::kClientWindowHasContent,
-      ws::mojom::WindowManager::kClientWindowHasContent_Property,
+      client::kWindowLayerDrawn,
+      ws::mojom::WindowManager::kWindowLayerDrawn_Property,
       CreateAcceptAnyValueCallback());
 }
 
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index 8b4c1ba..7f4369c 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -303,6 +303,10 @@
         if (iter->data.visible == data.visible)
           return iter;
         break;
+      case ServerChangeType::SET_TRANSPARENT:
+        if (iter->data.transparent == data.transparent)
+          return iter;
+        break;
     }
   }
   return iter;
@@ -676,6 +680,15 @@
     window_tree_client_->OnWindowMusSetVisible(this, visible);
 }
 
+void WindowPortMus::OnTransparentChanged(bool transparent) {
+  ServerChangeData change_data;
+  change_data.transparent = transparent;
+  if (!RemoveChangeByTypeAndData(ServerChangeType::SET_TRANSPARENT,
+                                 change_data)) {
+    window_tree_client_->OnWindowMusSetTransparent(this, transparent);
+  }
+}
+
 void WindowPortMus::OnDidChangeBounds(const gfx::Rect& old_bounds,
                                       const gfx::Rect& new_bounds) {
   ServerChangeData change_data;
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h
index bd3878c..97cced4 100644
--- a/ui/aura/mus/window_port_mus.h
+++ b/ui/aura/mus/window_port_mus.h
@@ -148,6 +148,7 @@
     REMOVE,
     REMOVE_TRANSIENT,
     REORDER,
+    SET_TRANSPARENT,
     TRANSFORM,
     VISIBLE,
   };
@@ -164,6 +165,8 @@
     std::string property_name;
     // Applies to TRANSFORM.
     gfx::Transform transform;
+    // Applies to SET_TRANSPARENT.
+    bool transparent;
   };
 
   // Used to identify a change the server.
@@ -281,6 +284,7 @@
   void OnWillRemoveChild(Window* child) override;
   void OnWillMoveChild(size_t current_index, size_t dest_index) override;
   void OnVisibilityChanged(bool visible) override;
+  void OnTransparentChanged(bool transparent) override;
   void OnDidChangeBounds(const gfx::Rect& old_bounds,
                          const gfx::Rect& new_bounds) override;
   void OnDidChangeTransform(const gfx::Transform& old_transform,
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 69ac7c3..bec8477 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -754,7 +754,7 @@
   DCHECK(!IsRoot(window));
 
   window->GetWindow()->SetProperty(
-      aura::client::kClientWindowHasContent,
+      aura::client::kWindowLayerDrawn,
       window->GetWindow()->layer()->type() != ui::LAYER_NOT_DRAWN);
 
   PropertyConverter* property_converter = delegate_->GetPropertyConverter();
@@ -875,6 +875,17 @@
   tree_->SetWindowVisibility(change_id, window->server_id(), visible);
 }
 
+void WindowTreeClient::OnWindowMusSetTransparent(WindowMus* window,
+                                                 bool transparent) {
+  if (!WasCreatedByThisClient(window) && !IsRoot(window))
+    return;
+  DCHECK(tree_);
+  const uint32_t change_id =
+      ScheduleInFlightChange(std::make_unique<CrashInFlightChange>(
+          window, ChangeType::SET_TRANSPARENT));
+  tree_->SetWindowTransparent(change_id, window->server_id(), transparent);
+}
+
 std::unique_ptr<ui::PropertyData>
 WindowTreeClient::OnWindowMusWillChangeProperty(WindowMus* window,
                                                 const void* key) {
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index c7d27a6..ddaffb7 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -376,6 +376,7 @@
                             size_t current_index,
                             size_t dest_index);
   void OnWindowMusSetVisible(WindowMus* window, bool visible);
+  void OnWindowMusSetTransparent(WindowMus* window, bool transparent);
   std::unique_ptr<ui::PropertyData> OnWindowMusWillChangeProperty(
       WindowMus* window,
       const void* key);
diff --git a/ui/aura/test/mus/test_window_tree.cc b/ui/aura/test/mus/test_window_tree.cc
index e9b4ff8..757c5d7 100644
--- a/ui/aura/test/mus/test_window_tree.cc
+++ b/ui/aura/test/mus/test_window_tree.cc
@@ -226,6 +226,12 @@
   OnChangeReceived(change_id, WindowTreeChangeType::VISIBLE);
 }
 
+void TestWindowTree::SetWindowTransparent(uint32_t change_id,
+                                          ws::Id window_id,
+                                          bool transparent) {
+  OnChangeReceived(change_id);
+}
+
 void TestWindowTree::SetWindowProperty(
     uint32_t change_id,
     ws::Id window_id,
diff --git a/ui/aura/test/mus/test_window_tree.h b/ui/aura/test/mus/test_window_tree.h
index 084bfc4..e3d0103 100644
--- a/ui/aura/test/mus/test_window_tree.h
+++ b/ui/aura/test/mus/test_window_tree.h
@@ -217,6 +217,9 @@
   void SetWindowVisibility(uint32_t change_id,
                            ws::Id window_id,
                            bool visible) override;
+  void SetWindowTransparent(uint32_t change_id,
+                            ws::Id window_id,
+                            bool transparent) override;
   void SetWindowProperty(
       uint32_t change_id,
       ws::Id window_id,
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index fb8c9ed8..e382c1d 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -208,9 +208,13 @@
 }
 
 void Window::SetTransparent(bool transparent) {
+  if (transparent == transparent_)
+    return;
   transparent_ = transparent;
   if (layer())
     layer()->SetFillsBoundsOpaquely(!transparent_);
+  if (port_)
+    port_->OnTransparentChanged(transparent);
 }
 
 void Window::SetFillsBoundsCompletely(bool fills_bounds) {
diff --git a/ui/aura/window_port.h b/ui/aura/window_port.h
index d07c84d..4818b26 100644
--- a/ui/aura/window_port.h
+++ b/ui/aura/window_port.h
@@ -79,6 +79,7 @@
   virtual void OnWillMoveChild(size_t current_index, size_t dest_index) = 0;
 
   virtual void OnVisibilityChanged(bool visible) = 0;
+  virtual void OnTransparentChanged(bool transparent) = 0;
 
   virtual void OnDidChangeBounds(const gfx::Rect& old_bounds,
                                  const gfx::Rect& new_bounds) = 0;
diff --git a/ui/aura/window_port_for_shutdown.cc b/ui/aura/window_port_for_shutdown.cc
index 5ff4b04..9fff1cc 100644
--- a/ui/aura/window_port_for_shutdown.cc
+++ b/ui/aura/window_port_for_shutdown.cc
@@ -35,6 +35,8 @@
 
 void WindowPortForShutdown::OnVisibilityChanged(bool visible) {}
 
+void WindowPortForShutdown::OnTransparentChanged(bool transparent) {}
+
 void WindowPortForShutdown::OnDidChangeBounds(const gfx::Rect& old_bounds,
                                               const gfx::Rect& new_bounds) {}
 
diff --git a/ui/aura/window_port_for_shutdown.h b/ui/aura/window_port_for_shutdown.h
index 4d7bd08..15884cc 100644
--- a/ui/aura/window_port_for_shutdown.h
+++ b/ui/aura/window_port_for_shutdown.h
@@ -30,6 +30,7 @@
   void OnWillRemoveChild(Window* child) override;
   void OnWillMoveChild(size_t current_index, size_t dest_index) override;
   void OnVisibilityChanged(bool visible) override;
+  void OnTransparentChanged(bool transparent) override;
   void OnDidChangeBounds(const gfx::Rect& old_bounds,
                          const gfx::Rect& new_bounds) override;
   void OnDidChangeTransform(const gfx::Transform& old_transform,
diff --git a/ui/base/cocoa/base_view.h b/ui/base/cocoa/base_view.h
index 0675cae..a53f629 100644
--- a/ui/base/cocoa/base_view.h
+++ b/ui/base/cocoa/base_view.h
@@ -32,6 +32,12 @@
   NSInteger pressureEventStage_;
 }
 
+// Process an NSLeftMouseUp event on this view that wasn't dispatched already
+// to BaseView (e.g. if captured via an event monitor). This may generate a
+// synthetic NSMouseExited if the mouse exited the view area during a drag and
+// should be invoked after a call to -mouseEvent: for the mouse up.
+- (void)handleLeftMouseUp:(NSEvent*)theEvent;
+
 // Override these methods (mouseEvent, keyEvent, forceTouchEvent) in a
 // subclass.
 - (void)mouseEvent:(NSEvent *)theEvent;
diff --git a/ui/base/cocoa/base_view.mm b/ui/base/cocoa/base_view.mm
index 7cd59f8e..68cbcb2 100644
--- a/ui/base/cocoa/base_view.mm
+++ b/ui/base/cocoa/base_view.mm
@@ -71,6 +71,26 @@
   }
 }
 
+- (void)handleLeftMouseUp:(NSEvent*)theEvent {
+  DCHECK_EQ([theEvent type], NSLeftMouseUp);
+  dragging_ = NO;
+  if (!pendingExitEvent_)
+    return;
+
+  NSEvent* exitEvent =
+      [NSEvent enterExitEventWithType:NSMouseExited
+                             location:[theEvent locationInWindow]
+                        modifierFlags:[theEvent modifierFlags]
+                            timestamp:[theEvent timestamp]
+                         windowNumber:[theEvent windowNumber]
+                              context:[theEvent context]
+                          eventNumber:[pendingExitEvent_ eventNumber]
+                       trackingNumber:[pendingExitEvent_ trackingNumber]
+                             userData:[pendingExitEvent_ userData]];
+  [self mouseEvent:exitEvent];
+  pendingExitEvent_.reset();
+}
+
 - (void)mouseEvent:(NSEvent*)theEvent {
   // This method left intentionally blank.
 }
@@ -105,22 +125,7 @@
 
 - (void)mouseUp:(NSEvent*)theEvent {
   [self mouseEvent:theEvent];
-
-  dragging_ = NO;
-  if (pendingExitEvent_.get()) {
-    NSEvent* exitEvent =
-        [NSEvent enterExitEventWithType:NSMouseExited
-                               location:[theEvent locationInWindow]
-                          modifierFlags:[theEvent modifierFlags]
-                              timestamp:[theEvent timestamp]
-                           windowNumber:[theEvent windowNumber]
-                                context:[theEvent context]
-                            eventNumber:[pendingExitEvent_.get() eventNumber]
-                         trackingNumber:[pendingExitEvent_.get() trackingNumber]
-                               userData:[pendingExitEvent_.get() userData]];
-    [self mouseEvent:exitEvent];
-    pendingExitEvent_.reset();
-  }
+  [self handleLeftMouseUp:theEvent];
 }
 
 - (void)rightMouseUp:(NSEvent*)theEvent {
@@ -148,7 +153,7 @@
 }
 
 - (void)mouseEntered:(NSEvent*)theEvent {
-  if (pendingExitEvent_.get()) {
+  if (pendingExitEvent_) {
     pendingExitEvent_.reset();
     return;
   }
diff --git a/ui/base/idle/DEPS b/ui/base/idle/DEPS
index 351596fe..b145fbe 100644
--- a/ui/base/idle/DEPS
+++ b/ui/base/idle/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
   "+jni",
   "+chromeos/dbus/dbus_thread_manager.h",
-  "+chromeos/dbus/session_manager_client.h",
+  "+chromeos/dbus/session_manager",
 ]
diff --git a/ui/base/idle/idle_chromeos.cc b/ui/base/idle/idle_chromeos.cc
index 55b96ea..4fd2677 100644
--- a/ui/base/idle/idle_chromeos.cc
+++ b/ui/base/idle/idle_chromeos.cc
@@ -6,7 +6,7 @@
 
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
+#include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "ui/base/user_activity/user_activity_detector.h"
 
 namespace ui {
diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc
index 26e6ea2..a2aa2308 100644
--- a/ui/base/win/shell.cc
+++ b/ui/base/win/shell.cc
@@ -20,6 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/win/win_util.h"
+#include "base/win/windows_version.h"
 #include "ui/base/ui_base_switches.h"
 
 namespace ui {
@@ -178,8 +179,17 @@
     return false;
 
   // If composition is not enabled, we behave like on XP.
-  BOOL enabled = FALSE;
-  return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;
+  return IsDwmCompositionEnabled();
+}
+
+bool IsDwmCompositionEnabled() {
+  // As of Windows 8, DWM composition is always enabled.
+  // In Windows 7 this can change at runtime.
+  if (GetVersion() >= base::win::VERSION_WIN8) {
+    return true;
+  }
+  BOOL is_enabled;
+  return SUCCEEDED(DwmIsCompositionEnabled(&is_enabled)) && is_enabled;
 }
 
 }  // namespace win
diff --git a/ui/base/win/shell.h b/ui/base/win/shell.h
index 46b625c..5a91276 100644
--- a/ui/base/win/shell.h
+++ b/ui/base/win/shell.h
@@ -71,10 +71,15 @@
 // Clears the Window Property Store on an HWND.
 UI_BASE_EXPORT void ClearWindowPropertyStore(HWND hwnd);
 
-// Returns true if composition is available and turned on on the current
+// Returns true if dwm composition is available and turned on on the current
 // platform.
+// This method supports a command-line override for testing.
 UI_BASE_EXPORT bool IsAeroGlassEnabled();
 
+// Returns true if dwm composition is available and turned on on the current
+// platform.
+UI_BASE_EXPORT bool IsDwmCompositionEnabled();
+
 }  // namespace win
 }  // namespace ui
 
diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc
index 7a3bae1..92afeee 100644
--- a/ui/events/blink/blink_event_util.cc
+++ b/ui/events/blink/blink_event_util.cc
@@ -315,17 +315,9 @@
   }
 
   if (event.has_synthetic_phase) {
-    // Synthetic phase information is added based on a timer in
-    // MouseWheelPhaseHandler. This information is for simulating scroll
-    // sequences when the beginning and end of scrolls are not available. It is
-    // alright to coalesce an event with synthetic phaseBegan to its previous
-    // event with synthetic phaseEnded since these phase values don't correspond
-    // with real start and end of the scroll sequences.
-    // It is also alright to coalesce a wheel event with synthetic phaseChanged
-    // to its previous one with synthetic phaseBegan.
-    return (event.phase == WebMouseWheelEvent::kPhaseEnded &&
-            event_to_coalesce.phase == WebMouseWheelEvent::kPhaseBegan) ||
-           (event.phase == WebMouseWheelEvent::kPhaseBegan &&
+    // It is alright to coalesce a wheel event with synthetic phaseChanged to
+    // its previous one with synthetic phaseBegan.
+    return (event.phase == WebMouseWheelEvent::kPhaseBegan &&
             event_to_coalesce.phase == WebMouseWheelEvent::kPhaseChanged);
   }
   return false;
@@ -375,18 +367,11 @@
       MergeDispatchTypes(old_dispatch_type, event_to_coalesce.dispatch_type);
   if (event_to_coalesce.has_synthetic_phase &&
       event_to_coalesce.phase != old_phase) {
-    if (event_to_coalesce.phase == WebMouseWheelEvent::kPhaseBegan) {
-      // Coalesce a wheel event with synthetic phase began with a wheel event
-      // with synthetic phase ended.
-      DCHECK_EQ(WebMouseWheelEvent::kPhaseEnded, old_phase);
-      event->phase = WebMouseWheelEvent::kPhaseChanged;
-    } else {
-      // Coalesce  a wheel event with synthetic phase changed to a wheel event
-      // with synthetic phase began.
-      DCHECK_EQ(WebMouseWheelEvent::kPhaseChanged, event_to_coalesce.phase);
-      DCHECK_EQ(WebMouseWheelEvent::kPhaseBegan, old_phase);
-      event->phase = WebMouseWheelEvent::kPhaseBegan;
-    }
+    // Coalesce  a wheel event with synthetic phase changed to a wheel event
+    // with synthetic phase began.
+    DCHECK_EQ(WebMouseWheelEvent::kPhaseChanged, event_to_coalesce.phase);
+    DCHECK_EQ(WebMouseWheelEvent::kPhaseBegan, old_phase);
+    event->phase = WebMouseWheelEvent::kPhaseBegan;
   }
 }
 
diff --git a/ui/events/blink/blink_event_util_unittest.cc b/ui/events/blink/blink_event_util_unittest.cc
index dc23a7ee..c5a2b08 100644
--- a/ui/events/blink/blink_event_util_unittest.cc
+++ b/ui/events/blink/blink_event_util_unittest.cc
@@ -182,21 +182,24 @@
   coalesced_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
   EXPECT_FALSE(CanCoalesce(event_to_be_coalesced, coalesced_event));
 
+  // With timer based wheel scroll latching, we break the latching sequence on
+  // direction change when all prior GSU events in the current sequence are
+  // ignored. To do so we dispatch the pending wheel event with phaseEnded and
+  // the first wheel event in the opposite direction will have phaseBegan. The
+  // GSB generated from this wheel event will cause a new hittesting. To make
+  // sure that a GSB will actually get created we should not coalesce the wheel
+  // event with synthetic kPhaseBegan to one with synthetic kPhaseEnded.
   event_to_be_coalesced.has_synthetic_phase = true;
   coalesced_event.has_synthetic_phase = true;
-  EXPECT_TRUE(CanCoalesce(event_to_be_coalesced, coalesced_event));
-  Coalesce(event_to_be_coalesced, &coalesced_event);
-  EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseChanged, coalesced_event.phase);
-  EXPECT_EQ(7, coalesced_event.delta_x);
-  EXPECT_EQ(9, coalesced_event.delta_y);
+  EXPECT_FALSE(CanCoalesce(event_to_be_coalesced, coalesced_event));
 
   event_to_be_coalesced.phase = blink::WebMouseWheelEvent::kPhaseChanged;
   coalesced_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
   EXPECT_TRUE(CanCoalesce(event_to_be_coalesced, coalesced_event));
   Coalesce(event_to_be_coalesced, &coalesced_event);
   EXPECT_EQ(blink::WebMouseWheelEvent::kPhaseBegan, coalesced_event.phase);
-  EXPECT_EQ(10, coalesced_event.delta_x);
-  EXPECT_EQ(13, coalesced_event.delta_y);
+  EXPECT_EQ(7, coalesced_event.delta_x);
+  EXPECT_EQ(9, coalesced_event.delta_y);
 
   event_to_be_coalesced.resending_plugin_id = 3;
   EXPECT_FALSE(CanCoalesce(event_to_be_coalesced, coalesced_event));
diff --git a/ui/events/test/cocoa_test_event_utils.h b/ui/events/test/cocoa_test_event_utils.h
index 24c948f..2e58e1c 100644
--- a/ui/events/test/cocoa_test_event_utils.h
+++ b/ui/events/test/cocoa_test_event_utils.h
@@ -82,10 +82,10 @@
                                   NSUInteger modifiers);
 
 // Returns a mouse enter event.
-NSEvent* EnterEvent();
+NSEvent* EnterEvent(NSPoint point = NSZeroPoint, NSWindow* window = nil);
 
 // Returns a mouse exit event.
-NSEvent* ExitEvent();
+NSEvent* ExitEvent(NSPoint point = NSZeroPoint, NSWindow* window = nil);
 
 // Return an "other" event with the given type.
 NSEvent* OtherEventWithType(NSEventType event_type);
diff --git a/ui/events/test/cocoa_test_event_utils.mm b/ui/events/test/cocoa_test_event_utils.mm
index 181dc3c6..2d60c26 100644
--- a/ui/events/test/cocoa_test_event_utils.mm
+++ b/ui/events/test/cocoa_test_event_utils.mm
@@ -266,24 +266,26 @@
                            keyCode:key_code];
 }
 
-static NSEvent* EnterExitEventWithType(NSEventType event_type) {
+static NSEvent* EnterExitEventWithType(NSPoint point,
+                                       NSEventType event_type,
+                                       NSWindow* window) {
   return [NSEvent enterExitEventWithType:event_type
-                                location:NSZeroPoint
+                                location:point
                            modifierFlags:0
                                timestamp:TimeIntervalSinceSystemStartup()
-                            windowNumber:0
+                            windowNumber:[window windowNumber]
                                  context:nil
                              eventNumber:0
                           trackingNumber:0
                                 userData:NULL];
 }
 
-NSEvent* EnterEvent() {
-  return EnterExitEventWithType(NSMouseEntered);
+NSEvent* EnterEvent(NSPoint point, NSWindow* window) {
+  return EnterExitEventWithType(point, NSMouseEntered, window);
 }
 
-NSEvent* ExitEvent() {
-  return EnterExitEventWithType(NSMouseExited);
+NSEvent* ExitEvent(NSPoint point, NSWindow* window) {
+  return EnterExitEventWithType(point, NSMouseExited, window);
 }
 
 NSEvent* OtherEventWithType(NSEventType event_type) {
diff --git a/ui/file_manager/file_manager/background/js/app_window_wrapper.js b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
index 0088362..69ab408 100644
--- a/ui/file_manager/file_manager/background/js/app_window_wrapper.js
+++ b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
@@ -23,7 +23,7 @@
   this.url_ = url;
   this.id_ = id;
   // Do deep copy for the template of options to assign customized params later.
-  this.options_ = /** @type {!chrome.app.window.CreateWindowOptions} */(
+  this.options_ = /** @type {!chrome.app.window.CreateWindowOptions} */ (
       JSON.parse(JSON.stringify(options)));
   this.window_ = null;
   this.appState_ = null;
@@ -53,7 +53,7 @@
  * @return {string} Key of window geometry preferences.
  */
 AppWindowWrapper.makeGeometryKey = url => {
-  return 'windowGeometry' + ':' + url;
+  return 'windowGeometry:' + url;
 };
 
 /**
@@ -184,11 +184,13 @@
       const nextLeft = candidateBounds.left + AppWindowWrapper.SHIFT_DISTANCE;
       const nextRight = nextLeft + candidateBounds.width;
       candidateBounds.left = nextRight >= screen.availWidth ?
-          nextRight % screen.availWidth : nextLeft;
+          nextRight % screen.availWidth :
+          nextLeft;
       const nextTop = candidateBounds.top + AppWindowWrapper.SHIFT_DISTANCE;
       const nextBottom = nextTop + candidateBounds.height;
       candidateBounds.top = nextBottom >= screen.availHeight ?
-          nextBottom % screen.availHeight : nextTop;
+          nextBottom % screen.availHeight :
+          nextTop;
     }
     this.window_.moveTo(
         /** @type {number} */ (candidateBounds.left),
@@ -281,7 +283,9 @@
 /**
  * Inherits from AppWindowWrapper.
  */
-SingletonAppWindowWrapper.prototype = {__proto__: AppWindowWrapper.prototype};
+SingletonAppWindowWrapper.prototype = {
+  __proto__: AppWindowWrapper.prototype
+};
 
 /**
  * Open the window.
@@ -293,8 +297,8 @@
  *     False otherwise.
  * @param {function()=} opt_callback Completion callback.
  */
-SingletonAppWindowWrapper.prototype.launch =
-    function(appState, reopen, opt_callback) {
+SingletonAppWindowWrapper.prototype.launch = function(
+    appState, reopen, opt_callback) {
   // If the window is not opened yet, just call the parent method.
   if (!this.openingOrOpened_) {
     AppWindowWrapper.prototype.launch.call(
diff --git a/ui/file_manager/file_manager/background/js/background.js b/ui/file_manager/file_manager/background/js/background.js
index e6224bb..a28c34c 100644
--- a/ui/file_manager/file_manager/background/js/background.js
+++ b/ui/file_manager/file_manager/background/js/background.js
@@ -67,8 +67,7 @@
    * @type {!importer.MediaScanner}
    */
   this.mediaScanner = new importer.DefaultMediaScanner(
-      importer.createMetadataHashcode,
-      this.dispositionChecker_,
+      importer.createMetadataHashcode, this.dispositionChecker_,
       importer.DefaultDirectoryWatcher.create);
 
   /**
@@ -161,32 +160,31 @@
  * @private
  */
 FileBrowserBackgroundImpl.prototype.handleViewEventInternal_ = function(event) {
-  volumeManagerFactory.getInstance()
-      .then(
-          /**
-          * Retrieves the root file entry of the volume on the requested
-          * device.
-          * @param {!VolumeManager} volumeManager
-          */
-          volumeManager => {
-            if (event.devicePath) {
-              let volume = volumeManager.findByDevicePath(event.devicePath);
-              if (volume) {
-                this.navigateToVolumeRoot_(volume, event.filePath);
-              } else {
-                console.error('Got view event with invalid volume id.');
-              }
-            } else if (event.volumeId) {
-              if (event.type === VolumeManagerCommon.VOLUME_ALREADY_MOUNTED) {
-                this.navigateToVolumeInFocusedWindowWhenReady_(
-                    event.volumeId, event.filePath);
-              } else {
-                this.navigateToVolumeWhenReady_(event.volumeId, event.filePath);
-              }
-            } else {
-              console.error('Got view event with no actionable destination.');
-            }
-          });
+  volumeManagerFactory.getInstance().then(
+      /**
+       * Retrieves the root file entry of the volume on the requested
+       * device.
+       * @param {!VolumeManager} volumeManager
+       */
+      volumeManager => {
+        if (event.devicePath) {
+          let volume = volumeManager.findByDevicePath(event.devicePath);
+          if (volume) {
+            this.navigateToVolumeRoot_(volume, event.filePath);
+          } else {
+            console.error('Got view event with invalid volume id.');
+          }
+        } else if (event.volumeId) {
+          if (event.type === VolumeManagerCommon.VOLUME_ALREADY_MOUNTED) {
+            this.navigateToVolumeInFocusedWindowWhenReady_(
+                event.volumeId, event.filePath);
+          } else {
+            this.navigateToVolumeWhenReady_(event.volumeId, event.filePath);
+          }
+        } else {
+          console.error('Got view event with no actionable destination.');
+        }
+      });
 };
 
 /**
@@ -248,16 +246,17 @@
  * @return {!Promise<!DirectoryEntry>}
  * @private
  */
-FileBrowserBackgroundImpl.prototype.retrieveEntryInVolume_ = (volume, opt_directoryPath) => {
-  return volume.resolveDisplayRoot().then(root => {
-    if (opt_directoryPath) {
-      return new Promise(
-          root.getDirectory.bind(root, opt_directoryPath, {create: false}));
-    } else {
-      return Promise.resolve(root);
-    }
-  });
-};
+FileBrowserBackgroundImpl.prototype.retrieveEntryInVolume_ =
+    (volume, opt_directoryPath) => {
+      return volume.resolveDisplayRoot().then(root => {
+        if (opt_directoryPath) {
+          return new Promise(
+              root.getDirectory.bind(root, opt_directoryPath, {create: false}));
+        } else {
+          return Promise.resolve(root);
+        }
+      });
+    };
 
 /**
  * Opens the volume root (or opt directoryPath) in main UI.
@@ -387,10 +386,10 @@
  */
 FileBrowserBackgroundImpl.prototype.onExternalMessageReceived_ =
     (message, sender) => {
-  if ('id' in sender && sender.id === GPLUS_PHOTOS_APP_ID) {
-    importer.handlePhotosAppMessage(message);
-  }
-};
+      if ('id' in sender && sender.id === GPLUS_PHOTOS_APP_ID) {
+        importer.handlePhotosAppMessage(message);
+      }
+    };
 
 /**
  * Restarted the app, restore windows.
@@ -429,20 +428,22 @@
   if (info.menuItemId == 'new-window') {
     // Find the focused window (if any) and use it's current url for the
     // new window. If not found, then launch with the default url.
-    this.findFocusedWindow_().then(key => {
-      if (!key) {
-        launcher.launchFileManager();
-        return;
-      }
-      const appState = {
-        // Do not clone the selection url, only the current directory.
-        currentDirectoryURL: window.appWindows[key].
-            contentWindow.appState.currentDirectoryURL
-      };
-      launcher.launchFileManager(appState);
-    }).catch(error => {
-      console.error(error.stack || error);
-    });
+    this.findFocusedWindow_()
+        .then(key => {
+          if (!key) {
+            launcher.launchFileManager();
+            return;
+          }
+          const appState = {
+            // Do not clone the selection url, only the current directory.
+            currentDirectoryURL: window.appWindows[key]
+                                     .contentWindow.appState.currentDirectoryURL
+          };
+          launcher.launchFileManager(appState);
+        })
+        .catch(error => {
+          console.error(error.stack || error);
+        });
   }
 };
 
diff --git a/ui/file_manager/file_manager/background/js/background_base.js b/ui/file_manager/file_manager/background/js/background_base.js
index 64b2287..417a3f1 100644
--- a/ui/file_manager/file_manager/background/js/background_base.js
+++ b/ui/file_manager/file_manager/background/js/background_base.js
@@ -49,29 +49,30 @@
     return;
   }
 
-  this.initializationPromise_.then(() => {
-    // Volume list needs to be initialized (more precisely,
-    // chrome.fileSystem.requestFileSystem needs to be called to grant access)
-    // before resolveIsolatedEntries().
-    return volumeManagerFactory.getInstance();
-  }).then(() => {
-    const isolatedEntries = launchData.items.map(item => {
-      return item.entry;
-    });
-
-    // Obtains entries in non-isolated file systems.
-    // The entries in launchData are stored in the isolated file system.
-    // We need to map the isolated entries to the normal entries to retrieve
-    // their parent directory.
-    chrome.fileManagerPrivate.resolveIsolatedEntries(
-        isolatedEntries,
-        externalEntries => {
-          const urls = util.entriesToURLs(externalEntries);
-          if (this.launchHandler_) {
-            this.launchHandler_(urls);
-          }
+  this.initializationPromise_
+      .then(() => {
+        // Volume list needs to be initialized (more precisely,
+        // chrome.fileSystem.requestFileSystem needs to be called to grant
+        // access) before resolveIsolatedEntries().
+        return volumeManagerFactory.getInstance();
+      })
+      .then(() => {
+        const isolatedEntries = launchData.items.map(item => {
+          return item.entry;
         });
-  });
+
+        // Obtains entries in non-isolated file systems.
+        // The entries in launchData are stored in the isolated file system.
+        // We need to map the isolated entries to the normal entries to retrieve
+        // their parent directory.
+        chrome.fileManagerPrivate.resolveIsolatedEntries(
+            isolatedEntries, externalEntries => {
+              const urls = util.entriesToURLs(externalEntries);
+              if (this.launchHandler_) {
+                this.launchHandler_(urls);
+              }
+            });
+      });
 };
 
 /**
@@ -85,5 +86,4 @@
 /**
  * Called when an app is restarted.
  */
-BackgroundBase.prototype.onRestarted_ = () => {
-};
+BackgroundBase.prototype.onRestarted_ = () => {};
diff --git a/ui/file_manager/file_manager/background/js/device_handler.js b/ui/file_manager/file_manager/background/js/device_handler.js
index be9441b..5bb25af8 100644
--- a/ui/file_manager/file_manager/background/js/device_handler.js
+++ b/ui/file_manager/file_manager/background/js/device_handler.js
@@ -93,11 +93,9 @@
  * @const
  */
 DeviceHandler.Notification.DEVICE_NAVIGATION = new DeviceHandler.Notification(
-    'deviceNavigation',
-    'REMOVABLE_DEVICE_DETECTION_TITLE',
+    'deviceNavigation', 'REMOVABLE_DEVICE_DETECTION_TITLE',
     'REMOVABLE_DEVICE_NAVIGATION_MESSAGE',
-    'REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL',
-    true);
+    'REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL', true);
 
 /**
  * @type {DeviceHandler.Notification}
@@ -105,21 +103,17 @@
  */
 DeviceHandler.Notification.DEVICE_NAVIGATION_READONLY_POLICY =
     new DeviceHandler.Notification(
-        'deviceNavigation',
-        'REMOVABLE_DEVICE_DETECTION_TITLE',
+        'deviceNavigation', 'REMOVABLE_DEVICE_DETECTION_TITLE',
         'REMOVABLE_DEVICE_NAVIGATION_MESSAGE_READONLY_POLICY',
-        'REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL',
-        true);
+        'REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL', true);
 
 /**
  * @type {DeviceHandler.Notification}
  * @const
  */
 DeviceHandler.Notification.DEVICE_IMPORT = new DeviceHandler.Notification(
-    'deviceImport',
-    'REMOVABLE_DEVICE_DETECTION_TITLE',
-    'REMOVABLE_DEVICE_IMPORT_MESSAGE',
-    'REMOVABLE_DEVICE_IMPORT_BUTTON_LABEL',
+    'deviceImport', 'REMOVABLE_DEVICE_DETECTION_TITLE',
+    'REMOVABLE_DEVICE_IMPORT_MESSAGE', 'REMOVABLE_DEVICE_IMPORT_BUTTON_LABEL',
     true);
 
 /**
@@ -127,8 +121,7 @@
  * @const
  */
 DeviceHandler.Notification.DEVICE_FAIL = new DeviceHandler.Notification(
-    'deviceFail',
-    'REMOVABLE_DEVICE_DETECTION_TITLE',
+    'deviceFail', 'REMOVABLE_DEVICE_DETECTION_TITLE',
     'DEVICE_UNSUPPORTED_DEFAULT_MESSAGE');
 
 /**
@@ -136,10 +129,8 @@
  * @const
  */
 DeviceHandler.Notification.DEVICE_FAIL_UNKNOWN = new DeviceHandler.Notification(
-    'deviceFail',
-    'REMOVABLE_DEVICE_DETECTION_TITLE',
-    'DEVICE_UNKNOWN_DEFAULT_MESSAGE',
-    'DEVICE_UNKNOWN_BUTTON_LABEL');
+    'deviceFail', 'REMOVABLE_DEVICE_DETECTION_TITLE',
+    'DEVICE_UNKNOWN_DEFAULT_MESSAGE', 'DEVICE_UNKNOWN_BUTTON_LABEL');
 
 /**
  * @type {DeviceHandler.Notification}
@@ -147,8 +138,7 @@
  */
 DeviceHandler.Notification.DEVICE_FAIL_UNKNOWN_READONLY =
     new DeviceHandler.Notification(
-        'deviceFail',
-        'REMOVABLE_DEVICE_DETECTION_TITLE',
+        'deviceFail', 'REMOVABLE_DEVICE_DETECTION_TITLE',
         'DEVICE_UNKNOWN_DEFAULT_MESSAGE');
 
 /**
@@ -157,8 +147,7 @@
  */
 DeviceHandler.Notification.DEVICE_EXTERNAL_STORAGE_DISABLED =
     new DeviceHandler.Notification(
-        'deviceFail',
-        'REMOVABLE_DEVICE_DETECTION_TITLE',
+        'deviceFail', 'REMOVABLE_DEVICE_DETECTION_TITLE',
         'EXTERNAL_STORAGE_DISABLED_MESSAGE');
 
 /**
@@ -167,8 +156,7 @@
  */
 DeviceHandler.Notification.DEVICE_HARD_UNPLUGGED =
     new DeviceHandler.Notification(
-        'hardUnplugged',
-        'DEVICE_HARD_UNPLUGGED_TITLE',
+        'hardUnplugged', 'DEVICE_HARD_UNPLUGGED_TITLE',
         'DEVICE_HARD_UNPLUGGED_MESSAGE');
 
 /**
@@ -176,8 +164,7 @@
  * @const
  */
 DeviceHandler.Notification.FORMAT_START = new DeviceHandler.Notification(
-    'formatStart',
-    'FORMATTING_OF_DEVICE_PENDING_TITLE',
+    'formatStart', 'FORMATTING_OF_DEVICE_PENDING_TITLE',
     'FORMATTING_OF_DEVICE_PENDING_MESSAGE');
 
 /**
@@ -185,8 +172,7 @@
  * @const
  */
 DeviceHandler.Notification.FORMAT_SUCCESS = new DeviceHandler.Notification(
-    'formatSuccess',
-    'FORMATTING_OF_DEVICE_FINISHED_TITLE',
+    'formatSuccess', 'FORMATTING_OF_DEVICE_FINISHED_TITLE',
     'FORMATTING_FINISHED_SUCCESS_MESSAGE');
 
 /**
@@ -194,8 +180,7 @@
  * @const
  */
 DeviceHandler.Notification.FORMAT_FAIL = new DeviceHandler.Notification(
-    'formatFail',
-    'FORMATTING_OF_DEVICE_FAILED_TITLE',
+    'formatFail', 'FORMATTING_OF_DEVICE_FAILED_TITLE',
     'FORMATTING_FINISHED_FAILURE_MESSAGE');
 
 /**
@@ -251,8 +236,7 @@
   const buttons =
       this.buttonLabel ? [{title: str(this.buttonLabel)}] : undefined;
   chrome.notifications.create(
-      notificationId,
-      {
+      notificationId, {
         type: 'basic',
         title: str(this.title),
         message: message || str(this.message),
@@ -311,8 +295,7 @@
       delete this.mountStatus_[event.devicePath];
       break;
     case 'hard_unplugged':
-      DeviceHandler.Notification.DEVICE_HARD_UNPLUGGED.show(
-          event.devicePath);
+      DeviceHandler.Notification.DEVICE_HARD_UNPLUGGED.show(event.devicePath);
       break;
     case 'format_start':
       DeviceHandler.Notification.FORMAT_START.show(event.devicePath);
@@ -444,8 +427,7 @@
           strf('MULTIPART_DEVICE_UNSUPPORTED_MESSAGE', volume.deviceLabel) :
           str('MULTIPART_DEVICE_UNSUPPORTED_DEFAULT_MESSAGE');
       DeviceHandler.Notification.DEVICE_FAIL.show(
-          /** @type {string} */ (volume.devicePath),
-          message);
+          /** @type {string} */ (volume.devicePath), message);
       break;
     case DeviceHandler.MountStatus.CHILD_ERROR:
     case DeviceHandler.MountStatus.ONLY_PARENT_ERROR:
@@ -454,20 +436,17 @@
             strf('DEVICE_UNSUPPORTED_MESSAGE', volume.deviceLabel) :
             str('DEVICE_UNSUPPORTED_DEFAULT_MESSAGE');
         DeviceHandler.Notification.DEVICE_FAIL.show(
-            /** @type {string} */ (volume.devicePath),
-            message);
+            /** @type {string} */ (volume.devicePath), message);
       } else {
         message = volume.deviceLabel ?
             strf('DEVICE_UNKNOWN_MESSAGE', volume.deviceLabel) :
             str('DEVICE_UNKNOWN_DEFAULT_MESSAGE');
         if (event.volumeMetadata.isReadOnly) {
           DeviceHandler.Notification.DEVICE_FAIL_UNKNOWN_READONLY.show(
-              /** @type {string} */ (volume.devicePath),
-              message);
+              /** @type {string} */ (volume.devicePath), message);
         } else {
           DeviceHandler.Notification.DEVICE_FAIL_UNKNOWN.show(
-              /** @type {string} */ (volume.devicePath),
-              message);
+              /** @type {string} */ (volume.devicePath), message);
         }
       }
   }
@@ -501,15 +480,14 @@
            *     of the volume.
            */
           volumeInfo => {
-            return importer.importEnabled()
-                .then(
-                    /** @param {boolean} enabled */
-                    enabled => {
-                      if (enabled && importer.isEligibleVolume(volumeInfo)) {
-                        return volumeInfo.resolveDisplayRoot();
-                      }
-                      return Promise.reject('Cloud import disabled.');
-                    });
+            return importer.importEnabled().then(
+                /** @param {boolean} enabled */
+                enabled => {
+                  if (enabled && importer.isEligibleVolume(volumeInfo)) {
+                    return volumeInfo.resolveDisplayRoot();
+                  }
+                  return Promise.reject('Cloud import disabled.');
+                });
           })
       .then(
           /**
@@ -520,23 +498,23 @@
             return importer.getMediaDirectory(root);
           })
       .then(/**
-   * @param {!DirectoryEntry} directory
-   */
-  directory => {
-    return importer.isPhotosAppImportEnabled().then(
-        /**
-         * @param {boolean} appEnabled
-         */
-        appEnabled => {
-          // We don't want to auto-open two windows when a user
-          // inserts a removable device.  Only open Files app if
-          // auto-import is disabled in Photos app.
-          if (!appEnabled) {
-            this.openMediaDirectory_(
-                metadata.volumeId, null, directory.fullPath);
-          }
-        });
-  })
+             * @param {!DirectoryEntry} directory
+             */
+            directory => {
+              return importer.isPhotosAppImportEnabled().then(
+                  /**
+                   * @param {boolean} appEnabled
+                   */
+                  appEnabled => {
+                    // We don't want to auto-open two windows when a user
+                    // inserts a removable device.  Only open Files app if
+                    // auto-import is disabled in Photos app.
+                    if (!appEnabled) {
+                      this.openMediaDirectory_(
+                          metadata.volumeId, null, directory.fullPath);
+                    }
+                  });
+            })
       .catch(error => {
         if (metadata.deviceType && metadata.devicePath) {
           if (metadata.isReadOnly && !metadata.isReadOnlyRemovableDevice) {
@@ -590,8 +568,8 @@
  * @param {?string} filePath
  * @private
  */
-DeviceHandler.prototype.openMediaDirectory_ =
-    function(volumeId, devicePath, filePath) {
+DeviceHandler.prototype.openMediaDirectory_ = function(
+    volumeId, devicePath, filePath) {
   const event = new Event(DeviceHandler.VOLUME_NAVIGATION_REQUESTED);
   event.volumeId = volumeId;
   event.devicePath = devicePath;
diff --git a/ui/file_manager/file_manager/background/js/device_handler_unittest.js b/ui/file_manager/file_manager/background/js/device_handler_unittest.js
index 0ca85d4..6e2415a 100644
--- a/ui/file_manager/file_manager/background/js/device_handler_unittest.js
+++ b/ui/file_manager/file_manager/background/js/device_handler_unittest.js
@@ -61,13 +61,10 @@
 function testRemovableMediaDeviceWithImportEnabled(callback) {
   const storage = new MockChromeStorageAPI();
 
-  setupFileSystem(
-      VolumeManagerCommon.VolumeType.REMOVABLE,
-      'blabbity',
-      [
-        '/DCIM/',
-        '/DCIM/grandma.jpg'
-      ]);
+  setupFileSystem(VolumeManagerCommon.VolumeType.REMOVABLE, 'blabbity', [
+    '/DCIM/',
+    '/DCIM/grandma.jpg',
+  ]);
 
   const resolver = new importer.Resolver();
 
@@ -85,23 +82,19 @@
   });
 
   reportPromise(
-      resolver.promise.then(
-          event => {
-            assertEquals('blabbity', event.volumeId);
-          }),
+      resolver.promise.then(event => {
+        assertEquals('blabbity', event.volumeId);
+      }),
       callback);
 }
 
 function testMtpMediaDeviceWithImportEnabled(callback) {
   const storage = new MockChromeStorageAPI();
 
-  setupFileSystem(
-      VolumeManagerCommon.VolumeType.MTP,
-      'blabbity',
-      [
-        '/dcim/',
-        '/dcim/grandpa.jpg'
-      ]);
+  setupFileSystem(VolumeManagerCommon.VolumeType.MTP, 'blabbity', [
+    '/dcim/',
+    '/dcim/grandpa.jpg',
+  ]);
 
   const resolver = new importer.Resolver();
 
@@ -119,10 +112,9 @@
   });
 
   reportPromise(
-      resolver.promise.then(
-          event => {
-            assertEquals('blabbity', event.volumeId);
-          }),
+      resolver.promise.then(event => {
+        assertEquals('blabbity', event.volumeId);
+      }),
       callback);
 }
 
@@ -374,8 +366,7 @@
           })
           .then(() => {
             const notifications = mockChrome.notifications.items;
-            assertEquals(
-                2, Object.keys(notifications).length);
+            assertEquals(2, Object.keys(notifications).length);
             assertEquals(
                 'MULTIPART_DEVICE_UNSUPPORTED: label',
                 notifications['deviceFail:/device/path'].message);
@@ -593,12 +584,11 @@
   // navigation-requested event is dispatched.
   mockChrome.notifications.onClicked.dispatch(notificationId);
   reportPromise(
-      resolver.promise.then(
-          event => {
-            assertEquals(null, event.volumeId);
-            assertEquals(devicePath, event.devicePath);
-            assertEquals(null, event.filePath);
-          }),
+      resolver.promise.then(event => {
+        assertEquals(null, event.volumeId);
+        assertEquals(devicePath, event.devicePath);
+        assertEquals(null, event.filePath);
+      }),
       callback);
 }
 
diff --git a/ui/file_manager/file_manager/background/js/drive_sync_handler.js b/ui/file_manager/file_manager/background/js/drive_sync_handler.js
index 56847cb0..1c624dd 100644
--- a/ui/file_manager/file_manager/background/js/drive_sync_handler.js
+++ b/ui/file_manager/file_manager/background/js/drive_sync_handler.js
@@ -121,8 +121,7 @@
  * @return {boolean}
  */
 DriveSyncHandlerImpl.prototype.isSyncSuppressed = function() {
-  return navigator.connection.type === 'cellular' &&
-      this.cellularDisabled_;
+  return navigator.connection.type === 'cellular' && this.cellularDisabled_;
 };
 
 /**
@@ -168,8 +167,7 @@
       }
       break;
     default:
-      throw new Error(
-          'Invalid transfer state: ' + status.transferState + '.');
+      throw new Error('Invalid transfer state: ' + status.transferState + '.');
   }
 };
 
@@ -214,7 +212,8 @@
 DriveSyncHandlerImpl.prototype.removeItem_ = function(status) {
   this.queue_.run(callback => {
     this.item_.state = status.transferState === 'completed' ?
-        ProgressItemState.COMPLETED : ProgressItemState.CANCELED;
+        ProgressItemState.COMPLETED :
+        ProgressItemState.CANCELED;
     this.progressCenter_.updateItem(this.item_);
     this.syncing_ = false;
     this.dispatchEvent(new Event(this.getCompletedEventName()));
@@ -244,8 +243,7 @@
     item.state = ProgressItemState.ERROR;
     switch (event.type) {
       case 'delete_without_permission':
-        item.message =
-            strf('SYNC_DELETE_WITHOUT_PERMISSION_ERROR', entry.name);
+        item.message = strf('SYNC_DELETE_WITHOUT_PERMISSION_ERROR', entry.name);
         break;
       case 'service_unavailable':
         item.message = str('SYNC_SERVICE_UNAVAILABLE_ERROR');
@@ -275,14 +273,16 @@
  * @param {number} buttonIndex Index of the button.
  * @private
  */
-DriveSyncHandlerImpl.prototype.onNotificationButtonClicked_ = (notificationId, buttonIndex) => {
-  const expectedId = DriveSyncHandlerImpl.DISABLED_MOBILE_SYNC_NOTIFICATION_ID_;
-  if (notificationId !== expectedId) {
-    return;
-  }
-  chrome.notifications.clear(notificationId, () => {});
-  chrome.fileManagerPrivate.setPreferences({cellularDisabled: false});
-};
+DriveSyncHandlerImpl.prototype.onNotificationButtonClicked_ =
+    (notificationId, buttonIndex) => {
+      const expectedId =
+          DriveSyncHandlerImpl.DISABLED_MOBILE_SYNC_NOTIFICATION_ID_;
+      if (notificationId !== expectedId) {
+        return;
+      }
+      chrome.notifications.clear(notificationId, () => {});
+      chrome.fileManagerPrivate.setPreferences({cellularDisabled: false});
+    };
 
 /**
  * Handles preferences change.
diff --git a/ui/file_manager/file_manager/background/js/duplicate_finder.js b/ui/file_manager/file_manager/background/js/duplicate_finder.js
index 9cd265b..c5206f8 100644
--- a/ui/file_manager/file_manager/background/js/duplicate_finder.js
+++ b/ui/file_manager/file_manager/background/js/duplicate_finder.js
@@ -19,8 +19,8 @@
    * An bounded cache of most recently calculated file content hashcodes.
    * @private {!LRUCache<!Promise<string>>}
    */
-  this.hashCache_ = new LRUCache(
-      importer.DriveDuplicateFinder.MAX_CACHED_HASHCODES_);
+  this.hashCache_ =
+      new LRUCache(importer.DriveDuplicateFinder.MAX_CACHED_HASHCODES_);
 };
 
 /**
@@ -70,9 +70,9 @@
           chrome.fileManagerPrivate.computeChecksum(
               entry,
               /**
-              * @param {string|undefined} result The content hash.
-              * @this {importer.DriveDuplicateFinder}
-              */
+               * @param {string|undefined} result The content hash.
+               * @this {importer.DriveDuplicateFinder}
+               */
               result => {
                 const elapsedTime = new Date().getTime() - startTime;
                 // Send the timing to GA only if it is sorta exceptionally long.
@@ -106,8 +106,7 @@
  */
 importer.DriveDuplicateFinder.prototype.findByHash_ = function(hash) {
   return /** @type {!Promise<!Array<string>>} */ (
-      this.getDriveId_()
-          .then(this.searchFilesByHash_.bind(this, hash)));
+      this.getDriveId_().then(this.searchFilesByHash_.bind(this, hash)));
 };
 
 /**
@@ -116,16 +115,16 @@
  */
 importer.DriveDuplicateFinder.prototype.getDriveId_ = function() {
   if (!this.driveIdPromise_) {
-    this.driveIdPromise_ = volumeManagerFactory.getInstance()
-        .then(
-            /**
-             * @param {!VolumeManager} volumeManager
-             * @return {string} ID of the user's Drive volume.
-             */
-            volumeManager => {
-              return volumeManager.getCurrentProfileVolumeInfo(
-                  VolumeManagerCommon.VolumeType.DRIVE).volumeId;
-            });
+    this.driveIdPromise_ = volumeManagerFactory.getInstance().then(
+        /**
+         * @param {!VolumeManager} volumeManager
+         * @return {string} ID of the user's Drive volume.
+         */
+        volumeManager => {
+          return volumeManager
+              .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DRIVE)
+              .volumeId;
+        });
   }
   return this.driveIdPromise_;
 };
@@ -137,19 +136,18 @@
  * @return {!Promise<!Array<string>>} A list of file URLs.
  * @private
  */
-importer.DriveDuplicateFinder.prototype.searchFilesByHash_ =
-    function(hash, volumeId) {
+importer.DriveDuplicateFinder.prototype.searchFilesByHash_ = function(
+    hash, volumeId) {
   return new Promise(
       /** @this {importer.DriveDuplicateFinder} */
       (resolve, reject) => {
         const startTime = new Date().getTime();
         chrome.fileManagerPrivate.searchFilesByHashes(
-            volumeId,
-            [hash],
+            volumeId, [hash],
             /**
-            * @param {!Object<string, !Array<string>>|undefined} urls
-            * @this {importer.DriveDuplicateFinder}
-            */
+             * @param {!Object<string, !Array<string>>|undefined} urls
+             * @this {importer.DriveDuplicateFinder}
+             */
             urls => {
               const elapsedTime = new Date().getTime() - startTime;
               // Send the timing to GA only if it is sorta exceptionally long.
@@ -199,8 +197,8 @@
 /**
  * @type {!importer.DispositionChecker.CheckerFunction}
  */
-importer.DispositionChecker.prototype.getDisposition =
-    function(entry, destination, mode) {
+importer.DispositionChecker.prototype.getDisposition = function(
+    entry, destination, mode) {
   if (destination !== importer.Destination.GOOGLE_DRIVE) {
     return Promise.reject('Unsupported destination: ' + destination);
   }
@@ -211,9 +209,9 @@
         this.hasHistoryDuplicate_(entry, destination)
             .then(
                 /**
-                * @param {boolean} duplicate
-                * @this {importer.DispositionChecker}
-                */
+                 * @param {boolean} duplicate
+                 * @this {importer.DispositionChecker}
+                 */
                 duplicate => {
                   if (duplicate) {
                     resolve(importer.Disposition.HISTORY_DUPLICATE);
@@ -223,19 +221,17 @@
                     resolve(importer.Disposition.ORIGINAL);
                     return;
                   }
-                  this.contentMatcher_.isDuplicate(entry)
-                      .then(
-                          /** @param {boolean} duplicate */
-                          duplicate => {
-                            if (duplicate) {
-                              resolve(
-                                  importer.Disposition.CONTENT_DUPLICATE);
-                            } else {
-                              resolve(importer.Disposition.ORIGINAL);
-                            }
-                          });
+                  this.contentMatcher_.isDuplicate(entry).then(
+                      /** @param {boolean} duplicate */
+                      duplicate => {
+                        if (duplicate) {
+                          resolve(importer.Disposition.CONTENT_DUPLICATE);
+                        } else {
+                          resolve(importer.Disposition.ORIGINAL);
+                        }
+                      });
                 });
-            });
+      });
 };
 
 /**
@@ -245,19 +241,20 @@
  *     for the file.
  * @private
  */
-importer.DispositionChecker.prototype.hasHistoryDuplicate_ =
-    function(entry, destination) {
-  return this.historyLoader_.getHistory()
-      .then(
-          /**
-          * @param {!importer.ImportHistory} history
-          * @return {!Promise}
-          */
-          history => {
-            return Promise.all([
+importer.DispositionChecker.prototype.hasHistoryDuplicate_ = function(
+    entry, destination) {
+  return this.historyLoader_.getHistory().then(
+      /**
+       * @param {!importer.ImportHistory} history
+       * @return {!Promise}
+       */
+      history => {
+        return Promise
+            .all([
               history.wasCopied(entry, destination),
               history.wasImported(entry, destination)
-            ]).then(
+            ])
+            .then(
                 /**
                  * @param {!Array<boolean>} results
                  * @return {boolean}
@@ -265,7 +262,7 @@
                 results => {
                   return results[0] || results[1];
                 });
-          });
+      });
 };
 
 /**
diff --git a/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.js b/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.js
index e0036f2..eb3a37a 100644
--- a/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.js
+++ b/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.js
@@ -86,11 +86,9 @@
   const files = setupHashes(filePaths, fileHashes);
 
   reportPromise(
-      duplicateFinder.isDuplicate(files[0])
-          .then(
-              isDuplicate => {
-                assertTrue(isDuplicate);
-              }),
+      duplicateFinder.isDuplicate(files[0]).then(isDuplicate => {
+        assertTrue(isDuplicate);
+      }),
       callback);
 }
 
@@ -106,11 +104,9 @@
   const newFile = /** @type {!FileEntry} */ (fileSystem.entries[newFilePath]);
 
   reportPromise(
-      duplicateFinder.isDuplicate(newFile)
-          .then(
-              isDuplicate => {
-                assertFalse(isDuplicate);
-              }),
+      duplicateFinder.isDuplicate(newFile).then(isDuplicate => {
+        assertFalse(isDuplicate);
+      }),
       callback);
 }
 
@@ -134,8 +130,7 @@
   const fileHashes = ['abc123'];
   const files = setupHashes(filePaths, fileHashes);
 
-  testHistory.importedPaths['/foo.txt'] =
-      [importer.Destination.GOOGLE_DRIVE];
+  testHistory.importedPaths['/foo.txt'] = [importer.Destination.GOOGLE_DRIVE];
 
   reportPromise(
       getDisposition(
@@ -174,10 +169,9 @@
   // Set up a filesystem with some files.
   fileSystem.populate(filePaths);
 
-  const files = filePaths.map(
-      filename => {
-        return fileSystem.entries[filename];
-      });
+  const files = filePaths.map(filename => {
+    return fileSystem.entries[filename];
+  });
 
   files.forEach((file, index) => {
     hashes[file.toURL()] = fileHashes[index];
diff --git a/ui/file_manager/file_manager/background/js/file_operation_handler.js b/ui/file_manager/file_manager/background/js/file_operation_handler.js
index 6d078b2..48dab04 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_handler.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_handler.js
@@ -39,11 +39,9 @@
 
   // Register event.
   this.fileOperationManager_.addEventListener(
-      'copy-progress',
-      this.onCopyProgress_.bind(this));
+      'copy-progress', this.onCopyProgress_.bind(this));
   this.fileOperationManager_.addEventListener(
-      'delete',
-      this.onDeleteProgress_.bind(this));
+      'delete', this.onDeleteProgress_.bind(this));
 };
 
 /**
@@ -70,44 +68,64 @@
           name += '/';
         }
         switch (event.status.operationType) {
-          case 'COPY': return strf('COPY_TARGET_EXISTS_ERROR', name);
-          case 'MOVE': return strf('MOVE_TARGET_EXISTS_ERROR', name);
-          case 'ZIP': return strf('ZIP_TARGET_EXISTS_ERROR', name);
-          default: return strf('TRANSFER_TARGET_EXISTS_ERROR', name);
+          case 'COPY':
+            return strf('COPY_TARGET_EXISTS_ERROR', name);
+          case 'MOVE':
+            return strf('MOVE_TARGET_EXISTS_ERROR', name);
+          case 'ZIP':
+            return strf('ZIP_TARGET_EXISTS_ERROR', name);
+          default:
+            return strf('TRANSFER_TARGET_EXISTS_ERROR', name);
         }
 
       case util.FileOperationErrorType.FILESYSTEM_ERROR:
         const detail = util.getFileErrorString(event.error.data.name);
         switch (event.status.operationType) {
-          case 'COPY': return strf('COPY_FILESYSTEM_ERROR', detail);
-          case 'MOVE': return strf('MOVE_FILESYSTEM_ERROR', detail);
-          case 'ZIP': return strf('ZIP_FILESYSTEM_ERROR', detail);
-          default: return strf('TRANSFER_FILESYSTEM_ERROR', detail);
+          case 'COPY':
+            return strf('COPY_FILESYSTEM_ERROR', detail);
+          case 'MOVE':
+            return strf('MOVE_FILESYSTEM_ERROR', detail);
+          case 'ZIP':
+            return strf('ZIP_FILESYSTEM_ERROR', detail);
+          default:
+            return strf('TRANSFER_FILESYSTEM_ERROR', detail);
         }
 
       default:
         switch (event.status.operationType) {
-          case 'COPY': return strf('COPY_UNEXPECTED_ERROR', event.error.code);
-          case 'MOVE': return strf('MOVE_UNEXPECTED_ERROR', event.error.code);
-          case 'ZIP': return strf('ZIP_UNEXPECTED_ERROR', event.error.code);
-          default: return strf('TRANSFER_UNEXPECTED_ERROR', event.error.code);
+          case 'COPY':
+            return strf('COPY_UNEXPECTED_ERROR', event.error.code);
+          case 'MOVE':
+            return strf('MOVE_UNEXPECTED_ERROR', event.error.code);
+          case 'ZIP':
+            return strf('ZIP_UNEXPECTED_ERROR', event.error.code);
+          default:
+            return strf('TRANSFER_UNEXPECTED_ERROR', event.error.code);
         }
     }
   } else if (event.status.numRemainingItems === 1) {
     var name = event.status.processingEntryName;
     switch (event.status.operationType) {
-      case 'COPY': return strf('COPY_FILE_NAME', name);
-      case 'MOVE': return strf('MOVE_FILE_NAME', name);
-      case 'ZIP': return strf('ZIP_FILE_NAME', name);
-      default: return strf('TRANSFER_FILE_NAME', name);
+      case 'COPY':
+        return strf('COPY_FILE_NAME', name);
+      case 'MOVE':
+        return strf('MOVE_FILE_NAME', name);
+      case 'ZIP':
+        return strf('ZIP_FILE_NAME', name);
+      default:
+        return strf('TRANSFER_FILE_NAME', name);
     }
   } else {
     const remainNumber = event.status.numRemainingItems;
     switch (event.status.operationType) {
-      case 'COPY': return strf('COPY_ITEMS_REMAINING', remainNumber);
-      case 'MOVE': return strf('MOVE_ITEMS_REMAINING', remainNumber);
-      case 'ZIP': return strf('ZIP_ITEMS_REMAINING', remainNumber);
-      default: return strf('TRANSFER_ITEMS_REMAINING', remainNumber);
+      case 'COPY':
+        return strf('COPY_ITEMS_REMAINING', remainNumber);
+      case 'MOVE':
+        return strf('MOVE_ITEMS_REMAINING', remainNumber);
+      case 'ZIP':
+        return strf('ZIP_ITEMS_REMAINING', remainNumber);
+      default:
+        return strf('TRANSFER_ITEMS_REMAINING', remainNumber);
     }
   }
 };
@@ -141,9 +159,12 @@
  */
 FileOperationHandler.getType_ = operationType => {
   switch (operationType) {
-    case 'COPY': return ProgressItemType.COPY;
-    case 'MOVE': return ProgressItemType.MOVE;
-    case 'ZIP': return ProgressItemType.ZIP;
+    case 'COPY':
+      return ProgressItemType.COPY;
+    case 'MOVE':
+      return ProgressItemType.MOVE;
+    case 'ZIP':
+      return ProgressItemType.ZIP;
     default:
       console.error('Unknown operation type.');
       return ProgressItemType.TRANSFER;
@@ -171,8 +192,7 @@
       item.progressMax = event.status.totalBytes;
       item.progressValue = event.status.processedBytes;
       item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind(
-          this.fileOperationManager_,
-          event.taskId);
+          this.fileOperationManager_, event.taskId);
       progressCenter.updateItem(item);
       break;
 
@@ -237,11 +257,11 @@
       item.progressMax = event.totalBytes;
       item.progressValue = event.processedBytes;
       item.cancelCallback = this.fileOperationManager_.requestTaskCancel.bind(
-          this.fileOperationManager_,
-          event.taskId);
+          this.fileOperationManager_, event.taskId);
       this.pendingItems_[item.id] = item;
-      setTimeout(this.showPendingItem_.bind(this, item),
-                 FileOperationHandler.PENDING_TIME_MS_);
+      setTimeout(
+          this.showPendingItem_.bind(this, item),
+          FileOperationHandler.PENDING_TIME_MS_);
       break;
 
     case EventType.PROGRESS:
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager.js b/ui/file_manager/file_manager/background/js/file_operation_manager.js
index 5c1ed7e..fc627d5 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager.js
@@ -80,8 +80,7 @@
  */
 FileOperationManagerImpl.prototype.hasQueuedTasks = function() {
   return Object.keys(this.runningCopyTasks_).length > 0 ||
-      this.pendingCopyTasks_.length > 0 ||
-      this.deleteTasks_.length > 0;
+      this.pendingCopyTasks_.length > 0 || this.deleteTasks_.length > 0;
 };
 
 /**
@@ -107,8 +106,7 @@
     }
     task.requestCancel();
     this.eventRouter_.sendProgressEvent(
-        fileOperationUtil.EventRouter.EventType.CANCELED,
-        task.getStatus(),
+        fileOperationUtil.EventRouter.EventType.CANCELED, task.getStatus(),
         task.taskId);
     this.pendingCopyTasks_.splice(i, 1);
   }
@@ -146,40 +144,41 @@
  * @return {Promise} Promise fulfilled with the filtered entry. This is not
  *     rejected.
  */
-FileOperationManagerImpl.prototype.filterSameDirectoryEntry = (sourceEntries, targetEntry, isMove) => {
-  if (!isMove) {
-    return Promise.resolve(sourceEntries);
-  }
-  // Utility function to concat arrays.
-  const compactArrays = arrays => {
-    return arrays.filter(element => {
-      return !!element;
-    });
-  };
-  // Call processEntry for each item of entries.
-  const processEntries = entries => {
-    const promises = entries.map(processFileOrDirectoryEntries);
-    return Promise.all(promises).then(compactArrays);
-  };
-  // Check all file entries and keeps only those need sharing operation.
-  var processFileOrDirectoryEntries = entry => {
-    return new Promise(resolve => {
-      entry.getParent(
-          inParentEntry => {
-            if (!util.isSameEntry(inParentEntry, targetEntry)) {
-              resolve(entry);
-            } else {
-              resolve(null);
-            }
-          },
-          error => {
-            console.error(error.stack || error);
-            resolve(null);
-          });
-    });
-  };
-  return processEntries(sourceEntries);
-};
+FileOperationManagerImpl.prototype.filterSameDirectoryEntry =
+    (sourceEntries, targetEntry, isMove) => {
+      if (!isMove) {
+        return Promise.resolve(sourceEntries);
+      }
+      // Utility function to concat arrays.
+      const compactArrays = arrays => {
+        return arrays.filter(element => {
+          return !!element;
+        });
+      };
+      // Call processEntry for each item of entries.
+      const processEntries = entries => {
+        const promises = entries.map(processFileOrDirectoryEntries);
+        return Promise.all(promises).then(compactArrays);
+      };
+      // Check all file entries and keeps only those need sharing operation.
+      var processFileOrDirectoryEntries = entry => {
+        return new Promise(resolve => {
+          entry.getParent(
+              inParentEntry => {
+                if (!util.isSameEntry(inParentEntry, targetEntry)) {
+                  resolve(entry);
+                } else {
+                  resolve(null);
+                }
+              },
+              error => {
+                console.error(error.stack || error);
+                resolve(null);
+              });
+        });
+      };
+      return processEntries(sourceEntries);
+    };
 
 /**
  * Kick off pasting.
@@ -232,8 +231,8 @@
     // When moving between different volumes, moving is implemented as a copy
     // and delete. This is because moving between volumes is slow, and moveTo()
     // is not cancellable nor provides progress feedback.
-    if (util.isSameFileSystem(entries[0].filesystem,
-                              targetDirEntry.filesystem)) {
+    if (util.isSameFileSystem(
+            entries[0].filesystem, targetDirEntry.filesystem)) {
       task = new fileOperationUtil.MoveTask(taskId, entries, targetDirEntry);
     } else {
       task =
@@ -245,8 +244,7 @@
   }
 
   this.eventRouter_.sendProgressEvent(
-      fileOperationUtil.EventRouter.EventType.BEGIN,
-      task.getStatus(),
+      fileOperationUtil.EventRouter.EventType.BEGIN, task.getStatus(),
       task.taskId);
 
   task.initialize(() => {
@@ -293,8 +291,7 @@
         /** @type {!DirectoryEntry} */ (task.targetDirEntry));
     if (volumeInfo === null) {
       this.eventRouter_.sendProgressEvent(
-          fileOperationUtil.EventRouter.EventType.ERROR,
-          task.getStatus(),
+          fileOperationUtil.EventRouter.EventType.ERROR, task.getStatus(),
           task.taskId,
           new fileOperationUtil.Error(
               util.FileOperationErrorType.FILESYSTEM_ERROR,
@@ -321,8 +318,7 @@
 
   const onTaskProgress = function(task) {
     this.eventRouter_.sendProgressEvent(
-        fileOperationUtil.EventRouter.EventType.PROGRESS,
-        task.getStatus(),
+        fileOperationUtil.EventRouter.EventType.PROGRESS, task.getStatus(),
         task.taskId);
   }.bind(this, nextTask);
 
@@ -339,10 +335,8 @@
     const reason = err.data.name === util.FileError.ABORT_ERR ?
         fileOperationUtil.EventRouter.EventType.CANCELED :
         fileOperationUtil.EventRouter.EventType.ERROR;
-    this.eventRouter_.sendProgressEvent(reason,
-                                        task.getStatus(),
-                                        task.taskId,
-                                        err);
+    this.eventRouter_.sendProgressEvent(
+        reason, task.getStatus(), task.taskId, err);
     this.serviceAllTasks_();
   }.bind(this, nextTaskVolumeId);
 
@@ -351,8 +345,7 @@
     delete this.runningCopyTasks_[volumeId];
 
     this.eventRouter_.sendProgressEvent(
-        fileOperationUtil.EventRouter.EventType.SUCCESS,
-        task.getStatus(),
+        fileOperationUtil.EventRouter.EventType.SUCCESS, task.getStatus(),
         task.taskId);
     this.serviceAllTasks_();
   }.bind(this, nextTaskVolumeId);
@@ -361,8 +354,7 @@
   this.runningCopyTasks_[nextTaskVolumeId] = nextTask;
 
   this.eventRouter_.sendProgressEvent(
-      fileOperationUtil.EventRouter.EventType.PROGRESS,
-      nextTask.getStatus(),
+      fileOperationUtil.EventRouter.EventType.PROGRESS, nextTask.getStatus(),
       nextTask.taskId);
   nextTask.run(onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
 };
@@ -422,14 +414,12 @@
  * @private
  */
 FileOperationManagerImpl.prototype.serviceAllDeleteTasks_ = function() {
-  this.serviceDeleteTask_(
-      this.deleteTasks_[0],
-      () => {
-        this.deleteTasks_.shift();
-        if (this.deleteTasks_.length) {
-          this.serviceAllDeleteTasks_();
-        }
-      });
+  this.serviceDeleteTask_(this.deleteTasks_[0], () => {
+    this.deleteTasks_.shift();
+    if (this.deleteTasks_.length) {
+      this.serviceAllDeleteTasks_();
+    }
+  });
 };
 
 /**
@@ -496,8 +486,7 @@
   const zipTask = new fileOperationUtil.ZipTask(
       this.generateTaskId(), selectionEntries, dirEntry, dirEntry);
   this.eventRouter_.sendProgressEvent(
-      fileOperationUtil.EventRouter.EventType.BEGIN,
-      zipTask.getStatus(),
+      fileOperationUtil.EventRouter.EventType.BEGIN, zipTask.getStatus(),
       zipTask.taskId);
   zipTask.initialize(() => {
     this.pendingCopyTasks_.push(zipTask);
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
index 84b4c02..c9c24f1 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.js
@@ -47,8 +47,8 @@
   this.numberOfBeginEvents = 0;
   this.numberOfErrorEvents = 0;
   this.numberOfSuccessEvents = 0;
-  fileOperationManager.addEventListener('copy-progress',
-      this.onCopyProgress_.bind(this));
+  fileOperationManager.addEventListener(
+      'copy-progress', this.onCopyProgress_.bind(this));
 }
 
 /**
@@ -108,8 +108,8 @@
 
   const completeCopyOperation = copyId => {
     const newPath = joinPath('/', newName);
-    const fileSystem = getFileSystemForURL(
-        this.fileSystems_, destination.toURL());
+    const fileSystem =
+        getFileSystemForURL(this.fileSystems_, destination.toURL());
     const mockEntry = /** @type {!MockEntry} */ (this.sourceEntry_);
     fileSystem.entries[newPath] =
         /** @type {!MockEntry} */ (mockEntry.clone(newPath));
@@ -145,7 +145,7 @@
  * @return {!Object}
  */
 FakeVolumeManager.prototype.getVolumeInfo = function(entry) {
-  return { volumeId: entry.filesystem.name };
+  return {volumeId: entry.filesystem.name};
 };
 
 /**
@@ -280,7 +280,7 @@
   const fileSystem = createTestFileSystem('testVolume', {
     '/': DIRECTORY_SIZE,
     '/file': 10,
-    '/directory': DIRECTORY_SIZE
+    '/directory': DIRECTORY_SIZE,
   });
   const root = fileSystem.root;
   const rootPromise = fileOperationUtil.resolvePath(root, '/');
@@ -295,19 +295,25 @@
               error => {
                 return error.name;
               });
-  reportPromise(Promise.all([
-    rootPromise,
-    filePromise,
-    directoryPromise,
-    errorPromise
-  ]).then(results => {
-    assertArrayEquals([
-      fileSystem.entries['/'],
-      fileSystem.entries['/file'],
-      fileSystem.entries['/directory'],
-      'NotFoundError'
-    ], results);
-  }), callback);
+  reportPromise(
+      Promise
+          .all([
+            rootPromise,
+            filePromise,
+            directoryPromise,
+            errorPromise,
+          ])
+          .then(results => {
+            assertArrayEquals(
+                [
+                  fileSystem.entries['/'],
+                  fileSystem.entries['/file'],
+                  fileSystem.entries['/directory'],
+                  'NotFoundError',
+                ],
+                results);
+          }),
+      callback);
 }
 
 /**
@@ -372,15 +378,13 @@
           fileEntry => {
             foundFiles.push(fileEntry);
           })
-      .then(
-          () => {
-            assertEquals(10, foundFiles.length);
-            foundFiles.forEach(
-                entry => {
-                  assertTrue(entry.isFile);
-                });
-            callback(false);
-          })
+      .then(() => {
+        assertEquals(10, foundFiles.length);
+        foundFiles.forEach(entry => {
+          assertTrue(entry.isFile);
+        });
+        callback(false);
+      })
       .catch(() => {
         const error = true;
         callback(error);
@@ -425,7 +429,7 @@
   const fileSystem1 = createTestFileSystem('testVolume', {'/': DIRECTORY_SIZE});
   const fileSystem2 = createTestFileSystem('testVolume', {
     '/': DIRECTORY_SIZE,
-    '/file.txt': 10
+    '/file.txt': 10,
   });
   const fileSystem3 = createTestFileSystem('testVolume', {
     '/': DIRECTORY_SIZE,
@@ -442,20 +446,20 @@
   });
 
   const nonExistingPromise =
-      fileOperationUtil.deduplicatePath(fileSystem1.root, 'file.txt').
-      then(path => {
-        assertEquals('file.txt', path);
-      });
+      fileOperationUtil.deduplicatePath(fileSystem1.root, 'file.txt')
+          .then(path => {
+            assertEquals('file.txt', path);
+          });
   const existingPathPromise =
-      fileOperationUtil.deduplicatePath(fileSystem2.root, 'file.txt').
-      then(path => {
-        assertEquals('file (1).txt', path);
-      });
+      fileOperationUtil.deduplicatePath(fileSystem2.root, 'file.txt')
+          .then(path => {
+            assertEquals('file (1).txt', path);
+          });
   const moreExistingPathPromise =
-      fileOperationUtil.deduplicatePath(fileSystem3.root, 'file.txt').
-      then(path => {
-        assertEquals('file (10).txt', path);
-      });
+      fileOperationUtil.deduplicatePath(fileSystem3.root, 'file.txt')
+          .then(path => {
+            assertEquals('file (10).txt', path);
+          });
 
   const testPromise = Promise.all([
     nonExistingPromise,
@@ -479,26 +483,27 @@
     resolveTestFileSystemURL(fileSystem, url, success, failure);
   };
 
-  mockChrome.fileManagerPrivate.startCopy = (source, destination, newName, callback) => {
-    const makeStatus = type => {
-      return {
-        type: type,
-        sourceUrl: source.toURL(),
-        destinationUrl: destination.toURL()
+  mockChrome.fileManagerPrivate.startCopy =
+      (source, destination, newName, callback) => {
+        const makeStatus = type => {
+          return {
+            type: type,
+            sourceUrl: source.toURL(),
+            destinationUrl: destination.toURL()
+          };
+        };
+        callback(1);
+        const listener = mockChrome.fileManagerPrivate.onCopyProgress.listener_;
+        listener(1, makeStatus('begin_copy_entry'));
+        listener(1, makeStatus('progress'));
+        const newPath = joinPath('/', newName);
+        const entry = /** @type {!MockEntry} */
+            (fileSystem.entries['/test.txt']);
+        fileSystem.entries[newPath] =
+            /** @type {!MockEntry} */ (entry.clone(newPath));
+        listener(1, makeStatus('end_copy_entry'));
+        listener(1, makeStatus('success'));
       };
-    };
-    callback(1);
-    const listener = mockChrome.fileManagerPrivate.onCopyProgress.listener_;
-    listener(1, makeStatus('begin_copy_entry'));
-    listener(1, makeStatus('progress'));
-    const newPath = joinPath('/', newName);
-    const entry = /** @type {!MockEntry} */
-        (fileSystem.entries['/test.txt']);
-    fileSystem.entries[newPath] =
-        /** @type {!MockEntry} */ (entry.clone(newPath));
-    listener(1, makeStatus('end_copy_entry'));
-    listener(1, makeStatus('success'));
-  };
 
   volumeManager = new FakeVolumeManager();
   fileOperationManager = new FileOperationManagerImpl();
@@ -507,29 +512,31 @@
   const eventsPromise = waitForEvents(fileOperationManager);
 
   // Verify the events.
-  reportPromise(eventsPromise.then(events => {
-    const firstEvent = events[0];
-    assertEquals('BEGIN', firstEvent.reason);
-    assertEquals(1, firstEvent.status.numRemainingItems);
-    assertEquals(0, firstEvent.status.processedBytes);
-    assertEquals(1, firstEvent.status.totalBytes);
+  reportPromise(
+      eventsPromise.then(events => {
+        const firstEvent = events[0];
+        assertEquals('BEGIN', firstEvent.reason);
+        assertEquals(1, firstEvent.status.numRemainingItems);
+        assertEquals(0, firstEvent.status.processedBytes);
+        assertEquals(1, firstEvent.status.totalBytes);
 
-    const lastEvent = events[events.length - 1];
-    assertEquals('SUCCESS', lastEvent.reason);
-    assertEquals(0, lastEvent.status.numRemainingItems);
-    assertEquals(10, lastEvent.status.processedBytes);
-    assertEquals(10, lastEvent.status.totalBytes);
+        const lastEvent = events[events.length - 1];
+        assertEquals('SUCCESS', lastEvent.reason);
+        assertEquals(0, lastEvent.status.numRemainingItems);
+        assertEquals(10, lastEvent.status.processedBytes);
+        assertEquals(10, lastEvent.status.totalBytes);
 
-    assertTrue(events.some(event => {
-      return event.type === 'entries-changed' &&
-          event.kind === util.EntryChangedKind.CREATED &&
-          event.entries[0].fullPath === '/test (1).txt';
-    }));
+        assertTrue(events.some(event => {
+          return event.type === 'entries-changed' &&
+              event.kind === util.EntryChangedKind.CREATED &&
+              event.entries[0].fullPath === '/test (1).txt';
+        }));
 
-    assertFalse(events.some(event => {
-      return event.type === 'delete';
-    }));
-  }), callback);
+        assertFalse(events.some(event => {
+          return event.type === 'delete';
+        }));
+      }),
+      callback);
 
   fileOperationManager.paste(
       [fileSystem.entries['/test.txt']],
@@ -545,7 +552,7 @@
   const fileSystem = createTestFileSystem('testVolume', {
     '/': DIRECTORY_SIZE,
     '/dest': DIRECTORY_SIZE,
-    '/test.txt': 10
+    '/test.txt': 10,
   });
   window.webkitResolveLocalFileSystemURL = (url, success, failure) => {
     resolveTestFileSystemURL(fileSystem, url, success, failure);
@@ -569,52 +576,62 @@
       /** @type {!DirectoryEntry} */ (fileSystem.entries['/dest']), false);
 
   let firstOperationTaskId;
-  reportPromise(waitUntil(() => {
-    // Wait until the first operation is blocked.
-    return blockableFakeStartCopy.resolveBlockedOperationCallback !== null;
-  }).then(() => {
-    assertEquals(1, eventLogger.events.length);
-    assertEquals('BEGIN', eventLogger.events[0].reason);
-    firstOperationTaskId = eventLogger.events[0].taskId;
+  reportPromise(
+      waitUntil(() => {
+        // Wait until the first operation is blocked.
+        return blockableFakeStartCopy.resolveBlockedOperationCallback !== null;
+      })
+          .then(() => {
+            assertEquals(1, eventLogger.events.length);
+            assertEquals('BEGIN', eventLogger.events[0].reason);
+            firstOperationTaskId = eventLogger.events[0].taskId;
 
-    // Copy test.txt to /. This operation should be blocked.
-    fileOperationManager.paste(
-        [fileSystem.entries['/test.txt']],
-        /** @type {!DirectoryEntry} */ (fileSystem.entries['/']), false);
+            // Copy test.txt to /. This operation should be blocked.
+            fileOperationManager.paste(
+                [fileSystem.entries['/test.txt']],
+                /** @type {!DirectoryEntry} */ (fileSystem.entries['/']),
+                false);
 
-    return waitUntil(() => {
-      return fileOperationManager.getPendingCopyTasksForTesting().length === 1;
-    });
-  }).then(() => {
-    // Asserts that the second operation is added to pending copy tasks. Current
-    // implementation run tasks synchronusly after adding it to pending tasks.
-    // TODO(yawano) This check deeply depends on the implementation. Find a
-    //     better way to test this.
-    const pendingTask = fileOperationManager.getPendingCopyTasksForTesting()[0];
-    assertEquals(fileSystem.entries['/'], pendingTask.targetDirEntry);
+            return waitUntil(() => {
+              return fileOperationManager.getPendingCopyTasksForTesting()
+                         .length === 1;
+            });
+          })
+          .then(() => {
+            // Asserts that the second operation is added to pending copy tasks.
+            // Current implementation run tasks synchronusly after adding it to
+            // pending tasks.
+            // TODO(yawano) This check deeply depends on the implementation.
+            // Find a
+            //     better way to test this.
+            const pendingTask =
+                fileOperationManager.getPendingCopyTasksForTesting()[0];
+            assertEquals(fileSystem.entries['/'], pendingTask.targetDirEntry);
 
-    blockableFakeStartCopy.resolveBlockedOperationCallback();
+            blockableFakeStartCopy.resolveBlockedOperationCallback();
 
-    return waitUntil(() => {
-      return eventLogger.numberOfSuccessEvents === 2;
-    });
-  }).then(() => {
-    // Events should be the following.
-    // BEGIN: first operation
-    // BEGIN: second operation
-    // SUCCESS: first operation
-    // SUCCESS: second operation
-    const events = eventLogger.events;
-    assertEquals(4, events.length);
-    assertEquals('BEGIN', events[0].reason);
-    assertEquals(firstOperationTaskId, events[0].taskId);
-    assertEquals('BEGIN', events[1].reason);
-    assertTrue(events[1].taskId !== firstOperationTaskId);
-    assertEquals('SUCCESS', events[2].reason);
-    assertEquals(firstOperationTaskId, events[2].taskId);
-    assertEquals('SUCCESS', events[3].reason);
-    assertEquals(events[1].taskId, events[3].taskId);
-  }), callback);
+            return waitUntil(() => {
+              return eventLogger.numberOfSuccessEvents === 2;
+            });
+          })
+          .then(() => {
+            // Events should be the following.
+            // BEGIN: first operation
+            // BEGIN: second operation
+            // SUCCESS: first operation
+            // SUCCESS: second operation
+            const events = eventLogger.events;
+            assertEquals(4, events.length);
+            assertEquals('BEGIN', events[0].reason);
+            assertEquals(firstOperationTaskId, events[0].taskId);
+            assertEquals('BEGIN', events[1].reason);
+            assertTrue(events[1].taskId !== firstOperationTaskId);
+            assertEquals('SUCCESS', events[2].reason);
+            assertEquals(firstOperationTaskId, events[2].taskId);
+            assertEquals('SUCCESS', events[3].reason);
+            assertEquals(events[1].taskId, events[3].taskId);
+          }),
+      callback);
 }
 
 /**
@@ -625,7 +642,7 @@
   // Prepare entries and their resolver.
   const fileSystemA = createTestFileSystem('volumeA', {
     '/': DIRECTORY_SIZE,
-    '/test.txt': 10
+    '/test.txt': 10,
   });
   const fileSystemB = createTestFileSystem('volumeB', {
     '/': DIRECTORY_SIZE,
@@ -638,9 +655,7 @@
   };
 
   const blockableFakeStartCopy = new BlockableFakeStartCopy(
-      'filesystem:volumeB/',
-      fileSystemA.entries['/test.txt'],
-      fileSystems);
+      'filesystem:volumeB/', fileSystemA.entries['/test.txt'], fileSystems);
   mockChrome.fileManagerPrivate.startCopy =
       blockableFakeStartCopy.startCopyFunc.bind(blockableFakeStartCopy);
 
@@ -656,48 +671,54 @@
       /** @type {!DirectoryEntry} */ (fileSystemB.entries['/']), false);
 
   let firstOperationTaskId;
-  reportPromise(waitUntil(() => {
-    return blockableFakeStartCopy.resolveBlockedOperationCallback !== null;
-  }).then(() => {
-    assertEquals(1, eventLogger.events.length);
-    assertEquals('BEGIN', eventLogger.events[0].reason);
-    firstOperationTaskId = eventLogger.events[0].taskId;
+  reportPromise(
+      waitUntil(() => {
+        return blockableFakeStartCopy.resolveBlockedOperationCallback !== null;
+      })
+          .then(() => {
+            assertEquals(1, eventLogger.events.length);
+            assertEquals('BEGIN', eventLogger.events[0].reason);
+            firstOperationTaskId = eventLogger.events[0].taskId;
 
-    // Copy test.txt from volume A to volume A. This should not be blocked by
-    // the previous operation.
-    fileOperationManager.paste(
-        [fileSystemA.entries['/test.txt']],
-        /** @type {!DirectoryEntry} */ (fileSystemA.entries['/']), false);
+            // Copy test.txt from volume A to volume A. This should not be
+            // blocked by the previous operation.
+            fileOperationManager.paste(
+                [fileSystemA.entries['/test.txt']],
+                /** @type {!DirectoryEntry} */ (fileSystemA.entries['/']),
+                false);
 
-    // Wait until the second operation is completed.
-    return waitUntil(() => {
-      return eventLogger.numberOfSuccessEvents === 1;
-    });
-  }).then(() => {
-    // Resolve the blocked operation.
-    blockableFakeStartCopy.resolveBlockedOperationCallback();
+            // Wait until the second operation is completed.
+            return waitUntil(() => {
+              return eventLogger.numberOfSuccessEvents === 1;
+            });
+          })
+          .then(() => {
+            // Resolve the blocked operation.
+            blockableFakeStartCopy.resolveBlockedOperationCallback();
 
-    // Wait until the blocked operation is completed.
-    return waitUntil(() => {
-      return eventLogger.numberOfSuccessEvents === 2;
-    });
-  }).then(() => {
-    // Events should be following.
-    // BEGIN: first operation
-    // BEGIN: second operation
-    // SUCCESS: second operation
-    // SUCCESS: first operation
-    const events = eventLogger.events;
-    assertEquals(4, events.length);
-    assertEquals('BEGIN', events[0].reason);
-    assertEquals(firstOperationTaskId, events[0].taskId);
-    assertEquals('BEGIN', events[1].reason);
-    assertTrue(firstOperationTaskId !== events[1].taskId);
-    assertEquals('SUCCESS', events[2].reason);
-    assertEquals(events[1].taskId, events[2].taskId);
-    assertEquals('SUCCESS', events[3].reason);
-    assertEquals(firstOperationTaskId, events[3].taskId);
-  }), callback);
+            // Wait until the blocked operation is completed.
+            return waitUntil(() => {
+              return eventLogger.numberOfSuccessEvents === 2;
+            });
+          })
+          .then(() => {
+            // Events should be following.
+            // BEGIN: first operation
+            // BEGIN: second operation
+            // SUCCESS: second operation
+            // SUCCESS: first operation
+            const events = eventLogger.events;
+            assertEquals(4, events.length);
+            assertEquals('BEGIN', events[0].reason);
+            assertEquals(firstOperationTaskId, events[0].taskId);
+            assertEquals('BEGIN', events[1].reason);
+            assertTrue(firstOperationTaskId !== events[1].taskId);
+            assertEquals('SUCCESS', events[2].reason);
+            assertEquals(events[1].taskId, events[2].taskId);
+            assertEquals('SUCCESS', events[3].reason);
+            assertEquals(firstOperationTaskId, events[3].taskId);
+          }),
+      callback);
 }
 
 /**
@@ -708,7 +729,7 @@
   // Prepare entries.
   const fileSystem = createTestFileSystem('testVolume', {
     '/': DIRECTORY_SIZE,
-    '/test.txt': 10
+    '/test.txt': 10,
   });
 
   volumeManager = {
@@ -728,20 +749,23 @@
       [fileSystem.entries['/test.txt']],
       /** @type {!DirectoryEntry} */ (fileSystem.entries['/']), false);
 
-  reportPromise(waitUntil(() => {
-    return eventLogger.numberOfErrorEvents === 1;
-  }).then(() => {
-    // Since the task fails with an error, pending copy tasks should be empty.
-    assertEquals(0,
-        fileOperationManager.getPendingCopyTasksForTesting().length);
+  reportPromise(
+      waitUntil(() => {
+        return eventLogger.numberOfErrorEvents === 1;
+      }).then(() => {
+        // Since the task fails with an error, pending copy tasks should be
+        // empty.
+        assertEquals(
+            0, fileOperationManager.getPendingCopyTasksForTesting().length);
 
-    // Check events.
-    const events = eventLogger.events;
-    assertEquals(2, events.length);
-    assertEquals('BEGIN', events[0].reason);
-    assertEquals('ERROR', events[1].reason);
-    assertEquals(events[0].taskId, events[1].taskId);
-  }), callback);
+        // Check events.
+        const events = eventLogger.events;
+        assertEquals(2, events.length);
+        assertEquals('BEGIN', events[0].reason);
+        assertEquals('ERROR', events[1].reason);
+        assertEquals(events[0].taskId, events[1].taskId);
+      }),
+      callback);
 }
 
 /**
@@ -766,35 +790,37 @@
   const eventsPromise = waitForEvents(fileOperationManager);
 
   // Verify the events.
-  reportPromise(eventsPromise.then(events => {
-    const firstEvent = events[0];
-    assertEquals('BEGIN', firstEvent.reason);
-    assertEquals(1, firstEvent.status.numRemainingItems);
-    assertEquals(0, firstEvent.status.processedBytes);
-    assertEquals(1, firstEvent.status.totalBytes);
+  reportPromise(
+      eventsPromise.then(events => {
+        const firstEvent = events[0];
+        assertEquals('BEGIN', firstEvent.reason);
+        assertEquals(1, firstEvent.status.numRemainingItems);
+        assertEquals(0, firstEvent.status.processedBytes);
+        assertEquals(1, firstEvent.status.totalBytes);
 
-    const lastEvent = events[events.length - 1];
-    assertEquals('SUCCESS', lastEvent.reason);
-    assertEquals(0, lastEvent.status.numRemainingItems);
-    assertEquals(1, lastEvent.status.processedBytes);
-    assertEquals(1, lastEvent.status.totalBytes);
+        const lastEvent = events[events.length - 1];
+        assertEquals('SUCCESS', lastEvent.reason);
+        assertEquals(0, lastEvent.status.numRemainingItems);
+        assertEquals(1, lastEvent.status.processedBytes);
+        assertEquals(1, lastEvent.status.totalBytes);
 
-    assertTrue(events.some(event => {
-      return event.type === 'entries-changed' &&
-          event.kind === util.EntryChangedKind.DELETED &&
-          event.entries[0].fullPath === '/test.txt';
-    }));
+        assertTrue(events.some(event => {
+          return event.type === 'entries-changed' &&
+              event.kind === util.EntryChangedKind.DELETED &&
+              event.entries[0].fullPath === '/test.txt';
+        }));
 
-    assertTrue(events.some(event => {
-      return event.type === 'entries-changed' &&
-          event.kind === util.EntryChangedKind.CREATED &&
-          event.entries[0].fullPath === '/directory/test.txt';
-    }));
+        assertTrue(events.some(event => {
+          return event.type === 'entries-changed' &&
+              event.kind === util.EntryChangedKind.CREATED &&
+              event.entries[0].fullPath === '/directory/test.txt';
+        }));
 
-    assertFalse(events.some(event => {
-      return event.type === 'delete';
-    }));
-  }), callback);
+        assertFalse(events.some(event => {
+          return event.type === 'delete';
+        }));
+      }),
+      callback);
 
   fileOperationManager.paste(
       [fileSystem.entries['/test.txt']],
@@ -865,27 +891,29 @@
   fileOperationManager = new FileOperationManagerImpl();
 
   // Observing manager's events.
-  reportPromise(waitForEvents(fileOperationManager).then(events => {
-    assertEquals('copy-progress', events[0].type);
-    assertEquals('BEGIN', events[0].reason);
-    assertEquals(1, events[0].status.totalBytes);
-    assertEquals(0, events[0].status.processedBytes);
+  reportPromise(
+      waitForEvents(fileOperationManager).then(events => {
+        assertEquals('copy-progress', events[0].type);
+        assertEquals('BEGIN', events[0].reason);
+        assertEquals(1, events[0].status.totalBytes);
+        assertEquals(0, events[0].status.processedBytes);
 
-    const lastEvent = events[events.length - 1];
-    assertEquals('copy-progress', lastEvent.type);
-    assertEquals('SUCCESS', lastEvent.reason);
-    assertEquals(10, lastEvent.status.totalBytes);
-    assertEquals(10, lastEvent.status.processedBytes);
+        const lastEvent = events[events.length - 1];
+        assertEquals('copy-progress', lastEvent.type);
+        assertEquals('SUCCESS', lastEvent.reason);
+        assertEquals(10, lastEvent.status.totalBytes);
+        assertEquals(10, lastEvent.status.processedBytes);
 
-    assertFalse(events.some(event => {
-      return event.type === 'delete';
-    }));
+        assertFalse(events.some(event => {
+          return event.type === 'delete';
+        }));
 
-    assertTrue(events.some(event => {
-      return event.type === 'entries-changed' &&
-          event.entries[0].fullPath === '/test.zip';
-    }));
-  }), callback);
+        assertTrue(events.some(event => {
+          return event.type === 'entries-changed' &&
+              event.entries[0].fullPath === '/test.zip';
+        }));
+      }),
+      callback);
 
   fileOperationManager.zipSelection(
       [fileSystem.entries['/test.txt']],
diff --git a/ui/file_manager/file_manager/background/js/file_operation_util.js b/ui/file_manager/file_manager/background/js/file_operation_util.js
index 211a0fd..cdbebe7 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_util.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_util.js
@@ -20,8 +20,8 @@
   if (path === '' || path === '/') {
     return Promise.resolve(root);
   }
-  return new Promise(root.getFile.bind(root, path, {create: false})).
-      catch(error => {
+  return new Promise(root.getFile.bind(root, path, {create: false}))
+      .catch(error => {
         if (error.name === util.FileError.TYPE_MISMATCH_ERR) {
           // Bah.  It's a directory, ask again.
           return new Promise(
@@ -48,44 +48,49 @@
  *     on error.
  * @return {Promise} Promise fulfilled with available path.
  */
-fileOperationUtil.deduplicatePath = (dirEntry, relativePath, opt_successCallback, opt_errorCallback) => {
-  // Crack the path into three part. The parenthesized number (if exists) will
-  // be replaced by incremented number for retry. For example, suppose
-  // |relativePath| is "file (10).txt", the second check path will be
-  // "file (11).txt".
-  const match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath);
-  const prefix = match[1];
-  const ext = match[3] || '';
+fileOperationUtil.deduplicatePath =
+    (dirEntry, relativePath, opt_successCallback, opt_errorCallback) => {
+      // Crack the path into three part. The parenthesized number (if exists)
+      // will be replaced by incremented number for retry. For example, suppose
+      // |relativePath| is "file (10).txt", the second check path will be
+      // "file (11).txt".
+      const match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath);
+      const prefix = match[1];
+      const ext = match[3] || '';
 
-  // Check to see if the target exists.
-  const resolvePath = (trialPath, copyNumber) => {
-    return fileOperationUtil.resolvePath(dirEntry, trialPath).then(() => {
-      const newTrialPath = prefix + ' (' + copyNumber + ')' + ext;
-      return resolvePath(newTrialPath, copyNumber + 1);
-    }, error => {
-      // We expect to be unable to resolve the target file, since we're
-      // going to create it during the copy.  However, if the resolve fails
-      // with anything other than NOT_FOUND, that's trouble.
-      if (error.name === util.FileError.NOT_FOUND_ERR) {
-        return trialPath;
-      } else {
-        return Promise.reject(error);
+      // Check to see if the target exists.
+      const resolvePath = (trialPath, copyNumber) => {
+        return fileOperationUtil.resolvePath(dirEntry, trialPath)
+            .then(
+                () => {
+                  const newTrialPath = prefix + ' (' + copyNumber + ')' + ext;
+                  return resolvePath(newTrialPath, copyNumber + 1);
+                },
+                error => {
+                  // We expect to be unable to resolve the target file, since
+                  // we're going to create it during the copy.  However, if the
+                  // resolve fails with anything other than NOT_FOUND, that's
+                  // trouble.
+                  if (error.name === util.FileError.NOT_FOUND_ERR) {
+                    return trialPath;
+                  } else {
+                    return Promise.reject(error);
+                  }
+                });
+      };
+
+      const promise = resolvePath(relativePath, 1).catch(error => {
+        if (error instanceof Error) {
+          return Promise.reject(error);
+        }
+        return Promise.reject(new fileOperationUtil.Error(
+            util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+      });
+      if (opt_successCallback) {
+        promise.then(opt_successCallback, opt_errorCallback);
       }
-    });
-  };
-
-  const promise = resolvePath(relativePath, 1).catch(error => {
-    if (error instanceof Error) {
-      return Promise.reject(error);
-    }
-    return Promise.reject(new fileOperationUtil.Error(
-      util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-  });
-  if (opt_successCallback) {
-    promise.then(opt_successCallback, opt_errorCallback);
-  }
-  return promise;
-};
+      return promise;
+    };
 
 /**
  * Traverses files/subdirectories of the given entry, and returns them.
@@ -99,47 +104,47 @@
  *     occurred error (i.e. following errors will just be discarded).
  * @private
  */
-fileOperationUtil.resolveRecursively_ = (entry, successCallback, errorCallback) => {
-  const result = [];
-  let error = null;
-  let numRunningTasks = 0;
+fileOperationUtil.resolveRecursively_ =
+    (entry, successCallback, errorCallback) => {
+      const result = [];
+      let error = null;
+      let numRunningTasks = 0;
 
-  const maybeInvokeCallback = () => {
-    // If there still remain some running tasks, wait their finishing.
-    if (numRunningTasks > 0) {
-      return;
-    }
+      const maybeInvokeCallback = () => {
+        // If there still remain some running tasks, wait their finishing.
+        if (numRunningTasks > 0) {
+          return;
+        }
 
-    if (error) {
-      errorCallback(error);
-    } else {
-      successCallback(result);
-    }
-  };
+        if (error) {
+          errorCallback(error);
+        } else {
+          successCallback(result);
+        }
+      };
 
-  // The error handling can be shared.
-  const onError = fileError => {
-    // If this is the first error, remember it.
-    if (!error) {
-      error = fileError;
-    }
-    --numRunningTasks;
-    maybeInvokeCallback();
-  };
+      // The error handling can be shared.
+      const onError = fileError => {
+        // If this is the first error, remember it.
+        if (!error) {
+          error = fileError;
+        }
+        --numRunningTasks;
+        maybeInvokeCallback();
+      };
 
-  const process = entry => {
-    numRunningTasks++;
-    result.push(entry);
-    if (entry.isDirectory) {
-      // The size of a directory is 1 bytes here, so that the progress bar
-      // will work smoother.
-      // TODO(hidehiko): Remove this hack.
-      entry.size = 1;
+      const process = entry => {
+        numRunningTasks++;
+        result.push(entry);
+        if (entry.isDirectory) {
+          // The size of a directory is 1 bytes here, so that the progress bar
+          // will work smoother.
+          // TODO(hidehiko): Remove this hack.
+          entry.size = 1;
 
-      // Recursively traverse children.
-      const reader = entry.createReader();
-      reader.readEntries(
-          function processSubEntries(subEntries) {
+          // Recursively traverse children.
+          const reader = entry.createReader();
+          reader.readEntries(function processSubEntries(subEntries) {
             if (error || subEntries.length == 0) {
               // If an error is found already, or this is the completion
               // callback, then finish the process.
@@ -154,20 +159,19 @@
 
             // Continue to read remaining children.
             reader.readEntries(processSubEntries, onError);
-          },
-          onError);
-    } else {
-      // For a file, annotate the file size.
-      metadataProxy.getEntryMetadata(entry).then(metadata => {
-        entry.size = metadata.size;
-        --numRunningTasks;
-        maybeInvokeCallback();
-      }, onError);
-    }
-  };
+          }, onError);
+        } else {
+          // For a file, annotate the file size.
+          metadataProxy.getEntryMetadata(entry).then(metadata => {
+            entry.size = metadata.size;
+            --numRunningTasks;
+            maybeInvokeCallback();
+          }, onError);
+        }
+      };
 
-  process(entry);
-};
+      process(entry);
+    };
 
 /**
  * Recursively gathers files from the given entry, resolving with
@@ -182,16 +186,16 @@
   /** @type {!Array<!Entry>} */
   const gatheredFiles = [];
 
-  return fileOperationUtil.findEntriesRecursively(
-      entry,
-      /** @param {!Entry} entry */
-      entry => {
-        gatheredFiles.push(entry);
-      })
-      .then(
-          () => {
-            return gatheredFiles;
-          });
+  return fileOperationUtil
+      .findEntriesRecursively(
+          entry,
+          /** @param {!Entry} entry */
+          entry => {
+            gatheredFiles.push(entry);
+          })
+      .then(() => {
+        return gatheredFiles;
+      });
 };
 
 /**
@@ -230,77 +234,74 @@
  * @return {!Promise} Resolves when scanning is complete.
  */
 fileOperationUtil.findEntriesRecursively = (entry, onResultCallback) => {
-  return new Promise(
-      (resolve, reject) => {
-        let numRunningTasks = 0;
-        let scanError = null;
+  return new Promise((resolve, reject) => {
+    let numRunningTasks = 0;
+    let scanError = null;
 
-        /**
-         * @param  {*=} opt_error If defined immediately
-         *     terminates scanning.
-         */
-        const maybeSettlePromise = opt_error => {
-          scanError = opt_error;
+    /**
+     * @param  {*=} opt_error If defined immediately
+     *     terminates scanning.
+     */
+    const maybeSettlePromise = opt_error => {
+      scanError = opt_error;
 
-          if (scanError) {
-            // Closure compiler currently requires an argument to reject.
-            reject(undefined);
-            return;
-          }
+      if (scanError) {
+        // Closure compiler currently requires an argument to reject.
+        reject(undefined);
+        return;
+      }
 
-          // If there still remain some running tasks, wait their finishing.
-          if (numRunningTasks === 0) {
-            // Closure compiler currently requires an argument to resolve.
-            resolve(undefined);
-          }
-        };
+      // If there still remain some running tasks, wait their finishing.
+      if (numRunningTasks === 0) {
+        // Closure compiler currently requires an argument to resolve.
+        resolve(undefined);
+      }
+    };
 
-        /** @param {!Entry} entry */
-        const processEntry = entry => {
-          // All scanning stops when an error is encountered.
-          if (scanError) {
-            return;
-          }
+    /** @param {!Entry} entry */
+    const processEntry = entry => {
+      // All scanning stops when an error is encountered.
+      if (scanError) {
+        return;
+      }
 
-          onResultCallback(entry);
-          if (entry.isDirectory) {
-            processDirectory(/** @type {!DirectoryEntry} */ (entry));
-          }
-        };
+      onResultCallback(entry);
+      if (entry.isDirectory) {
+        processDirectory(/** @type {!DirectoryEntry} */ (entry));
+      }
+    };
 
-        /** @param {!DirectoryEntry} directory */
-        var processDirectory = directory => {
-          // All scanning stops when an error is encountered.
-          if (scanError) {
-            return;
-          }
+    /** @param {!DirectoryEntry} directory */
+    var processDirectory = directory => {
+      // All scanning stops when an error is encountered.
+      if (scanError) {
+        return;
+      }
 
-          numRunningTasks++;
+      numRunningTasks++;
 
-          // Recursively traverse children.
-          // reader.readEntries chunksResults resulting in the need
-          // for us to call it multiple times.
-          const reader = directory.createReader();
-          reader.readEntries(
-              function processSubEntries(subEntries) {
-                if (subEntries.length === 0) {
-                  // If an error is found already, or this is the completion
-                  // callback, then finish the process.
-                  --numRunningTasks;
-                  maybeSettlePromise();
-                  return;
-                }
+      // Recursively traverse children.
+      // reader.readEntries chunksResults resulting in the need
+      // for us to call it multiple times.
+      const reader = directory.createReader();
+      reader.readEntries(function processSubEntries(subEntries) {
+        if (subEntries.length === 0) {
+          // If an error is found already, or this is the completion
+          // callback, then finish the process.
+          --numRunningTasks;
+          maybeSettlePromise();
+          return;
+        }
 
-                subEntries.forEach(processEntry);
+        subEntries.forEach(processEntry);
 
-                // Continue to read remaining children.
-                reader.readEntries(processSubEntries, maybeSettlePromise);
-              },
-              maybeSettlePromise);
-        };
+        // Continue to read remaining children.
+        reader.readEntries(processSubEntries, maybeSettlePromise);
+      }, maybeSettlePromise);
+    };
 
-        processEntry(entry);
-      });
+    processEntry(entry);
+  });
 };
 
 /**
@@ -311,26 +312,25 @@
  * @return {!Promise} Resolves when listing is complete.
  */
 fileOperationUtil.listEntries = (directory, callback) => {
-  return new Promise(
-      (resolve, reject) => {
-        const reader = directory.createReader();
+  return new Promise((resolve, reject) => {
+    const reader = directory.createReader();
 
-        const readEntries = () => {
-          reader.readEntries (
-              /** @param {!Array<!Entry>} entries */
-              entries => {
-                if (entries.length === 0) {
-                  resolve(undefined);
-                  return;
-                }
-                entries.forEach(callback);
-                readEntries();
-              },
-              reject);
-        };
+    const readEntries = () => {
+      reader.readEntries(
+          /** @param {!Array<!Entry>} entries */
+          entries => {
+            if (entries.length === 0) {
+              resolve(undefined);
+              return;
+            }
+            entries.forEach(callback);
+            readEntries();
+          },
+          reject);
+    };
 
-        readEntries();
-      });
+    readEntries();
+  });
 };
 
 /**
@@ -356,136 +356,128 @@
  *     When the cancel is done, errorCallback will be called. The returned
  *     callback must not be called more than once.
  */
-fileOperationUtil.copyTo = (
-  source,
-  parent,
-  newName,
-  entryChangedCallback,
-  progressCallback,
-  successCallback,
-  errorCallback
-) => {
+fileOperationUtil.copyTo =
+    (source, parent, newName, entryChangedCallback, progressCallback,
+     successCallback, errorCallback) => {
+      /** @type {number|undefined} */
+      let copyId;
+      const pendingCallbacks = [];
 
-  /** @type {number|undefined} */
-  let copyId;
-  const pendingCallbacks = [];
+      // Makes the callback called in order they were invoked.
+      const callbackQueue = new AsyncUtil.Queue();
 
-  // Makes the callback called in order they were invoked.
-  const callbackQueue = new AsyncUtil.Queue();
+      const onCopyProgress = (progressCopyId, status) => {
+        callbackQueue.run(callback => {
+          if (copyId === null) {
+            // If the copyId is not yet available, wait for it.
+            pendingCallbacks.push(
+                onCopyProgress.bind(null, progressCopyId, status));
+            callback();
+            return;
+          }
 
-  const onCopyProgress = (progressCopyId, status) => {
-    callbackQueue.run(callback => {
-      if (copyId === null) {
-        // If the copyId is not yet available, wait for it.
-        pendingCallbacks.push(
-            onCopyProgress.bind(null, progressCopyId, status));
-        callback();
-        return;
-      }
+          // This is not what we're interested in.
+          if (progressCopyId != copyId) {
+            callback();
+            return;
+          }
 
-      // This is not what we're interested in.
-      if (progressCopyId != copyId) {
-        callback();
-        return;
-      }
+          switch (status.type) {
+            case 'begin_copy_entry':
+              callback();
+              break;
 
-      switch (status.type) {
-        case 'begin_copy_entry':
-          callback();
-          break;
+            case 'end_copy_entry':
+              // TODO(mtomasz): Convert URL to Entry in custom bindings.
+              (source.isFile ? parent.getFile : parent.getDirectory)
+                  .call(
+                      parent, newName, null,
+                      entry => {
+                        entryChangedCallback(status.sourceUrl, entry);
+                        callback();
+                      },
+                      () => {
+                        entryChangedCallback(status.sourceUrl, null);
+                        callback();
+                      });
+              break;
 
-        case 'end_copy_entry':
-          // TODO(mtomasz): Convert URL to Entry in custom bindings.
-          (source.isFile ? parent.getFile : parent.getDirectory).call(
-              parent,
-              newName,
-              null,
-              entry => {
-                entryChangedCallback(status.sourceUrl, entry);
-                callback();
-              },
-              () => {
-                entryChangedCallback(status.sourceUrl, null);
-                callback();
-              });
-          break;
+            case 'progress':
+              progressCallback(status.sourceUrl, status.size);
+              callback();
+              break;
 
-        case 'progress':
-          progressCallback(status.sourceUrl, status.size);
-          callback();
-          break;
+            case 'success':
+              chrome.fileManagerPrivate.onCopyProgress.removeListener(
+                  onCopyProgress);
+              // TODO(mtomasz): Convert URL to Entry in custom bindings.
+              util.URLsToEntries(
+                  [status.destinationUrl], destinationEntries => {
+                    successCallback(destinationEntries[0] || null);
+                    callback();
+                  });
+              break;
 
-        case 'success':
-          chrome.fileManagerPrivate.onCopyProgress.removeListener(
-              onCopyProgress);
-          // TODO(mtomasz): Convert URL to Entry in custom bindings.
-          util.URLsToEntries(
-              [status.destinationUrl], destinationEntries => {
-                successCallback(destinationEntries[0] || null);
-                callback();
-              });
-          break;
+            case 'error':
+              console.error(
+                  'copy failed. sourceUrl: ' + source.toURL() +
+                  ' error: ' + status.error);
+              chrome.fileManagerPrivate.onCopyProgress.removeListener(
+                  onCopyProgress);
+              errorCallback(util.createDOMError(status.error));
+              callback();
+              break;
 
-        case 'error':
-          console.error(
-              'copy failed. sourceUrl: ' + source.toURL() +
-              ' error: ' + status.error);
-          chrome.fileManagerPrivate.onCopyProgress.removeListener(
-              onCopyProgress);
-          errorCallback(util.createDOMError(status.error));
-          callback();
-          break;
+            default:
+              // Found unknown state. Cancel the task, and return an error.
+              console.error('Unknown progress type: ' + status.type);
+              chrome.fileManagerPrivate.onCopyProgress.removeListener(
+                  onCopyProgress);
+              chrome.fileManagerPrivate.cancelCopy(
+                  assert(copyId), util.checkAPIError);
+              errorCallback(
+                  util.createDOMError(util.FileError.INVALID_STATE_ERR));
+              callback();
+          }
+        });
+      };
 
-        default:
-          // Found unknown state. Cancel the task, and return an error.
-          console.error('Unknown progress type: ' + status.type);
-          chrome.fileManagerPrivate.onCopyProgress.removeListener(
-              onCopyProgress);
-          chrome.fileManagerPrivate.cancelCopy(
-              assert(copyId), util.checkAPIError);
-          errorCallback(util.createDOMError(
-              util.FileError.INVALID_STATE_ERR));
-          callback();
-      }
-    });
-  };
+      // Register the listener before calling startCopy. Otherwise some events
+      // would be lost.
+      chrome.fileManagerPrivate.onCopyProgress.addListener(onCopyProgress);
 
-  // Register the listener before calling startCopy. Otherwise some events
-  // would be lost.
-  chrome.fileManagerPrivate.onCopyProgress.addListener(onCopyProgress);
+      // Then starts the copy.
+      chrome.fileManagerPrivate.startCopy(
+          source, parent, newName, startCopyId => {
+            // last error contains the FileError code on error.
+            if (chrome.runtime.lastError) {
+              // Unsubscribe the progress listener.
+              chrome.fileManagerPrivate.onCopyProgress.removeListener(
+                  onCopyProgress);
+              errorCallback(
+                  util.createDOMError(chrome.runtime.lastError.message || ''));
+              return;
+            }
 
-  // Then starts the copy.
-  chrome.fileManagerPrivate.startCopy(
-      source, parent, newName, startCopyId => {
-        // last error contains the FileError code on error.
-        if (chrome.runtime.lastError) {
-          // Unsubscribe the progress listener.
-          chrome.fileManagerPrivate.onCopyProgress.removeListener(
-              onCopyProgress);
-          errorCallback(util.createDOMError(
-              chrome.runtime.lastError.message || ''));
+            copyId = startCopyId;
+            for (let i = 0; i < pendingCallbacks.length; i++) {
+              pendingCallbacks[i]();
+            }
+          });
+
+      return () => {
+        // If copyId is not yet available, wait for it.
+        if (copyId === undefined) {
+          pendingCallbacks.push(() => {
+            chrome.fileManagerPrivate.cancelCopy(
+                assert(copyId), util.checkAPIError);
+          });
           return;
         }
 
-        copyId = startCopyId;
-        for (let i = 0; i < pendingCallbacks.length; i++) {
-          pendingCallbacks[i]();
-        }
-      });
-
-  return () => {
-    // If copyId is not yet available, wait for it.
-    if (copyId === undefined) {
-      pendingCallbacks.push(() => {
-        chrome.fileManagerPrivate.cancelCopy(
-            assert(copyId), util.checkAPIError);
-      });
-      return;
-    }
-
-    chrome.fileManagerPrivate.cancelCopy(copyId, util.checkAPIError);
-  };
-};
+        chrome.fileManagerPrivate.cancelCopy(copyId, util.checkAPIError);
+      };
+    };
 
 /**
  * Thin wrapper of chrome.fileManagerPrivate.zipSelection to adapt its
@@ -499,21 +491,22 @@
  * @param {function(DOMError)} errorCallback Callback invoked when an error
  *     is found.
  */
-fileOperationUtil.zipSelection = (sources, parent, newName, successCallback, errorCallback) => {
-  chrome.fileManagerPrivate.zipSelection(
-      sources, parent, newName, success => {
-        if (!success) {
-          // Failed to create a zip archive.
-          errorCallback(
-              util.createDOMError(util.FileError.INVALID_MODIFICATION_ERR));
-          return;
-        }
+fileOperationUtil.zipSelection =
+    (sources, parent, newName, successCallback, errorCallback) => {
+      chrome.fileManagerPrivate.zipSelection(
+          sources, parent, newName, success => {
+            if (!success) {
+              // Failed to create a zip archive.
+              errorCallback(
+                  util.createDOMError(util.FileError.INVALID_MODIFICATION_ERR));
+              return;
+            }
 
-        // Returns the created entry via callback.
-        parent.getFile(
-            newName, {create: false}, successCallback, errorCallback);
-      });
-};
+            // Returns the created entry via callback.
+            parent.getFile(
+                newName, {create: false}, successCallback, errorCallback);
+          });
+    };
 
 /**
  * A record of a queued copy operation.
@@ -598,8 +591,7 @@
 /**
  * @param {function()} callback When entries resolved.
  */
-fileOperationUtil.Task.prototype.initialize = callback => {
-};
+fileOperationUtil.Task.prototype.initialize = callback => {};
 
 /**
  * Requests cancellation of this task.
@@ -625,8 +617,9 @@
  * @param {function(fileOperationUtil.Error)} errorCallback Callback run on
  *     error.
  */
-fileOperationUtil.Task.prototype.run = (entryChangedCallback, progressCallback, successCallback, errorCallback) => {
-};
+fileOperationUtil.Task.prototype.run =
+    (entryChangedCallback, progressCallback, successCallback,
+     errorCallback) => {};
 
 /**
  * Get states of the task.
@@ -657,8 +650,8 @@
       break;
     }
     for (const name in entryMap) {
-      bytes += i < this.processingSourceIndex_ ?
-          entryMap[name].size : entryMap[name].processedBytes;
+      bytes += i < this.processingSourceIndex_ ? entryMap[name].size :
+                                                 entryMap[name].processedBytes;
     }
   }
   return bytes;
@@ -710,12 +703,10 @@
 fileOperationUtil.CopyTask = function(
     taskId, sourceEntries, targetDirEntry, deleteAfterCopy) {
   fileOperationUtil.Task.call(
-      this,
-      taskId,
-      deleteAfterCopy ?
-          util.FileOperationType.MOVE : util.FileOperationType.COPY,
-      sourceEntries,
-      targetDirEntry);
+      this, taskId,
+      deleteAfterCopy ? util.FileOperationType.MOVE :
+                        util.FileOperationType.COPY,
+      sourceEntries, targetDirEntry);
   this.deleteAfterCopy = deleteAfterCopy;
 
   /**
@@ -763,8 +754,7 @@
             callback();
           },
           error => {
-            console.error(
-                'Failed to resolve for copy: %s', error.name);
+            console.error('Failed to resolve for copy: %s', error.name);
             callback();
           });
     }.bind(this, i));
@@ -962,8 +952,7 @@
     sourceEntry, destinationEntry, entryChangedCallback, progressCallback,
     successCallback, errorCallback) {
   fileOperationUtil.deduplicatePath(
-      destinationEntry, sourceEntry.name,
-      destinationName => {
+      destinationEntry, sourceEntry.name, destinationName => {
         if (this.cancelRequested_) {
           errorCallback(new fileOperationUtil.Error(
               util.FileOperationErrorType.FILESYSTEM_ERROR,
@@ -982,8 +971,7 @@
               errorCallback(new fileOperationUtil.Error(
                   util.FileOperationErrorType.FILESYSTEM_ERROR, error));
             });
-      },
-      errorCallback);
+      }, errorCallback);
 };
 
 /**
@@ -1067,15 +1055,14 @@
         }
         progressCallback();
         fileOperationUtil.MoveTask.processEntry_(
-            assert(entry), assert(this.targetDirEntry), entryChangedCallback,
-            () => {
+            assert(entry), assert(this.targetDirEntry),
+            entryChangedCallback, () => {
               // Update current source index.
               this.processingSourceIndex_ = index + 1;
               this.processedBytes = this.calcProcessedBytes_();
               this.numRemainingItems = this.calcNumRemainingItems_();
               callback();
-            },
-            errorCallback);
+            }, errorCallback);
       },
       () => {
         successCallback();
@@ -1094,31 +1081,29 @@
  * @param {function(fileOperationUtil.Error)} errorCallback On error.
  * @private
  */
-fileOperationUtil.MoveTask.processEntry_ = (
-  sourceEntry,
-  destinationEntry,
-  entryChangedCallback,
-  successCallback,
-  errorCallback
-) => {
-  const destination =
-      /** @type{!DirectoryEntry} */ (
-          assert(util.unwrapEntry(destinationEntry)));
-  fileOperationUtil.deduplicatePath(
-      destination, sourceEntry.name, destinationName => {
-        sourceEntry.moveTo(
-            destination, destinationName,
-            movedEntry => {
-              entryChangedCallback(util.EntryChangedKind.CREATED, movedEntry);
-              entryChangedCallback(util.EntryChangedKind.DELETED, sourceEntry);
-              successCallback();
-            },
-            error => {
-              errorCallback(new fileOperationUtil.Error(
-                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-            });
-      }, errorCallback);
-};
+fileOperationUtil.MoveTask.processEntry_ =
+    (sourceEntry, destinationEntry, entryChangedCallback, successCallback,
+     errorCallback) => {
+      const destination =
+          /** @type{!DirectoryEntry} */ (
+              assert(util.unwrapEntry(destinationEntry)));
+      fileOperationUtil.deduplicatePath(
+          destination, sourceEntry.name, destinationName => {
+            sourceEntry.moveTo(
+                destination, destinationName,
+                movedEntry => {
+                  entryChangedCallback(
+                      util.EntryChangedKind.CREATED, movedEntry);
+                  entryChangedCallback(
+                      util.EntryChangedKind.DELETED, sourceEntry);
+                  successCallback();
+                },
+                error => {
+                  errorCallback(new fileOperationUtil.Error(
+                      util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+                });
+          }, errorCallback);
+    };
 
 /**
  * Task to create a zip archive.
@@ -1203,8 +1188,7 @@
   }
 
   fileOperationUtil.deduplicatePath(
-      this.targetDirEntry, destName + '.zip',
-      destPath => {
+      this.targetDirEntry, destName + '.zip', destPath => {
         // TODO: per-entry zip progress update with accurate byte count.
         // For now just set completedBytes to 0 so that it is not full until
         // the zip operatoin is done.
@@ -1219,9 +1203,7 @@
         }
 
         fileOperationUtil.zipSelection(
-            entries,
-            this.zipBaseDirEntry,
-            destPath,
+            entries, this.zipBaseDirEntry, destPath,
             entry => {
               this.processedBytes = this.totalBytes;
               entryChangedCallback(util.EntryChangedKind.CREATED, entry);
@@ -1231,8 +1213,7 @@
               errorCallback(new fileOperationUtil.Error(
                   util.FileOperationErrorType.FILESYSTEM_ERROR, error));
             });
-      },
-      errorCallback);
+      }, errorCallback);
 };
 
 /**
@@ -1362,7 +1343,8 @@
    * @param {!Object} task Delete task related with the event.
    */
   sendDeleteEvent(reason, task) {
-    const event = /** @type {FileOperationProgressEvent} */ (new Event('delete'));
+    const event =
+        /** @type {FileOperationProgressEvent} */ (new Event('delete'));
     event.reason = reason;
     event.taskId = task.taskId;
     event.entries = task.entries;
diff --git a/ui/file_manager/file_manager/background/js/import_history.js b/ui/file_manager/file_manager/background/js/import_history.js
index 64d42323..354d950 100644
--- a/ui/file_manager/file_manager/background/js/import_history.js
+++ b/ui/file_manager/file_manager/background/js/import_history.js
@@ -40,44 +40,39 @@
 };
 
 /** @override */
-importer.DummyImportHistory.prototype.wasCopied =
-    function(entry, destination) {
+importer.DummyImportHistory.prototype.wasCopied = function(entry, destination) {
   return Promise.resolve(this.answer_);
 };
 
 /** @override */
-importer.DummyImportHistory.prototype.wasImported =
-    function(entry, destination) {
+importer.DummyImportHistory.prototype.wasImported = function(
+    entry, destination) {
   return Promise.resolve(this.answer_);
 };
 
 /** @override */
 importer.DummyImportHistory.prototype.markCopied =
     (entry, destination, destinationUrl) => {
-  return Promise.resolve();
-};
+      return Promise.resolve();
+    };
 
 /** @override */
-importer.DummyImportHistory.prototype.listUnimportedUrls =
-    destination => {
+importer.DummyImportHistory.prototype.listUnimportedUrls = destination => {
   return Promise.resolve([]);
 };
 
 /** @override */
-importer.DummyImportHistory.prototype.markImported =
-    (entry, destination) => {
+importer.DummyImportHistory.prototype.markImported = (entry, destination) => {
   return Promise.resolve();
 };
 
 /** @override */
-importer.DummyImportHistory.prototype.markImportedByUrl =
-    destinationUrl => {
+importer.DummyImportHistory.prototype.markImportedByUrl = destinationUrl => {
   return Promise.resolve();
 };
 
 /** @override */
-importer.DummyImportHistory.prototype.addHistoryLoadedListener =
-    listener => {};
+importer.DummyImportHistory.prototype.addHistoryLoadedListener = listener => {};
 
 /** @override */
 importer.DummyImportHistory.prototype.addObserver = observer => {};
@@ -161,9 +156,9 @@
   return this.storage_.readAll(this.updateInMemoryRecord_.bind(this))
       .then(
           /**
-          * @return {!importer.PersistentImportHistory}
-          * @this {importer.PersistentImportHistory}
-          */
+           * @return {!importer.PersistentImportHistory}
+           * @this {importer.PersistentImportHistory}
+           */
           () => {
             return this;
           })
@@ -183,8 +178,8 @@
  * @param {!Array<*>} record
  * @this {importer.PersistentImportHistory}
  */
-importer.PersistentImportHistory.prototype.updateInMemoryRecord_ =
-    function(record) {
+importer.PersistentImportHistory.prototype.updateInMemoryRecord_ = function(
+    record) {
   switch (record[0]) {
     case importer.RecordType_.COPY:
       if (record.length !== 5) {
@@ -194,14 +189,10 @@
         break;
       }
       this.updateInMemoryCopyRecord_(
-          /** @type {string} */ (
-              record[1]),  // key
-          /** @type {!importer.Destination} */ (
-              record[2]),
-          /** @type {string } */ (
-              record[3]),  // sourceUrl
-          /** @type {string } */ (
-              record[4])); // destinationUrl
+          /** @type {string} */ (record[1]),  // key
+          /** @type {!importer.Destination} */ (record[2]),
+          /** @type {string } */ (record[3]),   // sourceUrl
+          /** @type {string } */ (record[4]));  // destinationUrl
       return;
     case importer.RecordType_.IMPORT:
       if (record.length !== 3) {
@@ -211,10 +202,8 @@
         break;
       }
       this.updateInMemoryImportRecord_(
-          /** @type {string } */ (
-              record[1]),  // key
-          /** @type {!importer.Destination} */ (
-              record[2]));
+          /** @type {string } */ (record[1]),  // key
+          /** @type {!importer.Destination} */ (record[2]));
       return;
     default:
       assertNotReached('Ignoring record with unrecognized type: ' + record[0]);
@@ -253,8 +242,8 @@
  * @return {boolean} True if a record was created.
  * @private
  */
-importer.PersistentImportHistory.prototype.updateInMemoryCopyRecord_ =
-    function(key, destination, sourceUrl, destinationUrl) {
+importer.PersistentImportHistory.prototype.updateInMemoryCopyRecord_ = function(
+    key, destination, sourceUrl, destinationUrl) {
   this.copyKeyIndex_[destinationUrl] = key;
   if (!this.copiedEntries_.hasOwnProperty(key)) {
     this.copiedEntries_[key] = {};
@@ -270,15 +259,14 @@
 };
 
 /** @override */
-importer.PersistentImportHistory.prototype.wasCopied =
-    function(entry, destination) {
-  return this.whenReady_
-      .then(this.createKey_.bind(this, entry))
+importer.PersistentImportHistory.prototype.wasCopied = function(
+    entry, destination) {
+  return this.whenReady_.then(this.createKey_.bind(this, entry))
       .then(
           /**
-          * @param {string} key
-          * @return {boolean}
-          */
+           * @param {string} key
+           * @return {boolean}
+           */
           key => {
             return key in this.copiedEntries_ &&
                 destination in this.copiedEntries_[key];
@@ -287,15 +275,14 @@
 };
 
 /** @override */
-importer.PersistentImportHistory.prototype.wasImported =
-    function(entry, destination) {
-  return this.whenReady_
-      .then(this.createKey_.bind(this, entry))
+importer.PersistentImportHistory.prototype.wasImported = function(
+    entry, destination) {
+  return this.whenReady_.then(this.createKey_.bind(this, entry))
       .then(
           /**
-          * @param {string} key
-          * @return {boolean}
-          */
+           * @param {string} key
+           * @return {boolean}
+           */
           key => {
             return this.getDestinations_(key).indexOf(destination) >= 0;
           })
@@ -308,16 +295,15 @@
   return this.whenReady_.then(this.createKey_.bind(this, entry))
       .then(
           /**
-          * @param {string} key
-          * @return {!Promise<?>}
-          */
+           * @param {string} key
+           * @return {!Promise<?>}
+           */
           key => {
             return this.storeRecord_([
-                importer.RecordType_.COPY,
-                key,
-                destination,
-                importer.deflateAppUrl(entry.toURL()),
-                importer.deflateAppUrl(destinationUrl)]);
+              importer.RecordType_.COPY, key, destination,
+              importer.deflateAppUrl(entry.toURL()),
+              importer.deflateAppUrl(destinationUrl)
+            ]);
           })
       .then(this.notifyObservers_.bind(
           this, importer.ImportHistoryState.COPIED, entry, destination,
@@ -326,10 +312,10 @@
 };
 
 /** @override */
-importer.PersistentImportHistory.prototype.listUnimportedUrls =
-    function(destination) {
-  return this.whenReady_.then(
-      () => {
+importer.PersistentImportHistory.prototype.listUnimportedUrls = function(
+    destination) {
+  return this.whenReady_
+      .then(() => {
         // TODO(smckay): Merge copy and sync records for simpler
         // unimported file discovery.
         const unimported = [];
@@ -355,14 +341,12 @@
   return this.whenReady_.then(this.createKey_.bind(this, entry))
       .then(
           /**
-          * @param {string} key
-          * @return {!Promise<?>}
-          */
+           * @param {string} key
+           * @return {!Promise<?>}
+           */
           key => {
-            return this.storeRecord_([
-                importer.RecordType_.IMPORT,
-                key,
-                destination]);
+            return this.storeRecord_(
+                [importer.RecordType_.IMPORT, key, destination]);
           })
       .then(this.notifyObservers_.bind(
           this, importer.ImportHistoryState.IMPORTED, entry, destination))
@@ -370,11 +354,11 @@
 };
 
 /** @override */
-importer.PersistentImportHistory.prototype.markImportedByUrl =
-    function(destinationUrl) {
+importer.PersistentImportHistory.prototype.markImportedByUrl = function(
+    destinationUrl) {
   const deflatedUrl = importer.deflateAppUrl(destinationUrl);
   const key = this.copyKeyIndex_[deflatedUrl];
-  if (!!key) {
+  if (key) {
     const copyData = this.copiedEntries_[key];
 
     // We could build an index of this as well, but it seems
@@ -382,21 +366,19 @@
     // be just one destination for a file (assumption).
     for (const destination in copyData) {
       if (copyData[destination].destinationUrl === deflatedUrl) {
-        return this.storeRecord_([
-          importer.RecordType_.IMPORT,
-          key,
-          destination])
-            .then(
-                () => {
-                  const sourceUrl = importer.inflateAppUrl(
-                      copyData[destination].sourceUrl);
-                  // Here we try to create an Entry for the source URL.
-                  // This will allow observers to update the UI if the
-                  // source entry is in view.
-                  util.urlToEntry(sourceUrl).then(
+        return this
+            .storeRecord_([importer.RecordType_.IMPORT, key, destination])
+            .then(() => {
+              const sourceUrl =
+                  importer.inflateAppUrl(copyData[destination].sourceUrl);
+              // Here we try to create an Entry for the source URL.
+              // This will allow observers to update the UI if the
+              // source entry is in view.
+              util.urlToEntry(sourceUrl)
+                  .then(
                       /**
-                      * @param {Entry} entry
-                      */
+                       * @param {Entry} entry
+                       */
                       entry => {
                         if (entry.isFile) {
                           this.notifyObservers_(
@@ -409,9 +391,9 @@
                             'Unable to find original entry for: ' + sourceUrl);
                         return;
                       })
-                      .catch(importer.getLogger().catcher(
-                          'notify-listeners-on-import'));
-                })
+                  .catch(importer.getLogger().catcher(
+                      'notify-listeners-on-import'));
+            })
             .catch(importer.getLogger().catcher('mark-imported-by-url'));
       }
     }
@@ -422,14 +404,12 @@
 };
 
 /** @override */
-importer.PersistentImportHistory.prototype.addObserver =
-    function(observer) {
+importer.PersistentImportHistory.prototype.addObserver = function(observer) {
   this.observers_.push(observer);
 };
 
 /** @override */
-importer.PersistentImportHistory.prototype.removeObserver =
-    function(observer) {
+importer.PersistentImportHistory.prototype.removeObserver = function(observer) {
   const index = this.observers_.indexOf(observer);
   if (index > -1) {
     this.observers_.splice(index, 1);
@@ -445,13 +425,13 @@
  * @param {string=} opt_destinationUrl
  * @private
  */
-importer.PersistentImportHistory.prototype.notifyObservers_ =
-    function(state, entry, destination, opt_destinationUrl) {
+importer.PersistentImportHistory.prototype.notifyObservers_ = function(
+    state, entry, destination, opt_destinationUrl) {
   this.observers_.forEach(
       /**
-      * @param {!importer.ImportHistory.Observer} observer
-      * @this {importer.PersistentImportHistory}
-      */
+       * @param {!importer.ImportHistory.Observer} observer
+       * @this {importer.PersistentImportHistory}
+       */
       observer => {
         observer({
           state: state,
@@ -517,18 +497,18 @@
     this.needsInitialization_ = false;
     this.getHistoryFiles_()
         .then(/**
-     * @param {!Array<!FileEntry>} fileEntries
-     */
-    fileEntries => {
-      const storage = new importer.FileBasedRecordStorage(fileEntries);
-      const history = new importer.PersistentImportHistory(
-          importer.createMetadataHashcode, storage);
-      new importer.DriveSyncWatcher(history);
-      history.whenReady().then(
-          () => {
-            this.historyResolver_.resolve(history);
-          });
-    })
+               * @param {!Array<!FileEntry>} fileEntries
+               */
+              fileEntries => {
+                const storage =
+                    new importer.FileBasedRecordStorage(fileEntries);
+                const history = new importer.PersistentImportHistory(
+                    importer.createMetadataHashcode, storage);
+                new importer.DriveSyncWatcher(history);
+                history.whenReady().then(() => {
+                  this.historyResolver_.resolve(history);
+                });
+              })
         .catch(importer.getLogger().catcher('history-load-chain'));
   }
 
@@ -577,8 +557,7 @@
  */
 importer.FileBasedRecordStorage = function(fileEntries) {
   /** @private {!Array<!importer.PromisingFileEntry>} */
-  this.inputFiles_ = fileEntries.map(
-      importer.PromisingFileEntry.create);
+  this.inputFiles_ = fileEntries.map(importer.PromisingFileEntry.create);
 
   /** @private {!importer.PromisingFileEntry} */
   this.outputFile_ = this.inputFiles_[0];
@@ -592,16 +571,18 @@
 
 /** @override */
 importer.FileBasedRecordStorage.prototype.write = function(record) {
-  return this.latestOperation_ = this.latestOperation_
-      .then(
-          /**
-          * @param {?} ignore
-          */
-          ignore => {
-            return this.outputFile_.createWriter();
-          })
-      .then(this.writeRecord_.bind(this, record))
-      .catch(importer.getLogger().catcher('file-record-store-write'));
+  return this.latestOperation_ =
+             this.latestOperation_
+                 .then(
+                     /**
+                      * @param {?} ignore
+                      */
+                     ignore => {
+                       return this.outputFile_.createWriter();
+                     })
+                 .then(this.writeRecord_.bind(this, record))
+                 .catch(
+                     importer.getLogger().catcher('file-record-store-write'));
 };
 
 /**
@@ -612,18 +593,17 @@
  * @return {!Promise<?>} Resolves when write is complete.
  * @private
  */
-importer.FileBasedRecordStorage.prototype.writeRecord_ =
-    function(record, writer) {
+importer.FileBasedRecordStorage.prototype.writeRecord_ = function(
+    record, writer) {
   const blob = new Blob(
-      [JSON.stringify(record) + ',\n'],
-      {type: 'text/plain; charset=UTF-8'});
+      [JSON.stringify(record) + ',\n'], {type: 'text/plain; charset=UTF-8'});
 
   return new Promise(
       /**
-      * @param {function()} resolve
-      * @param {function()} reject
-      * @this {importer.FileBasedRecordStorage}
-      */
+       * @param {function()} resolve
+       * @param {function()} reject
+       * @this {importer.FileBasedRecordStorage}
+       */
       (resolve, reject) => {
         writer.onwriteend = resolve;
         writer.onerror = reject;
@@ -635,57 +615,60 @@
 
 /** @override */
 importer.FileBasedRecordStorage.prototype.readAll = function(recordCallback) {
-  return this.latestOperation_ = this.latestOperation_
-      .then(
-          /**
-          * @param {?} ignored
-          */
-          ignored => {
-            const filePromises = this.inputFiles_.map(
-                /**
-                 * @param {!importer.PromisingFileEntry} entry
-                 * @this {importer.FileBasedRecordStorage}
-                 */
-                entry => {
-                  return entry.file();
-                });
-            return Promise.all(filePromises);
-          })
-      .then(
-          /**
-          * @return {!Promise<!Array<string>>}
-          */
-          files => {
-            const contentPromises = files.map(
-                this.readFileAsText_.bind(this));
-            return Promise.all(contentPromises);
-          },
-          /**
-          * @return {string}
-          */
-          () => {
-            console.error('Unable to read from one of history files.');
-            return '';
-          })
-      .then(
-          /**
-          * @param {!Array<string>} fileContents
-          */
-          fileContents => {
-            const parsePromises = fileContents.map(
-                this.parse_.bind(this));
-            return Promise.all(parsePromises);
-          })
-      .then(
-          /** @param {!Array<!Array<*>>} parsedContents */
-          parsedContents => {
-            parsedContents.forEach(
-                /** @param {!Array<!Array<*>>} recordSet */
-                recordSet => {
-                  recordSet.forEach(recordCallback);
-                });
-          })
-      .catch(importer.getLogger().catcher('file-record-store-read-all'));
+  return this.latestOperation_ =
+             this.latestOperation_
+                 .then(
+                     /**
+                      * @param {?} ignored
+                      */
+                     ignored => {
+                       const filePromises = this.inputFiles_.map(
+                           /**
+                            * @param {!importer.PromisingFileEntry} entry
+                            * @this {importer.FileBasedRecordStorage}
+                            */
+                           entry => {
+                             return entry.file();
+                           });
+                       return Promise.all(filePromises);
+                     })
+                 .then(
+                     /**
+                      * @return {!Promise<!Array<string>>}
+                      */
+                     files => {
+                       const contentPromises =
+                           files.map(this.readFileAsText_.bind(this));
+                       return Promise.all(contentPromises);
+                     },
+                     /**
+                      * @return {string}
+                      */
+                     () => {
+                       console.error(
+                           'Unable to read from one of history files.');
+                       return '';
+                     })
+                 .then(
+                     /**
+                      * @param {!Array<string>} fileContents
+                      */
+                     fileContents => {
+                       const parsePromises =
+                           fileContents.map(this.parse_.bind(this));
+                       return Promise.all(parsePromises);
+                     })
+                 .then(
+                     /** @param {!Array<!Array<*>>} parsedContents */
+                     parsedContents => {
+                       parsedContents.forEach(
+                           /** @param {!Array<!Array<*>>} recordSet */
+                           recordSet => {
+                             recordSet.forEach(recordCallback);
+                           });
+                     })
+                 .catch(importer.getLogger().catcher(
+                     'file-record-store-read-all'));
 };
 
 /**
@@ -696,28 +679,27 @@
  * @private
  */
 importer.FileBasedRecordStorage.prototype.readFileAsText_ = function(file) {
-  return new Promise(
-      (resolve, reject) => {
-        const reader = new FileReader();
+  return new Promise((resolve, reject) => {
+           const reader = new FileReader();
 
-        reader.onloadend = () => {
-          if (reader.error) {
-            console.error(reader.error);
-            reject();
-          } else {
-            resolve(reader.result);
-          }
-        };
+           reader.onloadend = () => {
+             if (reader.error) {
+               console.error(reader.error);
+               reject();
+             } else {
+               resolve(reader.result);
+             }
+           };
 
-        reader.onerror = error => {
-          console.error(error);
-          reject(error);
-        };
+           reader.onerror = error => {
+             console.error(error);
+             reject(error);
+           };
 
-        reader.readAsText(file);
-      })
-      .catch(importer.getLogger().catcher(
-      'file-record-store-read-file-as-text'));
+           reader.readAsText(file);
+         })
+      .catch(
+          importer.getLogger().catcher('file-record-store-read-file-as-text'));
 };
 
 /**
@@ -756,17 +738,14 @@
   /** @private {!importer.ImportHistory} */
   this.history_ = history;
 
-  this.history_.addObserver(
-      this.onHistoryChanged_.bind(this));
+  this.history_.addObserver(this.onHistoryChanged_.bind(this));
 
   this.history_.whenReady()
-      .then(
-          () => {
-            this.history_.listUnimportedUrls(importer.Destination.GOOGLE_DRIVE)
-                .then(this.updateSyncStatus_.bind(
-                    this,
-                    importer.Destination.GOOGLE_DRIVE));
-          })
+      .then(() => {
+        this.history_.listUnimportedUrls(importer.Destination.GOOGLE_DRIVE)
+            .then(this.updateSyncStatus_.bind(
+                this, importer.Destination.GOOGLE_DRIVE));
+      })
       .catch(importer.getLogger().catcher('drive-sync-watcher-constructor'));
 
   // Listener is only registered once the history object is initialized.
@@ -785,27 +764,23 @@
  * @param {!Array<string>} unimportedUrls
  * @private
  */
-importer.DriveSyncWatcher.prototype.updateSyncStatus_ =
-    function(destination, unimportedUrls) {
+importer.DriveSyncWatcher.prototype.updateSyncStatus_ = function(
+    destination, unimportedUrls) {
   // TODO(smckay): Chunk processing of urls...to ensure we're not
   // blocking interactive tasks. For now, we just defer the update
   // for a few seconds.
-  setTimeout(
-      () => {
-        unimportedUrls.forEach(
-            url => {
-              this.checkSyncStatus_(destination, url);
-            });
-      },
-      importer.DriveSyncWatcher.UPDATE_DELAY_MS);
+  setTimeout(() => {
+    unimportedUrls.forEach(url => {
+      this.checkSyncStatus_(destination, url);
+    });
+  }, importer.DriveSyncWatcher.UPDATE_DELAY_MS);
 };
 
 /**
  * @param {!chrome.fileManagerPrivate.FileTransferStatus} status
  * @private
  */
-importer.DriveSyncWatcher.prototype.onFileTransfersUpdated_ =
-    function(status) {
+importer.DriveSyncWatcher.prototype.onFileTransfersUpdated_ = function(status) {
   // If the synced file it isn't one we copied,
   // the call to mark by url will just fail...fine by us.
   if (status.transferState === 'completed') {
@@ -835,8 +810,8 @@
  *     make do without it.
  * @private
  */
-importer.DriveSyncWatcher.prototype.checkSyncStatus_ =
-    function(destination, url, opt_entry) {
+importer.DriveSyncWatcher.prototype.checkSyncStatus_ = function(
+    destination, url, opt_entry) {
   console.assert(
       destination === importer.Destination.GOOGLE_DRIVE,
       'Unsupported destination: ' + destination);
@@ -844,8 +819,8 @@
   this.getSyncStatus_(url)
       .then(
           /**
-          * @param {boolean} synced True if file is synced
-          */
+           * @param {boolean} synced True if file is synced
+           */
           synced => {
             if (synced) {
               if (opt_entry) {
@@ -856,8 +831,7 @@
             }
           })
       .catch(
-          importer.getLogger().catcher(
-              'drive-sync-watcher-check-sync-status'));
+          importer.getLogger().catcher('drive-sync-watcher-check-sync-status'));
 };
 
 /**
@@ -933,31 +907,28 @@
     importer.importEnabled()
         .then(
             /**
-            * @param {boolean} enabled
-            * @return {!importer.HistoryLoader}
-            */
+             * @param {boolean} enabled
+             * @return {!importer.HistoryLoader}
+             */
             enabled => {
-              return enabled ?
-                  this.createRealHistoryLoader_() :
-                  new importer.DummyImportHistory(false);
+              return enabled ? this.createRealHistoryLoader_() :
+                               new importer.DummyImportHistory(false);
             })
-        .then(
-            loader => {
-              return this.historyResolver_.resolve(
-                  /** @type {!importer.ImportHistory} */
-                      (loader.getHistory()));
-            })
+        .then(loader => {
+          return this.historyResolver_.resolve(
+              /** @type {!importer.ImportHistory} */
+              (loader.getHistory()));
+        })
         .catch(
-            importer.getLogger().catcher(
-                'runtime-history-loader-get-history'));
+            importer.getLogger().catcher('runtime-history-loader-get-history'));
   }
 
   return this.historyResolver_.promise;
 };
 
 /** @override */
-importer.RuntimeHistoryLoader.prototype.addHistoryLoadedListener =
-    function(listener) {
+importer.RuntimeHistoryLoader.prototype.addHistoryLoadedListener = function(
+    listener) {
   this.historyResolver_.promise.then(listener);
 };
 
@@ -967,23 +938,22 @@
  *     just the last modified time and the file size.
  */
 importer.createMetadataHashcode = function(fileEntry) {
-  return new Promise(
-             (resolve, reject) => {
-               metadataProxy.getEntryMetadata(fileEntry).then(
-                   /**
-                   * @param {!Object} metadata
-                   */
-                   metadata => {
-                     if (!('modificationTime' in metadata)) {
-                       reject('File entry missing "modificationTime" field.');
-                     } else if (!('size' in metadata)) {
-                       reject('File entry missing "size" field.');
-                     } else {
-                       const secondsSinceEpoch = importer.toSecondsFromEpoch(
-                           metadata.modificationTime);
-                       resolve(secondsSinceEpoch + '_' + metadata.size);
-                     }
-                   });
-             })
+  return new Promise((resolve, reject) => {
+           metadataProxy.getEntryMetadata(fileEntry).then(
+               /**
+                * @param {!Object} metadata
+                */
+               metadata => {
+                 if (!('modificationTime' in metadata)) {
+                   reject('File entry missing "modificationTime" field.');
+                 } else if (!('size' in metadata)) {
+                   reject('File entry missing "size" field.');
+                 } else {
+                   const secondsSinceEpoch =
+                       importer.toSecondsFromEpoch(metadata.modificationTime);
+                   resolve(secondsSinceEpoch + '_' + metadata.size);
+                 }
+               });
+         })
       .catch(importer.getLogger().catcher('importer-common-create-hashcode'));
 };
diff --git a/ui/file_manager/file_manager/background/js/import_history_unittest.js b/ui/file_manager/file_manager/background/js/import_history_unittest.js
index af8de79..f578dd4 100644
--- a/ui/file_manager/file_manager/background/js/import_history_unittest.js
+++ b/ui/file_manager/file_manager/background/js/import_history_unittest.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 /** @const {string} */
-const FILE_LAST_MODIFIED = new Date("Dec 4 1968").toString();
+const FILE_LAST_MODIFIED = new Date('Dec 4 1968').toString();
 
 /** @const {number} */
 const FILE_SIZE = 1234;
@@ -60,8 +60,7 @@
   storage = new TestRecordStorage();
 
   const history = new importer.PersistentImportHistory(
-      importer.createMetadataHashcode,
-      storage);
+      importer.createMetadataHashcode, storage);
 
   historyProvider = history.whenReady();
 }
@@ -74,63 +73,52 @@
 function testWasCopied_FalseForUnknownEntry(callback) {
   // TestRecordWriter is pre-configured with a Space Cloud entry
   // but not for this file.
-  testPromise = historyProvider.then(
-      history => {
-        return history.wasCopied(testFileEntry, SPACE_CAMP).then(assertFalse);
-      });
+  testPromise = historyProvider.then(history => {
+    return history.wasCopied(testFileEntry, SPACE_CAMP).then(assertFalse);
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testWasCopied_TrueForKnownEntryLoadedFromStorage(callback) {
   // TestRecordWriter is pre-configured with this entry.
-  testPromise = historyProvider.then(
-      history => {
-        return history.wasCopied(testFileEntry, GOOGLE_DRIVE).then(assertTrue);
-      });
+  testPromise = historyProvider.then(history => {
+    return history.wasCopied(testFileEntry, GOOGLE_DRIVE).then(assertTrue);
+  });
 
   reportPromise(testPromise, callback);
 }
 
 
 function testMarkCopied_FiresChangedEvent(callback) {
-  testPromise = historyProvider.then(
-      history => {
-        const recorder = new TestCallRecorder();
-        history.addObserver(recorder.callback);
-        return history.markCopied(testFileEntry, SPACE_CAMP, 'url1').then(
-            () => {
-              return Promise.resolve()
-                  .then(
-                      () => {
-                        recorder.assertCallCount(1);
-                        assertEquals(
-                            importer.ImportHistoryState.COPIED,
-                            recorder.getLastArguments()[0]['state']);
-                      });
-            });
+  testPromise = historyProvider.then(history => {
+    const recorder = new TestCallRecorder();
+    history.addObserver(recorder.callback);
+    return history.markCopied(testFileEntry, SPACE_CAMP, 'url1').then(() => {
+      return Promise.resolve().then(() => {
+        recorder.assertCallCount(1);
+        assertEquals(
+            importer.ImportHistoryState.COPIED,
+            recorder.getLastArguments()[0]['state']);
       });
+    });
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testMarkImported_ByUrl(callback) {
-  const destinationUrl = 'filesystem:chrome-extension://abc/photos/splosion.jpg';
-  testPromise = historyProvider.then(
-      history => {
-        return history.markCopied(testFileEntry, SPACE_CAMP, destinationUrl)
-            .then(
-                () => {
-                  return history.markImportedByUrl(destinationUrl)
-                      .then(
-                          () => {
-                            return history.wasImported(
-                                testFileEntry,
-                                SPACE_CAMP)
-                                .then(assertTrue);
-                          });
-                });
-      });
+  const destinationUrl =
+      'filesystem:chrome-extension://abc/photos/splosion.jpg';
+  testPromise = historyProvider.then(history => {
+    return history.markCopied(testFileEntry, SPACE_CAMP, destinationUrl)
+        .then(() => {
+          return history.markImportedByUrl(destinationUrl).then(() => {
+            return history.wasImported(testFileEntry, SPACE_CAMP)
+                .then(assertTrue);
+          });
+        });
+  });
 
   reportPromise(testPromise, callback);
 }
@@ -138,95 +126,77 @@
 function testWasImported_FalseForUnknownEntry(callback) {
   // TestRecordWriter is pre-configured with a Space Cloud entry
   // but not for this file.
-  testPromise = historyProvider.then(
-      history => {
-        return history.wasImported(testFileEntry, SPACE_CAMP).then(assertFalse);
-      });
+  testPromise = historyProvider.then(history => {
+    return history.wasImported(testFileEntry, SPACE_CAMP).then(assertFalse);
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testWasImported_TrueForKnownEntryLoadedFromStorage(callback) {
   // TestRecordWriter is pre-configured with this entry.
-  testPromise = historyProvider.then(
-      history => {
-        return history.wasImported(testFileEntry, GOOGLE_DRIVE)
-            .then(assertTrue);
-      });
+  testPromise = historyProvider.then(history => {
+    return history.wasImported(testFileEntry, GOOGLE_DRIVE).then(assertTrue);
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testWasImported_TrueForKnownEntrySetAtRuntime(callback) {
-  testPromise = historyProvider.then(
-      history => {
-        return history.markImported(testFileEntry, SPACE_CAMP).then(
-            () => {
-              return history.wasImported(testFileEntry, SPACE_CAMP)
-                  .then(assertTrue);
-            });
-      });
+  testPromise = historyProvider.then(history => {
+    return history.markImported(testFileEntry, SPACE_CAMP).then(() => {
+      return history.wasImported(testFileEntry, SPACE_CAMP).then(assertTrue);
+    });
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testMarkImport_FiresChangedEvent(callback) {
-  testPromise = historyProvider.then(
-      history => {
-        const recorder = new TestCallRecorder();
-        history.addObserver(recorder.callback);
-        return history.markImported(testFileEntry, SPACE_CAMP).then(
-            () => {
-              return Promise.resolve()
-                  .then(
-                      () => {
-                        recorder.assertCallCount(1);
-                        assertEquals(
-                            importer.ImportHistoryState.IMPORTED,
-                            recorder.getLastArguments()[0]['state']);
-                      });
-            });
+  testPromise = historyProvider.then(history => {
+    const recorder = new TestCallRecorder();
+    history.addObserver(recorder.callback);
+    return history.markImported(testFileEntry, SPACE_CAMP).then(() => {
+      return Promise.resolve().then(() => {
+        recorder.assertCallCount(1);
+        assertEquals(
+            importer.ImportHistoryState.IMPORTED,
+            recorder.getLastArguments()[0]['state']);
       });
+    });
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testHistoryObserver_Unsubscribe(callback) {
-  testPromise = historyProvider.then(
-      history => {
-        const recorder = new TestCallRecorder();
-        history.addObserver(recorder.callback);
-        history.removeObserver(recorder.callback);
+  testPromise = historyProvider.then(history => {
+    const recorder = new TestCallRecorder();
+    history.addObserver(recorder.callback);
+    history.removeObserver(recorder.callback);
 
-        const promises = [];
-        promises.push(history.markCopied(testFileEntry, SPACE_CAMP, 'url2'));
-        promises.push(history.markImported(testFileEntry, SPACE_CAMP));
-        return Promise.all(promises).then(
-            () => {
-              return Promise.resolve()
-                  .then(
-                      () => {
-                        recorder.assertCallCount(0);
-                      });
-            });
+    const promises = [];
+    promises.push(history.markCopied(testFileEntry, SPACE_CAMP, 'url2'));
+    promises.push(history.markImported(testFileEntry, SPACE_CAMP));
+    return Promise.all(promises).then(() => {
+      return Promise.resolve().then(() => {
+        recorder.assertCallCount(0);
       });
+    });
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testRecordStorage_RemembersPreviouslyWrittenRecords(callback) {
   const recorder = new TestCallRecorder();
-  testPromise = createRealStorage(['recordStorageTest.data'])
-      .then(
-          storage => {
-            return storage.write(['abc', '123']).then(
-                () => {
-                  return storage.readAll(recorder.callback).then(
-                      () => {
-                        recorder.assertCallCount(1);
-                      });
-                });
-          });
+  testPromise = createRealStorage(['recordStorageTest.data']).then(storage => {
+    return storage.write(['abc', '123']).then(() => {
+      return storage.readAll(recorder.callback).then(() => {
+        recorder.assertCallCount(1);
+      });
+    });
+  });
 
   reportPromise(testPromise, callback);
 }
@@ -234,70 +204,55 @@
 function testRecordStorage_LoadsRecordsFromMultipleHistoryFiles(callback) {
   const recorder = new TestCallRecorder();
 
-  const remoteData = createRealStorage(['multiStorage-1.data'])
-      .then(
-          storage => {
-            return storage.write(['remote-data', '98765432']);
-          });
-  const moreRemoteData = createRealStorage(['multiStorage-2.data'])
-      .then(
-          storage => {
-            return storage.write(['antarctica-data', '777777777777']);
-          });
+  const remoteData =
+      createRealStorage(['multiStorage-1.data']).then(storage => {
+        return storage.write(['remote-data', '98765432']);
+      });
+  const moreRemoteData =
+      createRealStorage(['multiStorage-2.data']).then(storage => {
+        return storage.write(['antarctica-data', '777777777777']);
+      });
 
-  testPromise = Promise.all([remoteData, moreRemoteData]).then(
-    () => {
-      return createRealStorage([
-        'multiStorage-0.data',
-        'multiStorage-1.data',
-        'multiStorage-2.data'])
-        .then(
-            storage => {
-              const writePromises = [
-                storage.write(['local-data', '111'])
-              ];
-              return Promise.all(writePromises)
-                  .then(
-                      () => {
-                        return storage.readAll(recorder.callback).then(
-                            () => {
-                              recorder.assertCallCount(3);
-                              assertEquals(
-                                  'local-data',
-                                  recorder.getArguments(0)[0][0]);
-                              assertEquals(
-                                  'remote-data',
-                                  recorder.getArguments(1)[0][0]);
-                              assertEquals(
-                                  'antarctica-data',
-                                  recorder.getArguments(2)[0][0]);
-                            });
-                      });
+  testPromise = Promise.all([remoteData, moreRemoteData]).then(() => {
+    return createRealStorage([
+             'multiStorage-0.data',
+             'multiStorage-1.data',
+             'multiStorage-2.data',
+           ])
+        .then(storage => {
+          const writePromises = [storage.write(['local-data', '111'])];
+          return Promise.all(writePromises).then(() => {
+            return storage.readAll(recorder.callback).then(() => {
+              recorder.assertCallCount(3);
+              assertEquals('local-data', recorder.getArguments(0)[0][0]);
+              assertEquals('remote-data', recorder.getArguments(1)[0][0]);
+              assertEquals('antarctica-data', recorder.getArguments(2)[0][0]);
             });
-    });
+          });
+        });
+  });
 
   reportPromise(testPromise, callback);
 }
 
 function testRecordStorage_SerializingOperations(callback) {
   const recorder = new TestCallRecorder();
-  testPromise = createRealStorage(['recordStorageTestForSerializing.data'])
-      .then(
-          storage => {
-            const writePromises = [];
-            const WRITES_COUNT = 20;
-            for (let i = 0; i < WRITES_COUNT; i++) {
-              writePromises.push(storage.write(['abc', '123']));
-            }
-            const readAllPromise = storage.readAll(recorder.callback).then(
-              () => {
-                recorder.assertCallCount(WRITES_COUNT);
-              });
-            // Write an extra record, which must be executed afte reading is
-            // completed.
-            writePromises.push(storage.write(['abc', '123']));
-            return Promise.all(writePromises.concat([readAllPromise]));
-          });
+  testPromise = createRealStorage([
+                  'recordStorageTestForSerializing.data'
+                ]).then(storage => {
+    const writePromises = [];
+    const WRITES_COUNT = 20;
+    for (let i = 0; i < WRITES_COUNT; i++) {
+      writePromises.push(storage.write(['abc', '123']));
+    }
+    const readAllPromise = storage.readAll(recorder.callback).then(() => {
+      recorder.assertCallCount(WRITES_COUNT);
+    });
+    // Write an extra record, which must be executed afte reading is
+    // completed.
+    writePromises.push(storage.write(['abc', '123']));
+    return Promise.all(writePromises.concat([readAllPromise]));
+  });
 
   reportPromise(testPromise, callback);
 }
@@ -352,25 +307,15 @@
  * @return {!Promise<!FileEntry>}
  */
 function createFileEntry(fileName) {
-  return new Promise(
-      (resolve, reject) => {
-        const onFileSystemReady = fileSystem => {
-          fileSystem.root.getFile(
-              fileName,
-              {
-                create: true,
-                exclusive: false
-              },
-              resolve,
-              reject);
-        };
+  return new Promise((resolve, reject) => {
+    const onFileSystemReady = fileSystem => {
+      fileSystem.root.getFile(
+          fileName, {create: true, exclusive: false}, resolve, reject);
+    };
 
-        window.webkitRequestFileSystem(
-            TEMPORARY,
-            1024 * 1024,
-            onFileSystemReady,
-            reject);
-      });
+    window.webkitRequestFileSystem(
+        TEMPORARY, 1024 * 1024, onFileSystemReady, reject);
+  });
 }
 
 /**
@@ -386,14 +331,15 @@
   // Pre-populate the store with some "previously written" data <wink>.
   /** @private {!Array<!Array<string>>} */
   this.records_ = [
-    [1,
-      timeStamp + '_' + FILE_SIZE, GOOGLE_DRIVE],
-    [0,
+    [1, timeStamp + '_' + FILE_SIZE, GOOGLE_DRIVE],
+    [
+      0,
       timeStamp + '_' + FILE_SIZE,
       'google-drive',
       '$/some/url/snazzy.pants',
-      '$/someother/url/snazzy.pants'],
-    [1, '99999_99999', SPACE_CAMP]
+      '$/someother/url/snazzy.pants',
+    ],
+    [1, '99999_99999', SPACE_CAMP],
   ];
 
   /**
diff --git a/ui/file_manager/file_manager/background/js/launcher.js b/ui/file_manager/file_manager/background/js/launcher.js
index f45e13b..44200846 100644
--- a/ui/file_manager/file_manager/background/js/launcher.js
+++ b/ui/file_manager/file_manager/background/js/launcher.js
@@ -42,9 +42,7 @@
     width: Math.min(Math.round(window.screen.availWidth * 0.8), 1000),
     height: Math.min(Math.round(window.screen.availHeight * 0.8), 600)
   },
-  frame: {
-    color: '#254fae'
-  },
+  frame: {color: '#254fae'},
   minWidth: 480,
   minHeight: 300
 };
@@ -94,12 +92,12 @@
           }
           // Different current directories.
           if (opt_appState.currentDirectoryURL !==
-                  contentWindow.appState.currentDirectoryURL) {
+              contentWindow.appState.currentDirectoryURL) {
             continue;
           }
           // Selection URL specified, and it is different.
           if (opt_appState.selectionURL &&
-                  opt_appState.selectionURL !==
+              opt_appState.selectionURL !==
                   contentWindow.appState.selectionURL) {
             continue;
           }
@@ -173,9 +171,7 @@
     const appId = FILES_ID_PREFIX + id;
 
     const appWindow = new AppWindowWrapper(
-        'main.html',
-        appId,
-        FILE_MANAGER_WINDOW_CREATE_OPTIONS);
+        'main.html', appId, FILE_MANAGER_WINDOW_CREATE_OPTIONS);
     appWindow.launch(opt_appState || {}, false, () => {
       appWindow.rawAppWindow.focus();
       if (opt_callback) {
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js
index 3772f7c..36c9580 100644
--- a/ui/file_manager/file_manager/background/js/launcher_search.js
+++ b/ui/file_manager/file_manager/background/js/launcher_search.js
@@ -159,8 +159,7 @@
       if (entry.isDirectory) {
         // If it's directory, open the directory with file manager.
         launcher.launchFileManager(
-            { currentDirectoryURL: entry.toURL() },
-            undefined, /* App ID */
+            {currentDirectoryURL: entry.toURL()}, undefined, /* App ID */
             LaunchType.FOCUS_SAME_OR_CREATE);
       } else {
         // getFileTasks supports only native entries.
@@ -220,8 +219,7 @@
  */
 LauncherSearch.prototype.openFileManagerWithSelectionURL_ = selectionURL => {
   launcher.launchFileManager(
-      {selectionURL: selectionURL},
-      undefined, /* App ID */
+      {selectionURL: selectionURL}, undefined, /* App ID */
       LaunchType.FOCUS_SAME_OR_CREATE);
 };
 
diff --git a/ui/file_manager/file_manager/background/js/media_import_handler.js b/ui/file_manager/file_manager/background/js/media_import_handler.js
index 3402d07..ebebb1d0 100644
--- a/ui/file_manager/file_manager/background/js/media_import_handler.js
+++ b/ui/file_manager/file_manager/background/js/media_import_handler.js
@@ -62,7 +62,6 @@
 /** @override */
 importer.MediaImportHandler.prototype.importFromScanResult = function(
     scanResult, destination, directoryPromise) {
-
   const task = new importer.MediaImportHandler.ImportTask(
       this.generateTaskId_(), this.historyLoader_, scanResult, directoryPromise,
       destination, this.getDisposition_);
@@ -96,8 +95,8 @@
  * @param {string} updateType
  * @private
  */
-importer.MediaImportHandler.prototype.onTaskProgress_ =
-    function(task, updateType) {
+importer.MediaImportHandler.prototype.onTaskProgress_ = function(
+    task, updateType) {
   const UpdateType = importer.TaskQueue.UpdateType;
 
   let item = this.progressCenter_.getItemById(task.taskId);
@@ -188,8 +187,8 @@
  * @param {string} updateType
  * @param {Object=} updateInfo
  */
-importer.MediaImportHandler.prototype.onFileImported_ =
-    (task, updateType, updateInfo) => {
+importer.MediaImportHandler.prototype
+    .onFileImported_ = (task, updateType, updateInfo) => {
   if (updateType !==
       importer.MediaImportHandler.ImportTask.UpdateType.ENTRY_CHANGED) {
     return;
@@ -205,10 +204,10 @@
       info.destination,
       'private',  // Scoped to just this app.
       importer.MediaImportHandler.IMPORTS_TAG_KEY,
-      importer.MediaImportHandler.IMPORTS_TAG_VALUE,
-      () => {
+      importer.MediaImportHandler.IMPORTS_TAG_VALUE, () => {
         if (chrome.runtime.lastError) {
-          console.error('Unable to tag imported media: ' +
+          console.error(
+              'Unable to tag imported media: ' +
               chrome.runtime.lastError.message);
         }
       });
@@ -422,20 +421,21 @@
  */
 importer.MediaImportHandler.ImportTask.prototype.markDuplicatesImported_ =
     function() {
-  this.historyLoader_.getHistory().then(
-      /**
-      * @param {!importer.ImportHistory} history
-      */
-      history => {
-        this.scanResult_.getDuplicateFileEntries().forEach(
-            /**
-            * @param {!FileEntry} entry
-            * @this {importer.MediaImportHandler.ImportTask}
-            */
-            entry => {
-              history.markImported(entry, this.destination_);
-            });
-      })
+  this.historyLoader_.getHistory()
+      .then(
+          /**
+           * @param {!importer.ImportHistory} history
+           */
+          history => {
+            this.scanResult_.getDuplicateFileEntries().forEach(
+                /**
+                 * @param {!FileEntry} entry
+                 * @this {importer.MediaImportHandler.ImportTask}
+                 */
+                entry => {
+                  history.markImported(entry, this.destination_);
+                });
+          })
       .catch(importer.getLogger().catcher('import-task-mark-dupes-imported'));
 };
 
@@ -460,27 +460,26 @@
   this.getDisposition_(
           entry, importer.Destination.GOOGLE_DRIVE, importer.ScanMode.CONTENT)
       .then(/**
-   * @param {!importer.Disposition} disposition The disposition
-   *     of the entry. Either some sort of dupe, or an original.
-   */
-  disposition => {
-    if (disposition === importer.Disposition.ORIGINAL) {
-      return this.copy_(entry, destinationDirectory);
-    }
-    this.duplicateFilesCount_++;
-    this.markAsImported_(entry);
-  })
+             * @param {!importer.Disposition} disposition The disposition
+             *     of the entry. Either some sort of dupe, or an original.
+             */
+            disposition => {
+              if (disposition === importer.Disposition.ORIGINAL) {
+                return this.copy_(entry, destinationDirectory);
+              }
+              this.duplicateFilesCount_++;
+              this.markAsImported_(entry);
+            })
       // Regardless of the result of this copy, push on to the next file.
       .then(completionCallback)
       .catch(/** @param {*} error */
-  error => {
-    importer.getLogger().catcher('import-task-import-one')(
-        error);
-    // TODO(oka): Retry copies only when failed due to
-    // insufficient disk space. crbug.com/788692.
-    this.failedEntries_.push(entry);
-    completionCallback();
-  });
+             error => {
+               importer.getLogger().catcher('import-task-import-one')(error);
+               // TODO(oka): Retry copies only when failed due to
+               // insufficient disk space. crbug.com/788692.
+               this.failedEntries_.push(entry);
+               completionCallback();
+             });
 };
 
 /**
@@ -491,8 +490,8 @@
  *     promise will reject if an error occurs.
  * @private
  */
-importer.MediaImportHandler.ImportTask.prototype.copy_ =
-    function(entry, destinationDirectory) {
+importer.MediaImportHandler.ImportTask.prototype.copy_ = function(
+    entry, destinationDirectory) {
   // A count of the current number of processed bytes for this entry.
   let currentBytes = 0;
 
@@ -524,10 +523,9 @@
     destinationEntry.size = entry.size;
     this.notify(
         /** @type {importer.TaskQueue.UpdateType} */
-            (importer.MediaImportHandler.ImportTask.UpdateType.ENTRY_CHANGED),
-        {
+        (importer.MediaImportHandler.ImportTask.UpdateType.ENTRY_CHANGED), {
           sourceUrl: sourceUrl,
-          destination: destinationEntry
+          destination: destinationEntry,
         });
     this.notify(importer.TaskQueue.UpdateType.PROGRESS);
   };
@@ -561,18 +559,13 @@
   fileOperationUtil.deduplicatePath(destinationDirectory, entry.name)
       .then(
           /**
-          * Performs the copy using the given deduped filename.
-          * @param {string} destinationFilename
-          */
+           * Performs the copy using the given deduped filename.
+           * @param {string} destinationFilename
+           */
           destinationFilename => {
             this.cancelCallback_ = fileOperationUtil.copyTo(
-                entry,
-                destinationDirectory,
-                destinationFilename,
-                onEntryChanged,
-                onProgress,
-                onComplete,
-                onError);
+                entry, destinationDirectory, destinationFilename,
+                onEntryChanged, onProgress, onComplete, onError);
           },
           resolver.reject)
       .catch(importer.getLogger().catcher('import-task-copy'));
@@ -584,15 +577,12 @@
  * @param {!FileEntry} entry
  * @param {!FileEntry} destinationEntry
  */
-importer.MediaImportHandler.ImportTask.prototype.markAsCopied_ =
-    function(entry, destinationEntry) {
+importer.MediaImportHandler.ImportTask.prototype.markAsCopied_ = function(
+    entry, destinationEntry) {
   this.remainingFilesCount_--;
-  this.historyLoader_.getHistory().then(
-      history => {
-        history.markCopied(
-            entry,
-            this.destination_,
-            destinationEntry.toURL());
+  this.historyLoader_.getHistory()
+      .then(history => {
+        history.markCopied(entry, this.destination_, destinationEntry.toURL());
       })
       .catch(importer.getLogger().catcher('import-task-mark-as-copied'));
 };
@@ -601,14 +591,15 @@
  * @param {!FileEntry} entry
  * @private
  */
-importer.MediaImportHandler.ImportTask.prototype.markAsImported_ =
-    function(entry) {
+importer.MediaImportHandler.ImportTask.prototype.markAsImported_ = function(
+    entry) {
   this.remainingFilesCount_--;
-  this.historyLoader_.getHistory().then(
-      /** @param {!importer.ImportHistory} history */
-      history => {
-        history.markImported(entry, this.destination_);
-      })
+  this.historyLoader_.getHistory()
+      .then(
+          /** @param {!importer.ImportHistory} history */
+          history => {
+            history.markImported(entry, this.destination_);
+          })
       .catch(importer.getLogger().catcher('import-task-mark-as-imported'));
 };
 
@@ -620,9 +611,7 @@
 /**
  * Sends import statistics to analytics.
  */
-importer.MediaImportHandler.ImportTask.prototype.sendImportStats_ =
-    function() {
-
+importer.MediaImportHandler.ImportTask.prototype.sendImportStats_ = function() {
   const scanStats = this.scanResult_.getStatistics();
 
   metrics.recordMediumCount(
@@ -646,12 +635,11 @@
   scanStats.duplicates[importer.Disposition.CONTENT_DUPLICATE] =
       this.duplicateFilesCount_;
 
-  Object.keys(scanStats.duplicates).forEach(
-      disposition => {
-        const count = scanStats.duplicates[
-            /** @type {!importer.Disposition} */ (disposition)];
-        totalDeduped += count;
-      }, this);
+  Object.keys(scanStats.duplicates).forEach(disposition => {
+    const count = scanStats.duplicates[
+        /** @type {!importer.Disposition} */ (disposition)];
+    totalDeduped += count;
+  }, this);
 
   metrics.recordMediumCount('MediaImport.Duplicates', totalDeduped);
 };
diff --git a/ui/file_manager/file_manager/background/js/media_import_handler_unittest.js b/ui/file_manager/file_manager/background/js/media_import_handler_unittest.js
index 52df8ca..90ed9657a 100644
--- a/ui/file_manager/file_manager/background/js/media_import_handler_unittest.js
+++ b/ui/file_manager/file_manager/background/js/media_import_handler_unittest.js
@@ -115,14 +115,12 @@
     '/DCIM/photos0/IMG00003.jpg',
     '/DCIM/photos1/IMG00004.jpg',
     '/DCIM/photos1/IMG00005.jpg',
-    '/DCIM/photos1/IMG00006.jpg'
+    '/DCIM/photos1/IMG00006.jpg',
   ]);
 
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -182,9 +180,7 @@
       progressCenter, importHistory, dispositionChecker, driveSyncHandler);
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -205,24 +201,24 @@
   });
 
   reportPromise(
-      whenImportDone.then(
-          () => {
-            // Only the new file should be copied.
-            const mockDirectoryEntry =
-                /** @type {!MockDirectoryEntry} */ (destinationFileSystem.root);
-            const copiedEntries = mockDirectoryEntry.getAllChildren();
-            assertEquals(1, copiedEntries.length);
-            assertEquals(ORIGINAL_FILE_DEST_PATH, copiedEntries[0].fullPath);
-            const mockFileEntry = /** @type {!MockFileEntry} */ (media[1]);
-            importHistory.assertCopied(
-                mockFileEntry, importer.Destination.GOOGLE_DRIVE);
-            // The 2 duplicated files should be marked as imported.
-            [media[0], media[2]].forEach(entry => {
-              entry = /** @type {!MockFileEntry} */ (entry);
-              importHistory.assertImported(
-                  entry, importer.Destination.GOOGLE_DRIVE);
-            });
-          }), callback);
+      whenImportDone.then(() => {
+        // Only the new file should be copied.
+        const mockDirectoryEntry =
+            /** @type {!MockDirectoryEntry} */ (destinationFileSystem.root);
+        const copiedEntries = mockDirectoryEntry.getAllChildren();
+        assertEquals(1, copiedEntries.length);
+        assertEquals(ORIGINAL_FILE_DEST_PATH, copiedEntries[0].fullPath);
+        const mockFileEntry = /** @type {!MockFileEntry} */ (media[1]);
+        importHistory.assertCopied(
+            mockFileEntry, importer.Destination.GOOGLE_DRIVE);
+        // The 2 duplicated files should be marked as imported.
+        [media[0], media[2]].forEach(entry => {
+          entry = /** @type {!MockFileEntry} */ (entry);
+          importHistory.assertImported(
+              entry, importer.Destination.GOOGLE_DRIVE);
+        });
+      }),
+      callback);
 
   scanResult.finalize();
 }
@@ -237,9 +233,7 @@
 
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const promise =
       new Promise((resolve, reject) => {
@@ -283,14 +277,12 @@
     '/DCIM/photos0/IMG00003.jpg',
     '/DCIM/photos1/IMG00001.jpg',
     '/DCIM/photos1/IMG00002.jpg',
-    '/DCIM/photos1/IMG00003.jpg'
+    '/DCIM/photos1/IMG00003.jpg',
   ]);
 
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -333,14 +325,12 @@
     '/DCIM/photos0/IMG00003.jpg',
     '/DCIM/photos1/IMG00004.jpg',
     '/DCIM/photos1/IMG00005.jpg',
-    '/DCIM/photos1/IMG00006.jpg'
+    '/DCIM/photos1/IMG00006.jpg',
   ]);
 
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -384,7 +374,7 @@
     '/DCIM/photos0/IMG00001.jpg',
     '/DCIM/photos1/IMG00003.jpg',
     '/DCIM/photos0/DRIVEDUPE00001.jpg',
-    '/DCIM/photos1/DRIVEDUPE99999.jpg'
+    '/DCIM/photos1/DRIVEDUPE99999.jpg',
   ]);
 
   const newFiles = entries.slice(0, 2);
@@ -393,9 +383,7 @@
   const scanResult = new TestScanResult(entries.slice(0, 2));
   scanResult.duplicateFileEntries = dupeFiles;
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -440,14 +428,12 @@
 function testTagsEntriesAfterImport(callback) {
   const entries = setupFileSystem([
     '/DCIM/photos0/IMG00001.jpg',
-    '/DCIM/photos1/IMG00003.jpg'
+    '/DCIM/photos1/IMG00003.jpg',
   ]);
 
   const scanResult = new TestScanResult(entries);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -474,10 +460,9 @@
   };
 
   reportPromise(
-      whenImportDone.then(
-          () => {
-            assertEquals(entries.length, taggedEntries.length);
-          }),
+      whenImportDone.then(() => {
+        assertEquals(entries.length, taggedEntries.length);
+      }),
       callback);
 
   scanResult.finalize();
@@ -493,7 +478,7 @@
     '/DCIM/photos0/IMG00003.jpg',
     '/DCIM/photos1/IMG00004.jpg',
     '/DCIM/photos1/IMG00005.jpg',
-    '/DCIM/photos1/IMG00006.jpg'
+    '/DCIM/photos1/IMG00006.jpg',
   ]);
 
   /** @const {number} */
@@ -501,9 +486,7 @@
 
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportCancelled = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -556,7 +539,7 @@
     '/DCIM/photos0/IMG00003.jpg',
     '/DCIM/photos1/IMG00004.jpg',
     '/DCIM/photos1/IMG00005.jpg',
-    '/DCIM/photos1/IMG00006.jpg'
+    '/DCIM/photos1/IMG00006.jpg',
   ]);
 
   /** @const {number} */
@@ -564,9 +547,7 @@
 
   const scanResult = new TestScanResult(media);
   const importTask = mediaImporter.importFromScanResult(
-      scanResult,
-      importer.Destination.GOOGLE_DRIVE,
-      destinationFactory);
+      scanResult, importer.Destination.GOOGLE_DRIVE, destinationFactory);
 
   const whenImportDone = new Promise((resolve, reject) => {
     importTask.addObserver(
@@ -666,8 +647,9 @@
  * @param {function(Entry)} successCallback
  * @param {function(Error)} errorCallback
  */
-MockCopyTo.prototype.copyTo_ = function(source, parent, newName,
-    entryChangedCallback, progressCallback, successCallback, errorCallback) {
+MockCopyTo.prototype.copyTo_ = function(
+    source, parent, newName, entryChangedCallback, progressCallback,
+    successCallback, errorCallback) {
   this.entryChangedCallback_ = entryChangedCallback;
   this.progressCallback_ = progressCallback;
   this.successCallback_ = successCallback;
diff --git a/ui/file_manager/file_manager/background/js/media_scanner.js b/ui/file_manager/file_manager/background/js/media_scanner.js
index 81612b5..16a8fc2 100644
--- a/ui/file_manager/file_manager/background/js/media_scanner.js
+++ b/ui/file_manager/file_manager/background/js/media_scanner.js
@@ -16,9 +16,8 @@
  *     !Promise<!importer.Disposition>} dispositionChecker
  * @param {!importer.DirectoryWatcherFactory} watcherFactory
  */
-importer.DefaultMediaScanner =
-    function(hashGenerator, dispositionChecker, watcherFactory) {
-
+importer.DefaultMediaScanner = function(
+    hashGenerator, dispositionChecker, watcherFactory) {
   /**
    * A little factory for DefaultScanResults which allows us to forgo
    * the saving it's dependencies in our fields.
@@ -63,8 +62,8 @@
 };
 
 /** @override */
-importer.DefaultMediaScanner.prototype.scanDirectory = function(directory,
-                                                                mode) {
+importer.DefaultMediaScanner.prototype.scanDirectory = function(
+    directory, mode) {
   const scan = this.createScanResult_(mode);
   console.info(scan.name + ': Scanning directory ' + directory.fullPath);
 
@@ -80,14 +79,12 @@
       .then(scan.resolve)
       .catch(scan.reject);
 
-  scan.whenFinal()
-      .then(
-          () => {
-            console.info(
-                scan.name + ': Finished directory scan. Details: ' +
-                JSON.stringify(scan.getStatistics()));
-            this.notify_(importer.ScanEvent.FINALIZED, scan);
-          });
+  scan.whenFinal().then(() => {
+    console.info(
+        scan.name + ': Finished directory scan. Details: ' +
+        JSON.stringify(scan.getStatistics()));
+    this.notify_(importer.ScanEvent.FINALIZED, scan);
+  });
 
   return scan;
 };
@@ -99,30 +96,24 @@
   }
   const scan = this.createScanResult_(mode);
   console.info(
-      scan.name + ': Scanning fixed set of ' +
-      entries.length + ' entries.');
+      scan.name + ': Scanning fixed set of ' + entries.length + ' entries.');
 
-  const watcher = this.watcherFactory_(
-      () => {
-        scan.cancel();
-        this.notify_(importer.ScanEvent.INVALIDATED, scan);
-      });
+  const watcher = this.watcherFactory_(() => {
+    scan.cancel();
+    this.notify_(importer.ScanEvent.INVALIDATED, scan);
+  });
 
   scan.setCandidateCount(entries.length);
   const scanPromises = entries.map(this.onFileEntryFound_.bind(this, scan));
 
-  Promise.all(scanPromises)
-      .then(scan.resolve)
-      .catch(scan.reject);
+  Promise.all(scanPromises).then(scan.resolve).catch(scan.reject);
 
-  scan.whenFinal()
-      .then(
-          () => {
-            console.info(
-                scan.name + ': Finished file-selection scan. Details: ' +
-                JSON.stringify(scan.getStatistics()));
-            this.notify_(importer.ScanEvent.FINALIZED, scan);
-          });
+  scan.whenFinal().then(() => {
+    console.info(
+        scan.name + ': Finished file-selection scan. Details: ' +
+        JSON.stringify(scan.getStatistics()));
+    this.notify_(importer.ScanEvent.FINALIZED, scan);
+  });
 
   return scan;
 };
@@ -137,8 +128,8 @@
  *     or canceled.
  * @private
  */
-importer.DefaultMediaScanner.prototype.scanMediaFiles_ =
-    function(scan, entries) {
+importer.DefaultMediaScanner.prototype.scanMediaFiles_ = function(
+    scan, entries) {
   scan.setCandidateCount(entries.length);
   const handleFileEntry = this.onFileEntryFound_.bind(this, scan);
 
@@ -150,8 +141,7 @@
   const scanBatch = begin => {
     if (scan.canceled()) {
       console.debug(
-          scan.name + ': Skipping remaining ' +
-          (entries.length - begin) +
+          scan.name + ': Skipping remaining ' + (entries.length - begin) +
           ' entries. Scan was canceled.');
       return Promise.resolve();
     }
@@ -161,14 +151,11 @@
     console.log(scan.name + ': Processing batch ' + begin + '-' + (end - 1));
     const batch = entries.slice(begin, end);
 
-    return Promise.all(
-        batch.map(handleFileEntry))
-        .then(
-            () => {
-              if (end < entries.length) {
-                return scanBatch(end);
-              }
-            });
+    return Promise.all(batch.map(handleFileEntry)).then(() => {
+      if (end < entries.length) {
+        return scanBatch(end);
+      }
+    });
   };
 
   return scanBatch(0);
@@ -200,30 +187,30 @@
  */
 importer.DefaultMediaScanner.prototype.crawlDirectory_ =
     (directory, watcher) => {
-  const mediaFiles = [];
+      const mediaFiles = [];
 
-  return fileOperationUtil.findEntriesRecursively(
-      directory,
-      /** @param  {!Entry} entry */
-      entry => {
-        if (watcher.triggered) {
-          return;
-        }
+      return fileOperationUtil
+          .findEntriesRecursively(
+              directory,
+              /** @param  {!Entry} entry */
+              entry => {
+                if (watcher.triggered) {
+                  return;
+                }
 
-        if (entry.isDirectory) {
-          // Note, there is no need for us to recurse, the utility
-          // function findEntriesRecursively does that. So we
-          // just watch the directory for modifications, and that's it.
-          watcher.addDirectory(/** @type {!DirectoryEntry} */(entry));
-        } else if (importer.isEligibleType(entry)) {
-          mediaFiles.push(/** @type {!FileEntry} */ (entry));
-        }
-      })
-      .then(
-          () => {
+                if (entry.isDirectory) {
+                  // Note, there is no need for us to recurse, the utility
+                  // function findEntriesRecursively does that. So we
+                  // just watch the directory for modifications, and that's it.
+                  watcher.addDirectory(/** @type {!DirectoryEntry} */ (entry));
+                } else if (importer.isEligibleType(entry)) {
+                  mediaFiles.push(/** @type {!FileEntry} */ (entry));
+                }
+              })
+          .then(() => {
             return mediaFiles;
           });
-};
+    };
 
 /**
  * Finds all files beneath directory.
@@ -233,17 +220,16 @@
  * @return {!Promise}
  * @private
  */
-importer.DefaultMediaScanner.prototype.onFileEntryFound_ =
-    function(scan, entry) {
-
-  return this.getDisposition_(entry, importer.Destination.GOOGLE_DRIVE,
-                              scan.mode)
+importer.DefaultMediaScanner.prototype.onFileEntryFound_ = function(
+    scan, entry) {
+  return this
+      .getDisposition_(entry, importer.Destination.GOOGLE_DRIVE, scan.mode)
       .then(
           /**
-          * @param {!importer.Disposition} disposition The disposition
-          *     of the entry. Either some sort of dupe, or an original.
-          * @return {!Promise}
-          */
+           * @param {!importer.Disposition} disposition The disposition
+           *     of the entry. Either some sort of dupe, or an original.
+           * @return {!Promise}
+           */
           disposition => {
             return disposition === importer.Disposition.ORIGINAL ?
                 this.onUniqueFileFound_(scan, entry) :
@@ -259,25 +245,23 @@
  * @return {!Promise}
  * @private
  */
-importer.DefaultMediaScanner.prototype.onUniqueFileFound_ =
-    function(scan, entry) {
-
+importer.DefaultMediaScanner.prototype.onUniqueFileFound_ = function(
+    scan, entry) {
   scan.onCandidatesProcessed(1);
   if (!importer.isEligibleType(entry)) {
     this.notify_(importer.ScanEvent.UPDATED, scan);
     return Promise.resolve();
   }
 
-  return scan.addFileEntry(entry)
-      .then(
-          /**
-          * @param {boolean} added
-          */
-          added => {
-            if (added) {
-              this.notify_(importer.ScanEvent.UPDATED, scan);
-            }
-          });
+  return scan.addFileEntry(entry).then(
+      /**
+       * @param {boolean} added
+       */
+      added => {
+        if (added) {
+          this.notify_(importer.ScanEvent.UPDATED, scan);
+        }
+      });
 };
 
 /**
@@ -290,8 +274,8 @@
  * @return {!Promise}
  * @private
  */
-importer.DefaultMediaScanner.prototype.onDuplicateFileFound_ =
-    function(scan, entry, disposition) {
+importer.DefaultMediaScanner.prototype.onDuplicateFileFound_ = function(
+    scan, entry, disposition) {
   scan.onCandidatesProcessed(1);
   scan.addDuplicateEntry(entry, disposition);
   this.notify_(importer.ScanEvent.UPDATED, scan);
@@ -427,8 +411,7 @@
 };
 
 /** @override */
-importer.DefaultScanResult.prototype.getDuplicateFileEntries =
-    function() {
+importer.DefaultScanResult.prototype.getDuplicateFileEntries = function() {
   return this.duplicateFileEntries_;
 };
 
@@ -457,35 +440,31 @@
 importer.DefaultScanResult.prototype.addFileEntry = function(entry) {
   return metadataProxy.getEntryMetadata(entry).then(
       /**
-      * @param {!Metadata} metadata
-      */
+       * @param {!Metadata} metadata
+       */
       metadata => {
         console.assert(
-            'size' in metadata,
-            'size attribute missing from metadata.');
+            'size' in metadata, 'size attribute missing from metadata.');
 
-        return this.createHashcode_(entry)
-            .then(
-                /**
-                * @param {string} hashcode
-                */
-                hashcode => {
-                  this.lastScanActivity_ = new Date();
+        return this.createHashcode_(entry).then(
+            /**
+             * @param {string} hashcode
+             */
+            hashcode => {
+              this.lastScanActivity_ = new Date();
 
-                  if (hashcode in this.fileHashcodes_) {
-                    this.addDuplicateEntry(
-                        entry,
-                        importer.Disposition.SCAN_DUPLICATE);
-                    return false;
-                  }
+              if (hashcode in this.fileHashcodes_) {
+                this.addDuplicateEntry(
+                    entry, importer.Disposition.SCAN_DUPLICATE);
+                return false;
+              }
 
-                  entry.size = metadata.size;
-                  this.totalBytes_ += metadata.size;
-                  this.fileHashcodes_[hashcode] = entry;
-                  this.fileEntries_.push(entry);
-                  return true;
-                });
-
+              entry.size = metadata.size;
+              this.totalBytes_ += metadata.size;
+              this.fileHashcodes_[hashcode] = entry;
+              this.fileEntries_.push(entry);
+              return true;
+            });
       });
 };
 
@@ -494,9 +473,8 @@
  * @param {!FileEntry} entry
  * @param {!importer.Disposition} disposition
  */
-importer.DefaultScanResult.prototype.addDuplicateEntry =
-    function(entry, disposition) {
-
+importer.DefaultScanResult.prototype.addDuplicateEntry = function(
+    entry, disposition) {
   switch (disposition) {
     case importer.Disposition.SCAN_DUPLICATE:
     case importer.Disposition.CONTENT_DUPLICATE:
@@ -519,7 +497,7 @@
     sizeBytes: this.totalBytes_,
     candidates: {
       total: this.candidateCount_,
-      processed: this.candidatesProcessed_
+      processed: this.candidatesProcessed_,
     },
     progress: this.calculateProgress_()
   };
diff --git a/ui/file_manager/file_manager/background/js/media_scanner_unittest.js b/ui/file_manager/file_manager/background/js/media_scanner_unittest.js
index 9511ecc6..9440ac9 100644
--- a/ui/file_manager/file_manager/background/js/media_scanner_unittest.js
+++ b/ui/file_manager/file_manager/background/js/media_scanner_unittest.js
@@ -67,7 +67,7 @@
 function testIsScanning(callback) {
   const filenames = [
     'happy',
-    'thoughts'
+    'thoughts',
   ];
   reportPromise(
       makeTestFileSystemRoot('testIsScanning')
@@ -87,7 +87,7 @@
 function testObserverNotifiedOnScanFinish(callback) {
   const filenames = [
     'happy',
-    'thoughts'
+    'thoughts',
   ];
   makeTestFileSystemRoot('testObserverNotifiedOnScanFinish')
       .then(populateDir.bind(null, filenames))
@@ -102,12 +102,11 @@
             // use in an assert. Promises ensure the scan won't finish
             // until after our function is fully processed.
             const result = scanner.scanDirectory(root, scanMode);
-            scanner.addObserver(
-                (eventType, scanResult) => {
-                  assertEquals(importer.ScanEvent.FINALIZED, eventType);
-                  assertEquals(result, scanResult);
-                  callback(false);
-                });
+            scanner.addObserver((eventType, scanResult) => {
+              assertEquals(importer.ScanEvent.FINALIZED, eventType);
+              assertEquals(result, scanResult);
+              callback(false);
+            });
           })
       .catch(() => {
         callback(true);
@@ -122,12 +121,12 @@
     'foo',
     'foo.jpg',
     'bar.gif',
-    'baz.avi'
+    'baz.avi',
   ];
   const expectedFiles = [
     '/testScanFiles/foo.jpg',
     '/testScanFiles/bar.gif',
-    '/testScanFiles/baz.avi'
+    '/testScanFiles/baz.avi',
   ];
   reportPromise(
       makeTestFileSystemRoot('testScanFiles')
@@ -151,7 +150,7 @@
     'driveimage1234.jpg',  // a content duplicate
     'foo.jpg',
     'bar.gif',
-    'baz.avi'
+    'baz.avi',
   ];
 
   // Replace the default dispositionChecker with a function
@@ -190,7 +189,7 @@
 function testEmptyScanResults(callback) {
   const filenames = [
     'happy',
-    'thoughts'
+    'thoughts',
   ];
   reportPromise(
       makeTestFileSystemRoot('testEmptyScanResults')
@@ -217,12 +216,12 @@
     'bar.gif',
     'baz.avi',
     'foo.mp3',
-    'bar.txt'
+    'bar.txt',
   ];
   const expectedFiles = [
     '/testSingleLevel/foo.jpg',
     '/testSingleLevel/bar.gif',
-    '/testSingleLevel/baz.avi'
+    '/testSingleLevel/baz.avi',
   ];
   reportPromise(
       makeTestFileSystemRoot('testSingleLevel')
@@ -250,12 +249,12 @@
     'bar.gif',
     'baz.avi',
     'foo.mp3',
-    'bar.txt'
+    'bar.txt',
   ];
   const expectedFiles = [
     '/testProgress/foo.jpg',
     '/testProgress/bar.gif',
-    '/testProgress/baz.avi'
+    '/testProgress/baz.avi',
   ];
   reportPromise(
       makeTestFileSystemRoot('testProgress')
@@ -276,15 +275,14 @@
  * Verifies that scanning ignores previously imported entries.
  */
 function testIgnoresPreviousImports(callback) {
-  importHistory.importedPaths[
-      '/testIgnoresPreviousImports/oldimage1234.jpg'] =
-          [importer.Destination.GOOGLE_DRIVE];
+  importHistory.importedPaths['/testIgnoresPreviousImports/oldimage1234.jpg'] =
+      [importer.Destination.GOOGLE_DRIVE];
   const filenames = [
     'oldimage1234.jpg',    // a history duplicate
     'driveimage1234.jpg',  // a content duplicate
     'foo.jpg',
     'bar.gif',
-    'baz.avi'
+    'baz.avi',
   ];
 
   // Replace the default dispositionChecker with a function
@@ -302,7 +300,7 @@
   const expectedFiles = [
     '/testIgnoresPreviousImports/foo.jpg',
     '/testIgnoresPreviousImports/bar.gif',
-    '/testIgnoresPreviousImports/baz.avi'
+    '/testIgnoresPreviousImports/baz.avi',
   ];
 
   const promise =
@@ -322,15 +320,14 @@
 }
 
 function testTracksDuplicates(callback) {
-  importHistory.importedPaths[
-      '/testTracksDuplicates/oldimage1234.jpg'] =
-          [importer.Destination.GOOGLE_DRIVE];
+  importHistory.importedPaths['/testTracksDuplicates/oldimage1234.jpg'] =
+      [importer.Destination.GOOGLE_DRIVE];
   const filenames = [
     'oldimage1234.jpg',    // a history duplicate
     'driveimage1234.jpg',  // a content duplicate
     'driveimage9999.jpg',  // a content duplicate
     'bar.gif',
-    'baz.avi'
+    'baz.avi',
   ];
 
   // Replace the default dispositionChecker with a function
@@ -350,7 +347,7 @@
 
   const expectedDuplicates = [
     '/testTracksDuplicates/driveimage1234.jpg',
-    '/testTracksDuplicates/driveimage9999.jpg'
+    '/testTracksDuplicates/driveimage9999.jpg',
   ];
 
   const promise =
@@ -371,26 +368,25 @@
 
 function testMultiLevel(callback) {
   const filenames = [
-    'foo.jpg',
-    'bar',
+    'foo.jpg', 'bar',
     [
       'dir1',
-      'bar.0.jpg'
+      'bar.0.jpg',
     ],
     [
       'dir2',
       'bar.1.gif',
       [
         'dir3',
-        'bar.1.0.avi'
-      ]
+        'bar.1.0.avi',
+      ],
     ]
   ];
   const expectedFiles = [
     '/testMultiLevel/foo.jpg',
     '/testMultiLevel/dir1/bar.0.jpg',
     '/testMultiLevel/dir2/bar.1.gif',
-    '/testMultiLevel/dir2/dir3/bar.1.0.avi'
+    '/testMultiLevel/dir2/dir3/bar.1.0.avi',
   ];
 
   reportPromise(
@@ -410,12 +406,11 @@
 
 function testDedupesFilesInScanResult(callback) {
   const filenames = [
-    'foo.jpg',
-    'bar.jpg',
+    'foo.jpg', 'bar.jpg',
     [
       'dir1',
       'foo.jpg',
-      'bar.jpg'
+      'bar.jpg',
     ],
     [
       'dir2',
@@ -424,13 +419,13 @@
       [
         'dir3',
         'foo.jpg',
-        'bar.jpg'
-      ]
+        'bar.jpg',
+      ],
     ]
   ];
   const expectedFiles = [
     '/testDedupesFilesInScanResult/foo.jpg',
-    '/testDedupesFilesInScanResult/bar.jpg'
+    '/testDedupesFilesInScanResult/bar.jpg',
   ];
 
   reportPromise(
@@ -535,28 +530,18 @@
   function makeTestFilesystem() {
     return new Promise((resolve, reject) => {
       window.webkitRequestFileSystem(
-          window.TEMPORARY,
-          1024 * 1024,
-          resolve,
-          reject);
+          window.TEMPORARY, 1024 * 1024, resolve, reject);
     });
   }
 
-  return makeTestFilesystem()
-      .then(
-          // Create a directory, pretend that's the root.
-          fs => {
-            return new Promise((resolve, reject) => {
-              fs.root.getDirectory(
-                    directoryName,
-                    {
-                      create: true,
-                      exclusive: true
-                    },
-                  resolve,
-                  reject);
-            });
-          });
+  return makeTestFilesystem().then(
+      // Create a directory, pretend that's the root.
+      fs => {
+        return new Promise((resolve, reject) => {
+          fs.root.getDirectory(
+              directoryName, {create: true, exclusive: true}, resolve, reject);
+        });
+      });
 }
 
 /**
@@ -568,27 +553,22 @@
  *     directory tree.
  */
 function populateDir(filenames, dir) {
-  return Promise.all(
-      filenames.map(
-          filename => {
-            if (filename instanceof Array) {
-              return new Promise(
-                  (resolve, reject) => {
-                    dir.getDirectory(
-                        filename[0],
-                        {create: true},
-                        resolve,
-                        reject);
-                  })
-                  .then(populateDir.bind(null, filename));
-            } else {
-              const name = /** @type {string} */ (filename);
-              return new Promise((resolve, reject) => {
-                dir.getFile(name, {create: true}, resolve, reject);
-              });
-            }
-          })).then(
-              () => {
-                return dir;
-              });
+  return Promise
+      .all(filenames.map(filename => {
+        if (filename instanceof Array) {
+          return new Promise((resolve, reject) => {
+                   dir.getDirectory(
+                       filename[0], {create: true}, resolve, reject);
+                 })
+              .then(populateDir.bind(null, filename));
+        } else {
+          const name = /** @type {string} */ (filename);
+          return new Promise((resolve, reject) => {
+            dir.getFile(name, {create: true}, resolve, reject);
+          });
+        }
+      }))
+      .then(() => {
+        return dir;
+      });
 }
diff --git a/ui/file_manager/file_manager/background/js/mock_media_scanner.js b/ui/file_manager/file_manager/background/js/mock_media_scanner.js
index d59443c4..911b3b8 100644
--- a/ui/file_manager/file_manager/background/js/mock_media_scanner.js
+++ b/ui/file_manager/file_manager/background/js/mock_media_scanner.js
@@ -84,10 +84,9 @@
 TestMediaScanner.prototype.update = function() {
   assertTrue(this.scans_.length > 0);
   const scan = this.scans_[this.scans_.length - 1];
-  this.observers.forEach(
-      observer => {
-        observer(importer.ScanEvent.UPDATED, scan);
-      });
+  this.observers.forEach(observer => {
+    observer(importer.ScanEvent.UPDATED, scan);
+  });
 };
 
 /**
@@ -164,17 +163,16 @@
   this.canceled_ = false;
 
   /** @type {!Promise<!importer.ScanResult>} */
-  this.whenFinal_ = new Promise(
-      (resolve, reject) => {
-        this.resolveResult_ = result => {
-          this.settled_ = true;
-          resolve(result);
-        };
-        this.rejectResult_ = () => {
-          this.settled_ = true;
-          reject();
-        };
-      });
+  this.whenFinal_ = new Promise((resolve, reject) => {
+    this.resolveResult_ = result => {
+      this.settled_ = true;
+      resolve(result);
+    };
+    this.rejectResult_ = () => {
+      this.settled_ = true;
+      reject();
+    };
+  });
 }
 
 /** @private {number} */
@@ -266,5 +264,4 @@
 /**
  * @override
  */
-TestDirectoryWatcher.prototype.addDirectory = () => {
-};
+TestDirectoryWatcher.prototype.addDirectory = () => {};
diff --git a/ui/file_manager/file_manager/background/js/mock_volume_manager.js b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
index a1a3f5a..fb11965e 100644
--- a/ui/file_manager/file_manager/background/js/mock_volume_manager.js
+++ b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
@@ -178,37 +178,41 @@
  * @param {string=} providerId Provider id.
  * @return {!VolumeInfo} Created mock VolumeInfo.
  */
-MockVolumeManager.createMockVolumeInfo = (type, volumeId, label, devicePath, providerId) => {
-  const fileSystem = new MockFileSystem(volumeId, 'filesystem:' + volumeId);
+MockVolumeManager.createMockVolumeInfo =
+    (type, volumeId, label, devicePath, providerId) => {
+      const fileSystem = new MockFileSystem(volumeId, 'filesystem:' + volumeId);
 
-  // If there's no label set it to volumeId to make it shorter to write tests.
-  const volumeInfo = new VolumeInfoImpl(
-      type, volumeId, fileSystem,
-      '',                                          // error
-      '',                                          // deviceType
-      devicePath || '',                            // devicePath
-      false,                                       // isReadOnly
-      false,                                       // isReadOnlyRemovableDevice
-      {isCurrentProfile: true, displayName: ''},   // profile
-      label || volumeId,                           // label
-      providerId,                                  // providerId
-      false,                                       // hasMedia
-      false,                                       // configurable
-      false,                                       // watchable
-      VolumeManagerCommon.Source.NETWORK,          // source
-      VolumeManagerCommon.FileSystemType.UNKNOWN,  // diskFileSystemType
-      {},                                          // iconSet
-      '');                                         // driveLabel
+      // If there's no label set it to volumeId to make it shorter to write
+      // tests.
+      const volumeInfo = new VolumeInfoImpl(
+          type, volumeId, fileSystem,
+          '',                // error
+          '',                // deviceType
+          devicePath || '',  // devicePath
+          false,             // isReadOnly
+          false,             // isReadOnlyRemovableDevice
+          {isCurrentProfile: true, displayName: ''},   // profile
+          label || volumeId,                           // label
+          providerId,                                  // providerId
+          false,                                       // hasMedia
+          false,                                       // configurable
+          false,                                       // watchable
+          VolumeManagerCommon.Source.NETWORK,          // source
+          VolumeManagerCommon.FileSystemType.UNKNOWN,  // diskFileSystemType
+          {},                                          // iconSet
+          '');                                         // driveLabel
 
-  return volumeInfo;
-};
+      return volumeInfo;
+    };
 
-MockVolumeManager.prototype.mountArchive = (fileUrl, successCallback, errorCallback) => {
-  throw new Error('Not implemented.');
-};
-MockVolumeManager.prototype.unmount = (volumeInfo, successCallback, errorCallback) => {
-  throw new Error('Not implemented.');
-};
+MockVolumeManager.prototype.mountArchive =
+    (fileUrl, successCallback, errorCallback) => {
+      throw new Error('Not implemented.');
+    };
+MockVolumeManager.prototype.unmount =
+    (volumeInfo, successCallback, errorCallback) => {
+      throw new Error('Not implemented.');
+    };
 MockVolumeManager.prototype.configure = volumeInfo => {
   throw new Error('Not implemented.');
 };
diff --git a/ui/file_manager/file_manager/background/js/progress_center.js b/ui/file_manager/file_manager/background/js/progress_center.js
index 58b08264..38658c2 100644
--- a/ui/file_manager/file_manager/background/js/progress_center.js
+++ b/ui/file_manager/file_manager/background/js/progress_center.js
@@ -94,7 +94,8 @@
  */
 ProgressCenterImpl.Notifications_.prototype.updateItem = function(
     item, newItemAcceptable) {
-  const NotificationState = ProgressCenterImpl.Notifications_.NotificationState_;
+  const NotificationState =
+      ProgressCenterImpl.Notifications_.NotificationState_;
   const newlyAdded = !(item.id in this.ids_);
 
   // If new item is not acceptable, just return.
@@ -136,7 +137,8 @@
       message: item.message,
       buttons: item.cancelable ? [{title: str('CANCEL_LABEL')}] : undefined,
       progress: item.state === ProgressItemState.PROGRESSING ?
-          item.progressRateInPercent : undefined,
+          item.progressRateInPercent :
+          undefined,
       priority: (item.state === ProgressItemState.ERROR || !item.quiet) ? 0 : -1
     };
     if (newlyAdded) {
diff --git a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
index f7e2c89..ec0fa7f 100644
--- a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
+++ b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
@@ -173,10 +173,11 @@
  *     information that contains contentText, attribute names and
  *     values, hidden attribute, and style names and values.
  */
-test.util.sync.queryAllElements = (contentWindow, targetQuery, opt_styleNames) => {
-  return test.util.sync.deepQueryAllElements(
-      contentWindow, targetQuery, opt_styleNames);
-};
+test.util.sync.queryAllElements =
+    (contentWindow, targetQuery, opt_styleNames) => {
+      return test.util.sync.deepQueryAllElements(
+          contentWindow, targetQuery, opt_styleNames);
+    };
 
 /**
  * Queries elements inside shadow DOM.
@@ -192,20 +193,21 @@
  *     information that contains contentText, attribute names and
  *     values, hidden attribute, and style names and values.
  */
-test.util.sync.deepQueryAllElements = (contentWindow, targetQuery, opt_styleNames) => {
-  if (!contentWindow.document) {
-    return [];
-  }
-  if (typeof targetQuery === 'string') {
-    targetQuery = [targetQuery];
-  }
+test.util.sync.deepQueryAllElements =
+    (contentWindow, targetQuery, opt_styleNames) => {
+      if (!contentWindow.document) {
+        return [];
+      }
+      if (typeof targetQuery === 'string') {
+        targetQuery = [targetQuery];
+      }
 
-  const elems =
-      test.util.sync.deepQuerySelectorAll_(contentWindow.document, targetQuery);
-  return elems.map(element => {
-    return extractElementInfo(element, contentWindow, opt_styleNames);
-  });
-};
+      const elems = test.util.sync.deepQuerySelectorAll_(
+          contentWindow.document, targetQuery);
+      return elems.map(element => {
+        return extractElementInfo(element, contentWindow, opt_styleNames);
+      });
+    };
 
 /**
  * Selects elements below |root|, possibly following shadow DOM subtree.
@@ -219,7 +221,8 @@
  * @private
  */
 test.util.sync.deepQuerySelectorAll_ = (root, targetQuery) => {
-  const elems = Array.prototype.slice.call(root.querySelectorAll(targetQuery[0]));
+  const elems =
+      Array.prototype.slice.call(root.querySelectorAll(targetQuery[0]));
   const remaining = targetQuery.slice(1);
   if (remaining.length === 0) {
     return elems;
@@ -249,15 +252,16 @@
  * @param {function(*)} callback Callback function to be called with the
  *   result of the |script|.
  */
-test.util.async.deepExecuteScriptInWebView = (contentWindow, targetQuery, script, callback) => {
-  const webviews =
-      test.util.sync.deepQuerySelectorAll_(contentWindow.document, targetQuery);
-  if (!webviews || webviews.length !== 1) {
-    throw new Error('<webview> not found: [' + targetQuery.join(',') + ']');
-  }
-  const webview = /** @type {WebView} */ (webviews[0]);
-  webview.executeScript({code: script}, callback);
-};
+test.util.async.deepExecuteScriptInWebView =
+    (contentWindow, targetQuery, script, callback) => {
+      const webviews = test.util.sync.deepQuerySelectorAll_(
+          contentWindow.document, targetQuery);
+      if (!webviews || webviews.length !== 1) {
+        throw new Error('<webview> not found: [' + targetQuery.join(',') + ']');
+      }
+      const webview = /** @type {WebView} */ (webviews[0]);
+      webview.executeScript({code: script}, callback);
+    };
 
 /**
  * Gets the information of the active element.
@@ -365,17 +369,18 @@
  *     properties.
  * @return {boolean} True if the event is sent to the target, false otherwise.
  */
-test.util.sync.fakeEvent = (contentWindow, targetQuery, eventType, opt_additionalProperties) => {
-  const event = new Event(
-      eventType,
-      /** @type {!EventInit} */ (opt_additionalProperties || {}));
-  if (opt_additionalProperties) {
-    for (const name in opt_additionalProperties) {
-      event[name] = opt_additionalProperties[name];
-    }
-  }
-  return test.util.sync.sendEvent(contentWindow, targetQuery, event);
-};
+test.util.sync.fakeEvent =
+    (contentWindow, targetQuery, eventType, opt_additionalProperties) => {
+      const event = new Event(
+          eventType,
+          /** @type {!EventInit} */ (opt_additionalProperties || {}));
+      if (opt_additionalProperties) {
+        for (const name in opt_additionalProperties) {
+          event[name] = opt_additionalProperties[name];
+        }
+      }
+      return test.util.sync.sendEvent(contentWindow, targetQuery, event);
+    };
 
 /**
  * Sends a fake key event to the element specified by |targetQuery| or active
@@ -390,17 +395,18 @@
  * @param {boolean} alt whether ALT should be pressed, or not.
  * @return {boolean} True if the event is sent to the target, false otherwise.
  */
-test.util.sync.fakeKeyDown = (contentWindow, targetQuery, key, ctrl, shift, alt) => {
-  const event = new KeyboardEvent('keydown', {
-    bubbles: true,
-    composed: true,  // Allow the event to bubble past shadow DOM root.
-    key: key,
-    ctrlKey: ctrl,
-    shiftKey: shift,
-    altKey: alt
-  });
-  return test.util.sync.sendEvent(contentWindow, targetQuery, event);
-};
+test.util.sync.fakeKeyDown =
+    (contentWindow, targetQuery, key, ctrl, shift, alt) => {
+      const event = new KeyboardEvent('keydown', {
+        bubbles: true,
+        composed: true,  // Allow the event to bubble past shadow DOM root.
+        key: key,
+        ctrlKey: ctrl,
+        shiftKey: shift,
+        altKey: alt,
+      });
+      return test.util.sync.sendEvent(contentWindow, targetQuery, event);
+    };
 
 /**
  * Simulates a fake mouse click (left button, single click) on the element
@@ -418,30 +424,31 @@
  * @return {boolean} True if the all events are sent to the target, false
  *     otherwise.
  */
-test.util.sync.fakeMouseClick = (contentWindow, targetQuery, opt_keyModifiers) => {
-  const modifiers = opt_keyModifiers || {};
-  const props = {
-    bubbles: true,
-    detail: 1,
-    composed: true,  // Allow the event to bubble past shadow DOM root.
-    ctrlKey: modifiers.ctrl,
-    shiftKey: modifiers.shift,
-    altKey: modifiers.alt,
-  };
-  const mouseOverEvent = new MouseEvent('mouseover', props);
-  const resultMouseOver =
-      test.util.sync.sendEvent(contentWindow, targetQuery, mouseOverEvent);
-  const mouseDownEvent = new MouseEvent('mousedown', props);
-  const resultMouseDown =
-      test.util.sync.sendEvent(contentWindow, targetQuery, mouseDownEvent);
-  const mouseUpEvent = new MouseEvent('mouseup', props);
-  const resultMouseUp =
-      test.util.sync.sendEvent(contentWindow, targetQuery, mouseUpEvent);
-  const clickEvent = new MouseEvent('click', props);
-  const resultClick =
-      test.util.sync.sendEvent(contentWindow, targetQuery, clickEvent);
-  return resultMouseOver && resultMouseDown && resultMouseUp && resultClick;
-};
+test.util.sync.fakeMouseClick =
+    (contentWindow, targetQuery, opt_keyModifiers) => {
+      const modifiers = opt_keyModifiers || {};
+      const props = {
+        bubbles: true,
+        detail: 1,
+        composed: true,  // Allow the event to bubble past shadow DOM root.
+        ctrlKey: modifiers.ctrl,
+        shiftKey: modifiers.shift,
+        altKey: modifiers.alt,
+      };
+      const mouseOverEvent = new MouseEvent('mouseover', props);
+      const resultMouseOver =
+          test.util.sync.sendEvent(contentWindow, targetQuery, mouseOverEvent);
+      const mouseDownEvent = new MouseEvent('mousedown', props);
+      const resultMouseDown =
+          test.util.sync.sendEvent(contentWindow, targetQuery, mouseDownEvent);
+      const mouseUpEvent = new MouseEvent('mouseup', props);
+      const resultMouseUp =
+          test.util.sync.sendEvent(contentWindow, targetQuery, mouseUpEvent);
+      const clickEvent = new MouseEvent('click', props);
+      const resultClick =
+          test.util.sync.sendEvent(contentWindow, targetQuery, clickEvent);
+      return resultMouseOver && resultMouseDown && resultMouseUp && resultClick;
+    };
 
 /**
  * Simulates a mouse hover on an element specified by |targetQuery|.
@@ -718,7 +725,8 @@
 test.util.async.getFilesUnderVolume = (volumeType, names, callback) => {
   const displayRootPromise =
       volumeManagerFactory.getInstance().then(volumeManager => {
-        const volumeInfo = volumeManager.getCurrentProfileVolumeInfo(volumeType);
+        const volumeInfo =
+            volumeManager.getCurrentProfileVolumeInfo(volumeType);
         return volumeInfo.resolveDisplayRoot();
       });
 
diff --git a/ui/file_manager/file_manager/background/js/task_queue.js b/ui/file_manager/file_manager/background/js/task_queue.js
index da0c33c..3e22b5e 100644
--- a/ui/file_manager/file_manager/background/js/task_queue.js
+++ b/ui/file_manager/file_manager/background/js/task_queue.js
@@ -107,7 +107,8 @@
   if (updateType === UpdateType.COMPLETE ||
       updateType === UpdateType.CANCELED) {
     // Assumption: the currently running task is at the head of the queue.
-    console.assert(this.tasks_[0] === task,
+    console.assert(
+        this.tasks_[0] === task,
         'Only tasks that are at the head of the queue should be active');
     // Remove the completed task from the queue.
     this.tasks_.shift();
@@ -227,8 +228,7 @@
       this.finishedResolver_.resolve(updateType);
   }
 
-  this.observers_.forEach(
-      callback => {
-        callback.call(null, updateType, opt_data);
-      });
+  this.observers_.forEach(callback => {
+    callback.call(null, updateType, opt_data);
+  });
 };
diff --git a/ui/file_manager/file_manager/background/js/task_queue_unittest.js b/ui/file_manager/file_manager/background/js/task_queue_unittest.js
index fd5cf32..78ecb85 100644
--- a/ui/file_manager/file_manager/background/js/task_queue_unittest.js
+++ b/ui/file_manager/file_manager/background/js/task_queue_unittest.js
@@ -102,9 +102,7 @@
   // Enqueue both tasks, and then verify that they were run.
   queue.queueTask(task0);
   queue.queueTask(task1);
-  reportPromise(
-      Promise.all([task0.whenRun(), task1.whenRun()]),
-      callback);
+  reportPromise(Promise.all([task0.whenRun(), task1.whenRun()]), callback);
 }
 
 // Verifies that the active callback triggers when the queue starts doing work
@@ -113,12 +111,11 @@
 
   // Make a promise that resolves when the active callback is triggered.
   const whenActive = new Promise(resolve => {
-    queue.setActiveCallback(
-        () => {
-          // Verify that the active callback is called before the task runs.
-          assertFalse(task.wasRun);
-          resolve();
-        });
+    queue.setActiveCallback(() => {
+      // Verify that the active callback is called before the task runs.
+      assertFalse(task.wasRun);
+      resolve();
+    });
   });
 
   // Queue a task, and then check that the active callback was triggered.
@@ -137,12 +134,11 @@
   // Make a promise that resolves when the idle callback is triggered
   // (i.e. after all queued tasks have finished running).
   const whenDone = new Promise(resolve => {
-    queue.setIdleCallback(
-        () => {
-          // Verify that the idle callback is called after the task runs.
-          assertTrue(task.wasRun);
-          resolve();
-        });
+    queue.setIdleCallback(() => {
+      // Verify that the idle callback is called after the task runs.
+      assertTrue(task.wasRun);
+      resolve();
+    });
   });
 
   // Queue a task, then check that the idle callback was triggered.
@@ -156,25 +152,22 @@
 
   // Get the task to report some progress, then success, when it's run.
   task.whenRun()
-      .then(
-          task => {
-            task.notifyProgress();
-            return task;
-          })
-      .then(
-          task => {
-            task.notifyComplete();
-            return task;
-          });
+      .then(task => {
+        task.notifyProgress();
+        return task;
+      })
+      .then(task => {
+        task.notifyComplete();
+        return task;
+      });
 
   // Make a promise that resolves after the task runs.
   const whenDone = new Promise(resolve => {
-    queue.setIdleCallback(
-        () => {
-          // Verify that progress was recorded.
-          assertEquals(1, updates[importer.TaskQueue.UpdateType.PROGRESS]);
-          resolve();
-        });
+    queue.setIdleCallback(() => {
+      // Verify that progress was recorded.
+      assertEquals(1, updates[importer.TaskQueue.UpdateType.PROGRESS]);
+      resolve();
+    });
   });
 
   queue.queueTask(task);
@@ -194,12 +187,11 @@
   queue.queueTask(task);
 
   const whenDone = new Promise(resolve => {
-    queue.setIdleCallback(
-        () => {
-          // Verify that the done callback was called.
-          assertEquals(1, updates[importer.TaskQueue.UpdateType.COMPLETE]);
-          resolve();
-        });
+    queue.setIdleCallback(() => {
+      // Verify that the done callback was called.
+      assertEquals(1, updates[importer.TaskQueue.UpdateType.COMPLETE]);
+      resolve();
+    });
   });
 
   reportPromise(whenDone, callback);
@@ -210,23 +202,21 @@
   const task = new TestTask('task0');
 
   // Get the task to report an error when it's run.
-  task.whenRun().then(
-      task => {
-        task.notifyError();
-        // Errors are not terminal; still need to signal task completion
-        // otherwise the test hangs.
-        task.notifyComplete();
-      });
+  task.whenRun().then(task => {
+    task.notifyError();
+    // Errors are not terminal; still need to signal task completion
+    // otherwise the test hangs.
+    task.notifyComplete();
+  });
 
   queue.queueTask(task);
 
   const whenDone = new Promise(resolve => {
-    queue.setIdleCallback(
-        () => {
-          // Verify that the done callback was called.
-          assertEquals(1, updates[importer.TaskQueue.UpdateType.ERROR]);
-          resolve();
-        });
+    queue.setIdleCallback(() => {
+      // Verify that the done callback was called.
+      assertEquals(1, updates[importer.TaskQueue.UpdateType.ERROR]);
+      resolve();
+    });
   });
 
   reportPromise(whenDone, callback);
@@ -247,7 +237,5 @@
   // Enqueue both tasks, and then verify that they were run.
   queue.queueTask(task0);
   queue.queueTask(task1);
-  reportPromise(
-      Promise.all([task0.whenRun(), task1.whenRun()]),
-      callback);
+  reportPromise(Promise.all([task0.whenRun(), task1.whenRun()]), callback);
 }
diff --git a/ui/file_manager/file_manager/background/js/test_import_history.js b/ui/file_manager/file_manager/background/js/test_import_history.js
index ef69fa7..903add4 100644
--- a/ui/file_manager/file_manager/background/js/test_import_history.js
+++ b/ui/file_manager/file_manager/background/js/test_import_history.js
@@ -60,8 +60,8 @@
  * @param {!FileEntry} entry
  * @param {!importer.Destination} destination
  */
-importer.TestImportHistory.prototype.assertCopied =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.assertCopied = function(
+    entry, destination) {
   assertTrue(this.wasCopied_(entry, destination));
 };
 
@@ -71,23 +71,21 @@
  * @param {!importer.Destination} destination
  * @return {boolean}
  */
-importer.TestImportHistory.prototype.wasCopied_ =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.wasCopied_ = function(entry, destination) {
   const path = entry.fullPath;
   return path in this.copiedPaths &&
       this.copiedPaths[path].indexOf(destination) > -1;
 };
 
 /** @override */
-importer.TestImportHistory.prototype.wasCopied =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.wasCopied = function(entry, destination) {
   const path = entry.fullPath;
   return Promise.resolve(this.wasCopied_(entry, destination));
 };
 
 /** @override */
-importer.TestImportHistory.prototype.markCopied =
-    function(entry, destination, destinationUrl) {
+importer.TestImportHistory.prototype.markCopied = function(
+    entry, destination, destinationUrl) {
   const path = entry.fullPath;
   if (path in this.copiedPaths) {
     this.copiedPaths[path].push(destination);
@@ -98,8 +96,7 @@
 };
 
 /** @override */
-importer.TestImportHistory.prototype.listUnimportedUrls =
-    destination => {
+importer.TestImportHistory.prototype.listUnimportedUrls = destination => {
   return Promise.resolve([]);
 };
 
@@ -107,8 +104,8 @@
  * @param {!FileEntry} entry
  * @param {!importer.Destination} destination
  */
-importer.TestImportHistory.prototype.assertImported =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.assertImported = function(
+    entry, destination) {
   assertTrue(this.wasImported_(entry, destination));
 };
 
@@ -118,23 +115,23 @@
  * @param {!importer.Destination} destination
  * @return {boolean}
  */
-importer.TestImportHistory.prototype.wasImported_ =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.wasImported_ = function(
+    entry, destination) {
   const path = entry.fullPath;
   return path in this.importedPaths &&
       this.importedPaths[path].indexOf(destination) > -1;
 };
 
 /** @override */
-importer.TestImportHistory.prototype.wasImported =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.wasImported = function(
+    entry, destination) {
   const path = entry.fullPath;
   return Promise.resolve(this.wasImported_(entry, destination));
 };
 
 /** @override */
-importer.TestImportHistory.prototype.markImported =
-    function(entry, destination) {
+importer.TestImportHistory.prototype.markImported = function(
+    entry, destination) {
   const path = entry.fullPath;
   if (path in this.importedPaths) {
     this.importedPaths[path].push(destination);
diff --git a/ui/file_manager/file_manager/background/js/test_util.js b/ui/file_manager/file_manager/background/js/test_util.js
index 83ac94b..686418d 100644
--- a/ui/file_manager/file_manager/background/js/test_util.js
+++ b/ui/file_manager/file_manager/background/js/test_util.js
@@ -10,10 +10,11 @@
  *     App ID.
  */
 test.util.async.openMainWindow = (appState, callback) => {
-  launcher.launchFileManager(appState,
-                    undefined,  // opt_type
-                    undefined,  // opt_id
-                    callback);
+  launcher.launchFileManager(
+      appState,
+      undefined,  // opt_type
+      undefined,  // opt_id
+      callback);
 };
 
 /**
@@ -117,7 +118,7 @@
 test.util.sync.openFile = (contentWindow, filename) => {
   const query = '#file-list li.table-row[selected] .filename-label span';
   return test.util.sync.selectFile(contentWindow, filename) &&
-         test.util.sync.fakeMouseDoubleClick(contentWindow, query);
+      test.util.sync.fakeMouseDoubleClick(contentWindow, query);
 };
 
 /**
@@ -134,7 +135,6 @@
       iconName == 'drive_shared_with_me' || iconName == 'drive_offline';
   return test.util.async.selectInDirectoryTree(
       contentWindow, query, isDriveSubVolume, callback);
-
 };
 
 /**
@@ -147,40 +147,42 @@
  * @param {function(boolean)} callback Callback function to notify the caller
  *     whether the target is found and mousedown and click events are sent.
  */
-test.util.async.selectInDirectoryTree = (contentWindow, query, isDriveSubVolume, callback) => {
-  const driveQuery = '#directory-tree [volume-type-icon=drive]';
-  let preSelection = false;
-  const steps = {
-    checkQuery: function() {
-      if (contentWindow.document.querySelector(query)) {
-        steps.sendEvents();
-        return;
-      }
-      // If the target volume is sub-volume of drive, we must click 'drive'
-      // before clicking the sub-item.
-      if (!preSelection) {
-        if (!isDriveSubVolume) {
-          callback(false);
-          return;
+test.util.async.selectInDirectoryTree =
+    (contentWindow, query, isDriveSubVolume, callback) => {
+      const driveQuery = '#directory-tree [volume-type-icon=drive]';
+      let preSelection = false;
+      const steps = {
+        checkQuery: function() {
+          if (contentWindow.document.querySelector(query)) {
+            steps.sendEvents();
+            return;
+          }
+          // If the target volume is sub-volume of drive, we must click 'drive'
+          // before clicking the sub-item.
+          if (!preSelection) {
+            if (!isDriveSubVolume) {
+              callback(false);
+              return;
+            }
+            if (!(test.util.sync.fakeMouseDown(contentWindow, driveQuery) &&
+                  test.util.sync.fakeMouseClick(contentWindow, driveQuery))) {
+              callback(false);
+              return;
+            }
+            preSelection = true;
+          }
+          setTimeout(steps.checkQuery, 50);
+        },
+        sendEvents: function() {
+          // To change the selected volume, we have to send both events
+          // 'mousedown' and 'click' to the navigation list.
+          callback(
+              test.util.sync.fakeMouseDown(contentWindow, query) &&
+              test.util.sync.fakeMouseClick(contentWindow, query));
         }
-        if (!(test.util.sync.fakeMouseDown(contentWindow, driveQuery) &&
-              test.util.sync.fakeMouseClick(contentWindow, driveQuery))) {
-          callback(false);
-          return;
-        }
-        preSelection = true;
-      }
-      setTimeout(steps.checkQuery, 50);
-    },
-    sendEvents: function() {
-      // To change the selected volume, we have to send both events 'mousedown'
-      // and 'click' to the navigation list.
-      callback(test.util.sync.fakeMouseDown(contentWindow, query) &&
-               test.util.sync.fakeMouseClick(contentWindow, query));
-    }
-  };
-  steps.checkQuery();
-};
+      };
+      steps.checkQuery();
+    };
 
 /**
  * Fakes pressing the down arrow until the given |folderName| is selected in the
@@ -246,8 +248,8 @@
     return false;
   }
   test.util.sync.fakeKeyDown(
-      contentWindow, '#directory-tree .tree-item[selected]', 'ArrowLeft',
-      false, false, false);
+      contentWindow, '#directory-tree .tree-item[selected]', 'ArrowLeft', false,
+      false, false);
   return true;
 };
 
@@ -292,8 +294,8 @@
  * @return {!Array<string>} List of visible item names.
  */
 test.util.sync.getTreeItems = contentWindow => {
-  const items = contentWindow.document.querySelectorAll(
-      '#directory-tree .tree-item');
+  const items =
+      contentWindow.document.querySelectorAll('#directory-tree .tree-item');
   const result = [];
   for (let i = 0; i < items.length; i++) {
     if (items[i].matches('.tree-children:not([expanded]) *')) {
@@ -323,10 +325,11 @@
  * @param {function(*)} callback Callback function with results returned by the
  *     script.
  */
-test.util.async.executeScriptInWebView = (contentWindow, webViewQuery, code, callback) => {
-  const webView = contentWindow.document.querySelector(webViewQuery);
-  webView.executeScript({code: code}, callback);
-};
+test.util.async.executeScriptInWebView =
+    (contentWindow, webViewQuery, code, callback) => {
+      const webView = contentWindow.document.querySelector(webViewQuery);
+      webView.executeScript({code: code}, callback);
+    };
 
 /**
  * Selects |filename| and fakes pressing Ctrl+C, Ctrl+V (copy, paste).
@@ -388,29 +391,29 @@
  */
 test.util.sync.overrideInstallWebstoreItemApi =
     (contentWindow, expectedItemId, intendedError) => {
-  const setLastError = message => {
-    contentWindow.chrome.runtime.lastError =
-        message ? {message: message} : undefined;
-  };
+      const setLastError = message => {
+        contentWindow.chrome.runtime.lastError =
+            message ? {message: message} : undefined;
+      };
 
-  const installWebstoreItem = (itemId, silentInstallation, callback) => {
-    setTimeout(() => {
-      if (itemId !== expectedItemId) {
-        setLastError('Invalid Chrome Web Store item ID');
-        callback();
-        return;
-      }
+      const installWebstoreItem = (itemId, silentInstallation, callback) => {
+        setTimeout(() => {
+          if (itemId !== expectedItemId) {
+            setLastError('Invalid Chrome Web Store item ID');
+            callback();
+            return;
+          }
 
-      setLastError(intendedError);
-      callback();
-    }, 0);
-  };
+          setLastError(intendedError);
+          callback();
+        }, 0);
+      };
 
-  test.util.executedTasks_ = [];
-  contentWindow.chrome.webstoreWidgetPrivate.installWebstoreItem =
-      installWebstoreItem;
-  return true;
-};
+      test.util.executedTasks_ = [];
+      contentWindow.chrome.webstoreWidgetPrivate.installWebstoreItem =
+          installWebstoreItem;
+      return true;
+    };
 
 /**
  * Override the task-related methods in private api for test.
@@ -493,12 +496,12 @@
  * @return {string} Path which is shown in the breadcrumb.
  */
 test.util.sync.getBreadcrumbPath = contentWindow => {
-  const breadcrumb = contentWindow.document.querySelector(
-      '#location-breadcrumbs');
+  const breadcrumb =
+      contentWindow.document.querySelector('#location-breadcrumbs');
   const paths = breadcrumb.querySelectorAll('.breadcrumb-path');
 
   let path = '';
-  for(let i = 0; i < paths.length; i++) {
+  for (let i = 0; i < paths.length; i++) {
     path += '/' + paths[i].textContent;
   }
   return path;
diff --git a/ui/file_manager/file_manager/background/js/test_util_base.js b/ui/file_manager/file_manager/background/js/test_util_base.js
index a6b0777f..3e1c4c4 100644
--- a/ui/file_manager/file_manager/background/js/test_util_base.js
+++ b/ui/file_manager/file_manager/background/js/test_util_base.js
@@ -44,67 +44,69 @@
 
   // Return true for asynchronous functions, which keeps the connection to the
   // caller alive; Return false for synchronous functions.
-  chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {
-    /**
-     * List of extension ID of the testing extension.
-     * @type {Array<string>}
-     * @const
-     */
-    const kTestingExtensionIds = [
-      'oobinhbdbiehknkpbpejbbpdbkdjmoco',  // File Manager test extension.
-      'ejhcmmdhhpdhhgmifplfmjobgegbibkn',  // Gallery test extension.
-      'ljoplibgfehghmibaoaepfagnmbbfiga',  // Video Player test extension.
-      'ddabbgbggambiildohfagdkliahiecfl',  // Audio Player test extension.
-    ];
+  chrome.runtime.onMessageExternal.addListener(
+      (request, sender, sendResponse) => {
+        /**
+         * List of extension ID of the testing extension.
+         * @type {Array<string>}
+         * @const
+         */
+        const kTestingExtensionIds = [
+          'oobinhbdbiehknkpbpejbbpdbkdjmoco',  // File Manager test extension.
+          'ejhcmmdhhpdhhgmifplfmjobgegbibkn',  // Gallery test extension.
+          'ljoplibgfehghmibaoaepfagnmbbfiga',  // Video Player test extension.
+          'ddabbgbggambiildohfagdkliahiecfl',  // Audio Player test extension.
+        ];
 
-    // Check the sender.
-    if (!sender.id || kTestingExtensionIds.indexOf(sender.id) === -1) {
-      // Silently return.  Don't return false; that short-circuits the
-      // propagation of messages, and there are now other listeners that want to
-      // handle external messages.
-      return;
-    }
+        // Check the sender.
+        if (!sender.id || kTestingExtensionIds.indexOf(sender.id) === -1) {
+          // Silently return.  Don't return false; that short-circuits the
+          // propagation of messages, and there are now other listeners that
+          // want to handle external messages.
+          return;
+        }
 
-    // Set the global IN_TEST flag, so other components are aware of it.
-    window.IN_TEST = true;
+        // Set the global IN_TEST flag, so other components are aware of it.
+        window.IN_TEST = true;
 
-    // If testing functions are loaded just run the requested function.
-    if (test.util.executeTestMessage !== null) {
-      return test.util.executeTestMessage(request, sendResponse);
-    }
+        // If testing functions are loaded just run the requested function.
+        if (test.util.executeTestMessage !== null) {
+          return test.util.executeTestMessage(request, sendResponse);
+        }
 
-    // Queue the request/response pair.
-    const obj = {request, sendResponse};
-    responsesWaitingForLoad.push(obj);
+        // Queue the request/response pair.
+        const obj = {request, sendResponse};
+        responsesWaitingForLoad.push(obj);
 
-    // Only load the script with testing functions in the first request.
-    if (responsesWaitingForLoad.length > 1) {
-      return true;
-    }
+        // Only load the script with testing functions in the first request.
+        if (responsesWaitingForLoad.length > 1) {
+          return true;
+        }
 
-    // Asynchronously load the testing functions.
-    let script = document.createElement('script');
-    document.body.appendChild(script);
+        // Asynchronously load the testing functions.
+        let script = document.createElement('script');
+        document.body.appendChild(script);
 
-    script.onload = () => {
-      // Run queued request/response pairs.
-      responsesWaitingForLoad.forEach((queueObj) => {
-        test.util.executeTestMessage(queueObj.request, queueObj.sendResponse);
+        script.onload = () => {
+          // Run queued request/response pairs.
+          responsesWaitingForLoad.forEach((queueObj) => {
+            test.util.executeTestMessage(
+                queueObj.request, queueObj.sendResponse);
+          });
+          responsesWaitingForLoad = [];
+        };
+
+        script.onerror = /** Event */ event => {
+          console.error('Failed to load the run-time test script: ' + event);
+          throw new Error('Failed to load the run-time test script: ' + event);
+        };
+
+        const kFileManagerExtension =
+            'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj';
+        const kTestScriptUrl = kFileManagerExtension +
+            '/background/js/runtime_loaded_test_util.js';
+        console.log('Loading ' + kTestScriptUrl);
+        script.src = kTestScriptUrl;
+        return true;
       });
-      responsesWaitingForLoad = [];
-    };
-
-    script.onerror = /** Event */ event => {
-      console.error('Failed to load the run-time test script: ' + event);
-      throw new Error('Failed to load the run-time test script: ' + event);
-    };
-
-    const kFileManagerExtension =
-        'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj';
-    const kTestScriptUrl =
-        kFileManagerExtension + '/background/js/runtime_loaded_test_util.js';
-    console.log('Loading ' + kTestScriptUrl);
-    script.src = kTestScriptUrl;
-    return true;
-  });
 };
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
index 1f9a610..c8c8856 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -77,48 +77,50 @@
  * @private
  */
 VolumeManagerImpl.prototype.addVolumeMetadata_ = function(volumeMetadata) {
-  return volumeManagerUtil.createVolumeInfo(volumeMetadata).then(
-      /**
-      * @param {!VolumeInfo} volumeInfo
-      * @return {!VolumeInfo}
-      */
-      volumeInfo => {
-        // We don't show Downloads and Drive on volume list if they have mount
-        // error, since users can do nothing in this situation.
-        // We show Removable and Provided volumes regardless of mount error so
-        // that users can unmount or format the volume.
-        // TODO(fukino): Once the Files app gets ready, show erroneous Drive
-        // volume so that users can see auth warning banner on the volume.
-        // crbug.com/517772.
-        let shouldShow = true;
-        switch (volumeInfo.volumeType) {
-          case VolumeManagerCommon.VolumeType.DOWNLOADS:
-          case VolumeManagerCommon.VolumeType.DRIVE:
-            shouldShow = !!volumeInfo.fileSystem;
-            break;
-        }
-        if (!shouldShow) {
-          return volumeInfo;
-        }
-        if (this.volumeInfoList.findIndex(volumeInfo.volumeId) === -1) {
-          this.volumeInfoList.add(volumeInfo);
+  return volumeManagerUtil.createVolumeInfo(volumeMetadata)
+      .then(
+          /**
+           * @param {!VolumeInfo} volumeInfo
+           * @return {!VolumeInfo}
+           */
+          volumeInfo => {
+            // We don't show Downloads and Drive on volume list if they have
+            // mount error, since users can do nothing in this situation. We
+            // show Removable and Provided volumes regardless of mount error so
+            // that users can unmount or format the volume.
+            // TODO(fukino): Once the Files app gets ready, show erroneous Drive
+            // volume so that users can see auth warning banner on the volume.
+            // crbug.com/517772.
+            let shouldShow = true;
+            switch (volumeInfo.volumeType) {
+              case VolumeManagerCommon.VolumeType.DOWNLOADS:
+              case VolumeManagerCommon.VolumeType.DRIVE:
+                shouldShow = !!volumeInfo.fileSystem;
+                break;
+            }
+            if (!shouldShow) {
+              return volumeInfo;
+            }
+            if (this.volumeInfoList.findIndex(volumeInfo.volumeId) === -1) {
+              this.volumeInfoList.add(volumeInfo);
 
-          // Update the network connection status, because until the drive is
-          // initialized, the status is set to not ready.
-          // TODO(mtomasz): The connection status should be migrated into
-          // chrome.fileManagerPrivate.VolumeMetadata.
-          if (volumeMetadata.volumeType ===
-              VolumeManagerCommon.VolumeType.DRIVE) {
-            this.onDriveConnectionStatusChanged_();
-          }
-        } else if (volumeMetadata.volumeType ===
-            VolumeManagerCommon.VolumeType.REMOVABLE) {
-          // Update for remounted USB external storage, because they were
-          // remounted to switch read-only policy.
-          this.volumeInfoList.add(volumeInfo);
-        }
-        return volumeInfo;
-      });
+              // Update the network connection status, because until the drive
+              // is initialized, the status is set to not ready.
+              // TODO(mtomasz): The connection status should be migrated into
+              // chrome.fileManagerPrivate.VolumeMetadata.
+              if (volumeMetadata.volumeType ===
+                  VolumeManagerCommon.VolumeType.DRIVE) {
+                this.onDriveConnectionStatusChanged_();
+              }
+            } else if (
+                volumeMetadata.volumeType ===
+                VolumeManagerCommon.VolumeType.REMOVABLE) {
+              // Update for remounted USB external storage, because they were
+              // remounted to switch read-only policy.
+              this.volumeInfoList.add(volumeInfo);
+            }
+            return volumeInfo;
+          });
 };
 
 /**
@@ -140,14 +142,12 @@
     // volumes in the volumeMetadataList are mounted. crbug.com/135477.
     this.mountQueue_.run(inCallback => {
       // Create VolumeInfo for each volume.
-      Promise.all(
-          volumeMetadataList.map(volumeMetadata => {
-            console.warn(
-                'Initializing volume: ' + volumeMetadata.volumeId);
-            return this.addVolumeMetadata_(volumeMetadata).then(
-                volumeInfo => {
-                  console.warn('Initialized volume: ' + volumeInfo.volumeId);
-                });
+      Promise
+          .all(volumeMetadataList.map(volumeMetadata => {
+            console.warn('Initializing volume: ' + volumeMetadata.volumeId);
+            return this.addVolumeMetadata_(volumeMetadata).then(volumeInfo => {
+              console.warn('Initialized volume: ' + volumeInfo.volumeId);
+            });
           }))
           .then(() => {
             console.warn('Initialized all volumes.');
@@ -171,21 +171,19 @@
     switch (event.eventType) {
       case 'mount':
         var requestKey = this.makeRequestKey_(
-            'mount',
-            event.volumeMetadata.sourcePath || '');
+            'mount', event.volumeMetadata.sourcePath || '');
 
         if (event.status === 'success' ||
             event.status ===
                 VolumeManagerCommon.VolumeError.UNKNOWN_FILESYSTEM ||
             event.status ===
                 VolumeManagerCommon.VolumeError.UNSUPPORTED_FILESYSTEM) {
-          this.addVolumeMetadata_(event.volumeMetadata).then(
-              volumeInfo => {
-                this.finishRequest_(requestKey, event.status, volumeInfo);
-                callback();
-              });
-        } else if (event.status ===
-            VolumeManagerCommon.VolumeError.ALREADY_MOUNTED) {
+          this.addVolumeMetadata_(event.volumeMetadata).then(volumeInfo => {
+            this.finishRequest_(requestKey, event.status, volumeInfo);
+            callback();
+          });
+        } else if (
+            event.status === VolumeManagerCommon.VolumeError.ALREADY_MOUNTED) {
           const navigationEvent =
               new Event(VolumeManagerCommon.VOLUME_ALREADY_MOUNTED);
           navigationEvent.volumeId = event.volumeMetadata.volumeId;
@@ -204,10 +202,10 @@
         const status = event.status;
         var requestKey = this.makeRequestKey_('unmount', volumeId);
         const requested = requestKey in this.requests_;
-        const volumeInfoIndex =
-            this.volumeInfoList.findIndex(volumeId);
+        const volumeInfoIndex = this.volumeInfoList.findIndex(volumeId);
         const volumeInfo = volumeInfoIndex !== -1 ?
-            this.volumeInfoList.item(volumeInfoIndex) : null;
+            this.volumeInfoList.item(volumeInfoIndex) :
+            null;
         if (event.status === 'success' && !requested && volumeInfo) {
           console.warn('Unmounted volume without a request: ' + volumeId);
           const e = new Event('externally-unmounted');
@@ -251,9 +249,8 @@
 };
 
 /** @override */
-VolumeManagerImpl.prototype.unmount = function(volumeInfo,
-                                           successCallback,
-                                           errorCallback) {
+VolumeManagerImpl.prototype.unmount = function(
+    volumeInfo, successCallback, errorCallback) {
   chrome.fileManagerPrivate.removeMount(volumeInfo.volumeId);
   const requestKey = this.makeRequestKey_('unmount', volumeInfo.volumeId);
   this.startRequest_(requestKey, successCallback, errorCallback);
@@ -313,7 +310,7 @@
     console.error('Invalid entry passed to getLocationInfo: ' + entry);
     return null;
   }
-   const volumeInfo = this.getVolumeInfo(entry);
+  const volumeInfo = this.getVolumeInfo(entry);
 
   if (util.isFakeEntry(entry)) {
     return new EntryLocationImpl(
@@ -452,8 +449,8 @@
  *     when the request fails.
  * @private
  */
-VolumeManagerImpl.prototype.startRequest_ = function(key,
-    successCallback, errorCallback) {
+VolumeManagerImpl.prototype.startRequest_ = function(
+    key, successCallback, errorCallback) {
   if (key in this.requests_) {
     const request = this.requests_[key];
     request.successCallbacks.push(successCallback);
@@ -463,8 +460,8 @@
       successCallbacks: [successCallback],
       errorCallbacks: [errorCallback],
 
-      timeout: setTimeout(this.onTimeout_.bind(this, key),
-                          volumeManagerUtil.TIMEOUT)
+      timeout:
+          setTimeout(this.onTimeout_.bind(this, key), volumeManagerUtil.TIMEOUT)
     };
   }
 };
@@ -475,8 +472,8 @@
  * @private
  */
 VolumeManagerImpl.prototype.onTimeout_ = function(key) {
-  this.invokeRequestCallbacks_(this.requests_[key],
-                               VolumeManagerCommon.VolumeError.TIMEOUT);
+  this.invokeRequestCallbacks_(
+      this.requests_[key], VolumeManagerCommon.VolumeError.TIMEOUT);
   delete this.requests_[key];
 };
 
@@ -487,8 +484,8 @@
  * @param {VolumeInfo=} opt_volumeInfo Volume info of the mounted volume.
  * @private
  */
-VolumeManagerImpl.prototype.finishRequest_ =
-    function(key, status, opt_volumeInfo) {
+VolumeManagerImpl.prototype.finishRequest_ = function(
+    key, status, opt_volumeInfo) {
   const request = this.requests_[key];
   if (!request) {
     return;
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
index 068396c5..d388f17 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
@@ -32,9 +32,7 @@
         const event = {
           eventType: 'unmount',
           status: 'success',
-          volumeMetadata: {
-            volumeId: volumeId
-          }
+          volumeMetadata: {volumeId: volumeId}
         };
         mockChrome.fileManagerPrivate.onMountCompleted.dispatchEvent(event);
       },
@@ -144,13 +142,13 @@
 function testGetVolumeInfo(callback) {
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
-        const entry = new MockFileEntry(new MockFileSystem('download:Downloads'),
-            '/foo/bar/bla.zip');
+        const entry = new MockFileEntry(
+            new MockFileSystem('download:Downloads'), '/foo/bar/bla.zip');
 
         const volumeInfo = volumeManager.getVolumeInfo(entry);
         assertEquals('download:Downloads', volumeInfo.volumeId);
-        assertEquals(VolumeManagerCommon.VolumeType.DOWNLOADS,
-            volumeInfo.volumeType);
+        assertEquals(
+            VolumeManagerCommon.VolumeType.DOWNLOADS, volumeInfo.volumeType);
       }),
       callback);
 }
@@ -159,19 +157,22 @@
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
         // Default connection state is online
-        assertEquals(VolumeManagerCommon.DriveConnectionType.ONLINE,
+        assertEquals(
+            VolumeManagerCommon.DriveConnectionType.ONLINE,
             volumeManager.getDriveConnectionState());
 
         // Sets it to offline.
         chrome.fileManagerPrivate.driveConnectionState =
             VolumeManagerCommon.DriveConnectionType.OFFLINE;
-        assertEquals(VolumeManagerCommon.DriveConnectionType.OFFLINE,
+        assertEquals(
+            VolumeManagerCommon.DriveConnectionType.OFFLINE,
             volumeManager.getDriveConnectionState());
 
         // Sets it back to online
         chrome.fileManagerPrivate.driveConnectionState =
             VolumeManagerCommon.DriveConnectionType.ONLINE;
-        assertEquals(VolumeManagerCommon.DriveConnectionType.ONLINE,
+        assertEquals(
+            VolumeManagerCommon.DriveConnectionType.ONLINE,
             volumeManager.getDriveConnectionState());
       }),
       callback);
@@ -189,45 +190,45 @@
         const numberOfVolumes = volumeManager.volumeInfoList.length;
 
         return new Promise((resolve, reject) => {
-          // Mount an archieve
-          volumeManager.mountArchive(
-              'filesystem:chrome-extension://extensionid/external/' +
-              'Downloads-test/foobar.zip',
-              resolve, reject);
+                 // Mount an archieve
+                 volumeManager.mountArchive(
+                     'filesystem:chrome-extension://extensionid/external/' +
+                         'Downloads-test/foobar.zip',
+                     resolve, reject);
 
-          mockChrome.fileManagerPrivate.onMountCompleted.dispatchEvent({
-            eventType: 'mount',
-            status: 'success',
-            volumeMetadata: {
-              volumeId: 'archive:foobar.zip',
-              volumeLabel: 'foobar.zip',
-              volumeType: VolumeManagerCommon.VolumeType.ARCHIVE,
-              isReadOnly: true,
-              sourcePath: mountSourcePath,
-              profile: getMockProfile(),
-              configurable: false,
-              watchable: true,
-              source: VolumeManagerCommon.Source.FILE
-            }
-          });
-        }).then(result => {
-          assertEquals(numberOfVolumes + 1,
-                       volumeManager.volumeInfoList.length);
+                 mockChrome.fileManagerPrivate.onMountCompleted.dispatchEvent({
+                   eventType: 'mount',
+                   status: 'success',
+                   volumeMetadata: {
+                     volumeId: 'archive:foobar.zip',
+                     volumeLabel: 'foobar.zip',
+                     volumeType: VolumeManagerCommon.VolumeType.ARCHIVE,
+                     isReadOnly: true,
+                     sourcePath: mountSourcePath,
+                     profile: getMockProfile(),
+                     configurable: false,
+                     watchable: true,
+                     source: VolumeManagerCommon.Source.FILE
+                   }
+                 });
+               })
+            .then(result => {
+              assertEquals(
+                  numberOfVolumes + 1, volumeManager.volumeInfoList.length);
 
-          return new Promise((resolve, reject) => {
-            // Unmount the mounted archievea
-            volumeManager.volumeInfoList.addEventListener('splice', () => {
-              assertEquals(numberOfVolumes,
-                  volumeManager.volumeInfoList.length);
-              resolve(true);
+              return new Promise((resolve, reject) => {
+                // Unmount the mounted archievea
+                volumeManager.volumeInfoList.addEventListener('splice', () => {
+                  assertEquals(
+                      numberOfVolumes, volumeManager.volumeInfoList.length);
+                  resolve(true);
+                });
+                const entry = new MockFileEntry(
+                    new MockFileSystem('archive:foobar.zip'), '/foo.txt');
+                const volumeInfo = volumeManager.getVolumeInfo(entry);
+                volumeManager.unmount(volumeInfo);
+              });
             });
-            const entry = new MockFileEntry(
-                new MockFileSystem('archive:foobar.zip'),
-                '/foo.txt');
-            const volumeInfo = volumeManager.getVolumeInfo(entry);
-            volumeManager.unmount(volumeInfo);
-          });
-        });
       }),
       callback);
 }
@@ -238,10 +239,10 @@
         const volumeInfo = volumeManager.getCurrentProfileVolumeInfo(
             VolumeManagerCommon.VolumeType.DRIVE);
 
-        assertEquals('drive:drive-foobar%40chromium.org-hash',
-            volumeInfo.volumeId);
-        assertEquals(VolumeManagerCommon.VolumeType.DRIVE,
-            volumeInfo.volumeType);
+        assertEquals(
+            'drive:drive-foobar%40chromium.org-hash', volumeInfo.volumeId);
+        assertEquals(
+            VolumeManagerCommon.VolumeType.DRIVE, volumeInfo.volumeType);
       }),
       callback);
 }
@@ -250,10 +251,11 @@
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
         const downloadEntry = new MockFileEntry(
-            new MockFileSystem('download:Downloads'),
-            '/foo/bar/bla.zip');
-        const downloadLocationInfo = volumeManager.getLocationInfo(downloadEntry);
-        assertEquals(VolumeManagerCommon.RootType.DOWNLOADS,
+            new MockFileSystem('download:Downloads'), '/foo/bar/bla.zip');
+        const downloadLocationInfo =
+            volumeManager.getLocationInfo(downloadEntry);
+        assertEquals(
+            VolumeManagerCommon.RootType.DOWNLOADS,
             downloadLocationInfo.rootType);
         assertFalse(downloadLocationInfo.hasFixedLabel);
         assertFalse(downloadLocationInfo.isReadOnly);
@@ -263,8 +265,8 @@
             new MockFileSystem('drive:drive-foobar%40chromium.org-hash'),
             '/root');
         const driveLocationInfo = volumeManager.getLocationInfo(driveEntry);
-        assertEquals(VolumeManagerCommon.RootType.DRIVE,
-            driveLocationInfo.rootType);
+        assertEquals(
+            VolumeManagerCommon.RootType.DRIVE, driveLocationInfo.rootType);
         assertTrue(driveLocationInfo.hasFixedLabel);
         assertFalse(driveLocationInfo.isReadOnly);
         assertTrue(driveLocationInfo.isRootEntry);
@@ -413,8 +415,10 @@
   // Complete initialization.
   sendMetadataListCallback([]);
 
-  reportPromise(instancePromise.then(volumeManager => {
-    assertTrue(!!volumeManager.getCurrentProfileVolumeInfo(
-        VolumeManagerCommon.VolumeType.DRIVE));
-  }), callback);
+  reportPromise(
+      instancePromise.then(volumeManager => {
+        assertTrue(!!volumeManager.getCurrentProfileVolumeInfo(
+            VolumeManagerCommon.VolumeType.DRIVE));
+      }),
+      callback);
 }
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js
index 9f317f9c..7b988bf 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_util.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -154,8 +154,7 @@
               // it fails, accessing to some path later will just become
               // a fast-fetch and it re-triggers full-feed fetch.
               fileSystem.root.createReader().readEntries(
-                  () => { /* do nothing */ },
-                  error => {
+                  () => {/* do nothing */}, error => {
                     console.warn(
                         'Triggering full feed fetch has failed: ' + error.name);
                   });
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 2e2780c..892e1dd 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -6,7 +6,7 @@
   -->
 <html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
-    <title></title>
+    <title>$i18n{FILEMANAGER_APP_NAME}</title>
 
     <meta name="google" value="notranslate">
     <script src="chrome://resources/polymer/v1_0/html-imports/html-imports.min.js"></script>
@@ -30,7 +30,7 @@
     <script src="foreground/js/main_scripts.js" defer></script>
   </head>
 
-  <body tabindex="-1">
+  <body aria-label="$i18n{FILEMANAGER_APP_NAME}" tabindex="-1">
     <custom-style>
       <style is="custom-style">
         #search-box cr-input {
@@ -336,7 +336,7 @@
              menu-item-selector="cr-menu-item">
     </cr-menu>
 
-    <div class="dialog-header">
+    <div class="dialog-header" role="contentinfo">
       <div id="location-breadcrumbs" class="breadcrumbs"></div>
       <div id="cancel-selection-button-wrapper">
         <paper-button id="cancel-selection-button" class="menu-button" tabindex="8"
@@ -502,7 +502,7 @@
                 <div class="drive-text" id="drive-auth-failed-warning-text"></div>
               </div>
               <div class="downloads-warning" hidden></div>
-              <div id="list-container">
+              <div id="list-container" role="main">
                 <div id="more-actions-info" hidden>$i18n{SEE_MENU_FOR_ACTIONS}</div>
                 <div id="empty-folder" hidden>
                   <div class="image"></div>
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
index f21a1ac1..bc5556b8 100644
--- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -1051,4 +1051,59 @@
       appId, '/DocumentsProvider/photos', folderMenus, false /* rootMenu */);
 };
 
+/**
+ * Tests context menu for Audio, Images and Videos roots, currently they don't
+ * show context menu.
+ */
+testcase.dirContextMenuMediaView = async () => {
+  const audioViewQuery = '#directory-tree [entry-label="Audio"]';
+  const imagesViewQuery = '#directory-tree [entry-label="Images"]';
+  const videosViewQuery = '#directory-tree [entry-label="Videos"]';
+
+  await sendTestMessage({name: 'mountMediaView'});
+
+  // Open Files app on local Downloads.
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.beautiful], []);
+
+  // Right click Audio root.
+  await remoteCall.waitAndClickElement(appId, audioViewQuery);
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Audio');
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil(
+          'fakeMouseRightClick', appId, [audioViewQuery]),
+      'fakeMouseRightClick failed');
+
+  // Check that both menus are still hidden.
+  await remoteCall.waitForElement(appId, '#roots-context-menu[hidden]');
+  await remoteCall.waitForElement(
+      appId, '#directory-tree-context-menu[hidden]');
+
+  // Right click Images root.
+  await remoteCall.waitAndClickElement(appId, imagesViewQuery);
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Images');
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil(
+          'fakeMouseRightClick', appId, [imagesViewQuery]),
+      'fakeMouseRightClick failed');
+
+  // Check that both menus are still hidden.
+  await remoteCall.waitForElement(appId, '#roots-context-menu[hidden]');
+  await remoteCall.waitForElement(
+      appId, '#directory-tree-context-menu[hidden]');
+
+  // Right click Videos root.
+  await remoteCall.waitAndClickElement(appId, videosViewQuery);
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Videos');
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil(
+          'fakeMouseRightClick', appId, [videosViewQuery]),
+      'fakeMouseRightClick failed');
+
+  // Check that both menus are still hidden.
+  await remoteCall.waitForElement(appId, '#roots-context-menu[hidden]');
+  await remoteCall.waitForElement(
+      appId, '#directory-tree-context-menu[hidden]');
+};
+
 })();
diff --git a/ui/gfx/rrect_f.cc b/ui/gfx/rrect_f.cc
index d8bb08e..7d3a625 100644
--- a/ui/gfx/rrect_f.cc
+++ b/ui/gfx/rrect_f.cc
@@ -12,6 +12,24 @@
 
 namespace gfx {
 
+// Sets all x radii to x_rad, and all y radii to y_rad. If one of x_rad or
+// y_rad are zero, sets ALL radii to zero.
+RRectF::RRectF(float x,
+               float y,
+               float width,
+               float height,
+               float x_rad,
+               float y_rad)
+    : skrrect_(SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, width, height),
+                                   x_rad,
+                                   y_rad)) {
+  if (IsEmpty()) {
+    // Make sure that empty rects are created fully empty, not with some
+    // non-zero dimensions.
+    skrrect_ = SkRRect::MakeEmpty();
+  }
+}
+
 // Directly sets all four corners.
 RRectF::RRectF(float x,
                float y,
@@ -91,6 +109,15 @@
 }
 
 void RRectF::Scale(float x_scale, float y_scale) {
+  if (IsEmpty()) {
+    // SkRRect doesn't support scaling of empty rects.
+    return;
+  }
+  if (!x_scale || !y_scale) {
+    // SkRRect doesn't support scaling TO an empty rect.
+    skrrect_ = SkRRect::MakeEmpty();
+    return;
+  }
   SkMatrix scale = SkMatrix::MakeScale(x_scale, y_scale);
   SkRRect result;
   bool success = skrrect_.transform(scale, &result);
diff --git a/ui/gfx/rrect_f.h b/ui/gfx/rrect_f.h
index 0acb013..cbf042a 100644
--- a/ui/gfx/rrect_f.h
+++ b/ui/gfx/rrect_f.h
@@ -30,10 +30,7 @@
       : RRectF(x, y, width, height, radius, radius) {}
   // Sets all x radii to x_rad, and all y radii to y_rad. If one of x_rad or
   // y_rad are zero, sets ALL radii to zero.
-  RRectF(float x, float y, float width, float height, float x_rad, float y_rad)
-      : skrrect_(SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, width, height),
-                                     x_rad,
-                                     y_rad)) {}
+  RRectF(float x, float y, float width, float height, float x_rad, float y_rad);
   // Directly sets all four corners.
   RRectF(float x,
          float y,
diff --git a/ui/gfx/rrect_f_unittest.cc b/ui/gfx/rrect_f_unittest.cc
index 20d62a1..62a17c85 100644
--- a/ui/gfx/rrect_f_unittest.cc
+++ b/ui/gfx/rrect_f_unittest.cc
@@ -18,18 +18,20 @@
 }
 
 TEST(RRectFTest, Equals) {
-  ASSERT_TRUE(RRectF(0, 0, 0, 0, 0, 0) == RRectF(0, 0, 0, 0, 0, 0));
-  ASSERT_TRUE(RRectF(1, 2, 3, 4, 5, 6) == RRectF(1, 2, 3, 4, 5, 6));
-  ASSERT_TRUE(RRectF(1, 2, 3, 4, 5, 5) == RRectF(1, 2, 3, 4, 5));
-  ASSERT_TRUE(RRectF(0, 0, 2, 3, 0, 0) == RRectF(0, 0, 2, 3, 0, 1));
-  ASSERT_TRUE(RRectF(0, 0, 2, 3, 0, 0) == RRectF(0, 0, 2, 3, 1, 0));
+  EXPECT_EQ(RRectF(0, 0, 0, 0, 0, 0), RRectF(0, 0, 0, 0, 0, 0));
+  EXPECT_EQ(RRectF(1, 2, 3, 4, 5, 6), RRectF(1, 2, 3, 4, 5, 6));
+  EXPECT_EQ(RRectF(1, 2, 3, 4, 5, 5), RRectF(1, 2, 3, 4, 5));
+  EXPECT_EQ(RRectF(0, 0, 2, 3, 0, 0), RRectF(0, 0, 2, 3, 0, 1));
+  EXPECT_EQ(RRectF(0, 0, 2, 3, 0, 0), RRectF(0, 0, 2, 3, 1, 0));
+  EXPECT_EQ(RRectF(1, 2, 3, 0, 5, 6), RRectF(0, 0, 0, 0, 0, 0));
+  EXPECT_EQ(RRectF(0, 0, 0, 0, 5, 6), RRectF(0, 0, 0, 0, 0, 0));
 
-  ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(1, 20, 30, 40, 7, 8));
-  ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 2, 30, 40, 7, 8));
-  ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 3, 40, 7, 8));
-  ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 30, 4, 7, 8));
-  ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 30, 40, 5, 8));
-  ASSERT_TRUE(RRectF(10, 20, 30, 40, 7, 8) != RRectF(10, 20, 30, 40, 7, 6));
+  EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(1, 20, 30, 40, 7, 8));
+  EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 2, 30, 40, 7, 8));
+  EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 3, 40, 7, 8));
+  EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 30, 4, 7, 8));
+  EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 30, 40, 5, 8));
+  EXPECT_NE(RRectF(10, 20, 30, 40, 7, 8), RRectF(10, 20, 30, 40, 7, 6));
 }
 
 TEST(RRectFTest, PlusMinusOffset) {
@@ -187,38 +189,55 @@
 
 TEST(RRectFTest, Scale) {
   // Note that SKRRect (the backing for RRectF) does not support scaling by NaN,
-  // scaling out of numerical bounds, or scaling to zero. So this test doesn't
-  // exercise those.
+  // or scaling out of numerical bounds. So this test doesn't exercise those.
   static const struct Test {
     float x1;  // source
     float y1;
     float w1;
     float h1;
-    float r1;
+    float x_rad1;
+    float y_rad1;
 
-    float scale;
+    float x_scale;
+    float y_scale;
     float x2;  // target
     float y2;
     float w2;
     float h2;
-    float r2;
+    float x_rad2;
+    float y_rad2;
   } tests[] = {
-      {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f, 1.5f},
-      {3.0f, 4.0f, 5.0f, 6.0f, 0.0f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f, 0.0f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 0.0f, 0.0f, 1.5f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f,
+       0.0f, 0.0f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.5f, 1.5f, 4.5f, 6.0f, 7.5f, 9.0f,
+       1.5f, 1.5f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 0.0f, 0.0f, 1.5f, 3.0f, 4.5f, 12.0f, 7.5f, 18.0f,
+       0.0f, 0.0f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.5f, 3.0f, 4.5f, 12.0f, 7.5f, 18.0f,
+       1.5f, 3.0f},
+      {3.0f, 4.0f, 0.0f, 6.0f, 1.0f, 1.0f, 1.5f, 1.5f, 0.0f, 0.0f, 0.0f, 0.0f,
+       0.0f, 0.0f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+       0.0f, 0.0f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+       0.0f, 0.0f},
+      {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+       0.0f, 0.0f},
   };
 
   for (size_t i = 0; i < base::size(tests); ++i) {
-    RRectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1, tests[i].r1);
-    RRectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2, tests[i].r2);
+    RRectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1,
+              tests[i].x_rad1, tests[i].y_rad1);
+    RRectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2,
+              tests[i].x_rad2, tests[i].y_rad2);
 
-    r1.Scale(tests[i].scale);
-    EXPECT_TRUE((r1.GetType() == RRectF::Type::kRect) ||
-                (r1.GetType() == RRectF::Type::kSingle));
+    r1.Scale(tests[i].x_scale, tests[i].y_scale);
+    ASSERT_TRUE(r1.GetType() <= RRectF::Type::kSimple);
     EXPECT_EQ(r1.rect().x(), r2.rect().x());
     EXPECT_EQ(r1.rect().y(), r2.rect().y());
     EXPECT_EQ(r1.rect().width(), r2.rect().width());
     EXPECT_EQ(r1.rect().height(), r2.rect().height());
-    EXPECT_EQ(r1.GetSimpleRadius(), r2.GetSimpleRadius());
+    EXPECT_EQ(r1.GetSimpleRadii(), r2.GetSimpleRadii());
   }
 }
 
diff --git a/ui/ozone/demo/BUILD.gn b/ui/ozone/demo/BUILD.gn
index dc215da..e76ca1f 100644
--- a/ui/ozone/demo/BUILD.gn
+++ b/ui/ozone/demo/BUILD.gn
@@ -60,6 +60,7 @@
     ":ozone_demo_lib",
     "//components/tracing:startup_tracing",
     "//gpu/vulkan:buildflags",
+    "//mojo/core/embedder",
     "//ui/events/ozone:events_ozone_layout",
     "//ui/gl",
     "//ui/gl/init",
@@ -91,6 +92,7 @@
   deps = [
     ":ozone_demo_lib",
     "//components/tracing:startup_tracing",
+    "//mojo/core/embedder",
     "//skia",
     "//ui/events/ozone:events_ozone_layout",
     "//ui/gl",
diff --git a/ui/ozone/demo/DEPS b/ui/ozone/demo/DEPS
index 2dbcda8..23b30425 100644
--- a/ui/ozone/demo/DEPS
+++ b/ui/ozone/demo/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+components/tracing",
+  "+mojo/core/embedder",
   "+ui/gl",
 ]
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
index 11379e5..c27f416 100644
--- a/ui/ozone/demo/ozone_demo.cc
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -14,10 +14,12 @@
 #include "build/build_config.h"
 #include "components/tracing/common/trace_to_console.h"
 #include "components/tracing/common/tracing_switches.h"
+#include "mojo/core/embedder/embedder.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/ozone/demo/simple_renderer_factory.h"
 #include "ui/ozone/demo/window_manager.h"
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
 #include "ui/ozone/public/ozone_platform.h"
 
 const char kHelp[] = "help";
@@ -65,17 +67,32 @@
         trace_config, base::trace_event::TraceLog::RECORDING_MODE);
   }
 
-  // Build UI thread message loop. This is used by platform
-  // implementations for event polling & running background tasks.
+  mojo::core::Init();
+
   base::MessageLoopForUI message_loop;
   base::TaskScheduler::CreateAndStartWithDefaultParams("OzoneDemo");
 
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
+  params.using_mojo = ui::OzonePlatform::EnsureInstance()
+                          ->GetPlatformProperties()
+                          .requires_mojo;
   ui::OzonePlatform::InitializeForUI(params);
   ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
       ->SetCurrentLayoutByName("us");
 
+  ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
+
+  std::unique_ptr<ui::OzoneGpuTestHelper> gpu_helper;
+  if (!params.using_mojo) {
+    // OzoneGpuTestHelper transports Chrome IPC messages between host & gpu code
+    // in single process mode. We don't use both Chrome IPC and mojo, so only
+    // initialize it for non-mojo platforms.
+    gpu_helper = std::make_unique<ui::OzoneGpuTestHelper>();
+    gpu_helper->Initialize(base::ThreadTaskRunnerHandle::Get());
+  }
+
   base::RunLoop run_loop;
 
   ui::WindowManager window_manager(
diff --git a/ui/ozone/demo/simple_renderer_factory.cc b/ui/ozone/demo/simple_renderer_factory.cc
index 984e6e0..043583c 100644
--- a/ui/ozone/demo/simple_renderer_factory.cc
+++ b/ui/ozone/demo/simple_renderer_factory.cc
@@ -49,19 +49,13 @@
 SimpleRendererFactory::~SimpleRendererFactory() {}
 
 bool SimpleRendererFactory::Initialize() {
-  OzonePlatform::InitParams params;
-  params.single_process = true;
-  OzonePlatform::InitializeForGPU(params);
-  OzonePlatform::GetInstance()->AfterSandboxEntry();
-
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 
 #if BUILDFLAG(ENABLE_VULKAN)
   if (command_line->HasSwitch(kEnableVulkan)) {
     vulkan_implementation_ = gpu::CreateVulkanImplementation();
     if (vulkan_implementation_ &&
-        vulkan_implementation_->InitializeVulkanInstance() &&
-        gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get())) {
+        vulkan_implementation_->InitializeVulkanInstance()) {
       type_ = VULKAN;
       return true;
     } else {
@@ -69,8 +63,7 @@
     }
   }
 #endif
-  if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff() &&
-      gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get())) {
+  if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff()) {
     type_ = GL;
   } else {
     type_ = SOFTWARE;
diff --git a/ui/ozone/demo/simple_renderer_factory.h b/ui/ozone/demo/simple_renderer_factory.h
index 135619e..c28a2ab 100644
--- a/ui/ozone/demo/simple_renderer_factory.h
+++ b/ui/ozone/demo/simple_renderer_factory.h
@@ -39,9 +39,6 @@
 
   RendererType type_ = SOFTWARE;
 
-  // Helper for applications that do GL on main thread.
-  OzoneGpuTestHelper gpu_helper_;
-
   DISALLOW_COPY_AND_ASSIGN(SimpleRendererFactory);
 };
 
diff --git a/ui/ozone/demo/skia/skia_demo.cc b/ui/ozone/demo/skia/skia_demo.cc
index 2eee7b2..98ac14f 100644
--- a/ui/ozone/demo/skia/skia_demo.cc
+++ b/ui/ozone/demo/skia/skia_demo.cc
@@ -13,10 +13,12 @@
 #include "base/trace_event/trace_event.h"
 #include "components/tracing/common/trace_to_console.h"
 #include "components/tracing/common/tracing_switches.h"
+#include "mojo/core/embedder/embedder.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/ozone/demo/skia/skia_renderer_factory.h"
 #include "ui/ozone/demo/window_manager.h"
+#include "ui/ozone/public/ozone_gpu_test_helper.h"
 #include "ui/ozone/public/ozone_platform.h"
 
 int main(int argc, char** argv) {
@@ -38,6 +40,8 @@
         trace_config, base::trace_event::TraceLog::RECORDING_MODE);
   }
 
+  mojo::core::Init();
+
   // Build UI thread message loop. This is used by platform
   // implementations for event polling & running background tasks.
   base::MessageLoopForUI message_loop;
@@ -45,10 +49,25 @@
 
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
+  params.using_mojo = ui::OzonePlatform::EnsureInstance()
+                          ->GetPlatformProperties()
+                          .requires_mojo;
   ui::OzonePlatform::InitializeForUI(params);
   ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
       ->SetCurrentLayoutByName("us");
 
+  ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
+
+  std::unique_ptr<ui::OzoneGpuTestHelper> gpu_helper;
+  if (!params.using_mojo) {
+    // OzoneGpuTestHelper transports Chrome IPC messages between host & gpu code
+    // in single process mode. We don't use both Chrome IPC and mojo, so only
+    // initialize it for non-mojo platforms.
+    gpu_helper = std::make_unique<ui::OzoneGpuTestHelper>();
+    gpu_helper->Initialize(base::ThreadTaskRunnerHandle::Get());
+  }
+
   base::RunLoop run_loop;
 
   ui::WindowManager window_manager(std::make_unique<ui::SkiaRendererFactory>(),
diff --git a/ui/ozone/demo/skia/skia_renderer_factory.cc b/ui/ozone/demo/skia/skia_renderer_factory.cc
index 3ef7654..b1037fc 100644
--- a/ui/ozone/demo/skia/skia_renderer_factory.cc
+++ b/ui/ozone/demo/skia/skia_renderer_factory.cc
@@ -36,13 +36,7 @@
 SkiaRendererFactory::~SkiaRendererFactory() {}
 
 bool SkiaRendererFactory::Initialize() {
-  OzonePlatform::InitParams params;
-  params.single_process = true;
-  OzonePlatform::InitializeForGPU(params);
-  OzonePlatform::GetInstance()->AfterSandboxEntry();
-
-  if (!gl::init::InitializeGLOneOff() ||
-      !gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get())) {
+  if (!gl::init::InitializeGLOneOff()) {
     LOG(FATAL) << "Failed to initialize GL";
   }
 
diff --git a/ui/ozone/demo/skia/skia_renderer_factory.h b/ui/ozone/demo/skia/skia_renderer_factory.h
index dd4068f7..bd14c35 100644
--- a/ui/ozone/demo/skia/skia_renderer_factory.h
+++ b/ui/ozone/demo/skia/skia_renderer_factory.h
@@ -29,9 +29,6 @@
                                            const gfx::Size& size) override;
 
  private:
-  // Helper for applications that do GL on main thread.
-  OzoneGpuTestHelper gpu_helper_;
-
   DISALLOW_COPY_AND_ASSIGN(SkiaRendererFactory);
 };
 
diff --git a/ui/ozone/platform/wayland/test/test_data_source.cc b/ui/ozone/platform/wayland/test/test_data_source.cc
index a0ef41e..797a2bf 100644
--- a/ui/ozone/platform/wayland/test/test_data_source.cc
+++ b/ui/ozone/platform/wayland/test/test_data_source.cc
@@ -40,13 +40,6 @@
   return bytes;
 }
 
-void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
-  int raw_pipe[2];
-  PCHECK(0 == pipe(raw_pipe));
-  read_pipe->reset(raw_pipe[0]);
-  write_pipe->reset(raw_pipe[1]);
-}
-
 void DataSourceOffer(wl_client* client,
                      wl_resource* resource,
                      const char* mime_type) {
@@ -83,7 +76,7 @@
                               ReadDataCallback callback) {
   base::ScopedFD read_fd;
   base::ScopedFD write_fd;
-  CreatePipe(&read_fd, &write_fd);
+  PCHECK(base::CreatePipe(&read_fd, &write_fd));
 
   // 1. Send the SEND event to notify client's DataSource that it's time
   // to send us the drag data thrhough the write_fd file descriptor.
diff --git a/ui/ozone/platform/wayland/wayland_data_offer.cc b/ui/ozone/platform/wayland/wayland_data_offer.cc
index a3900dd..1a7d06b 100644
--- a/ui/ozone/platform/wayland/wayland_data_offer.cc
+++ b/ui/ozone/platform/wayland/wayland_data_offer.cc
@@ -7,6 +7,7 @@
 #include <fcntl.h>
 #include <algorithm>
 
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 
@@ -20,13 +21,6 @@
 const char kTextPlainUtf8[] = "text/plain;charset=utf-8";
 const char kUtf8String[] = "UTF8_STRING";
 
-void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
-  int raw_pipe[2];
-  PCHECK(0 == pipe(raw_pipe));
-  read_pipe->reset(raw_pipe[0]);
-  write_pipe->reset(raw_pipe[1]);
-}
-
 }  // namespace
 
 WaylandDataOffer::WaylandDataOffer(wl_data_offer* data_offer)
@@ -81,7 +75,7 @@
 
   base::ScopedFD read_fd;
   base::ScopedFD write_fd;
-  CreatePipe(&read_fd, &write_fd);
+  PCHECK(base::CreatePipe(&read_fd, &write_fd));
 
   // If we needed to forcibly write "text/plain" as an available
   // mimetype, then it is safer to "read" the clipboard data with
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index 0479858..39ca31a 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -767,6 +767,9 @@
       <message name="IDS_MESSAGE_NOTIFICATION_SEND_TAB_TO_SELF_DEVICE_INFO" desc="The message text for the notification when the user receive a shared tab from another device. It shows the name of the device which shared the tab.">
         Shared from <ph name="DEVICE_NAME">$1<ex>Ted's Pixel 2</ex></ph>
       </message>
+      <message name="IDS_MESSAGE_NOTIFICATION_SEND_TAB_TO_SELF_CONFIRMATION_SUCCESS" desc="The title text for the comformation notification when the user successfully share a tab to other devices.">
+        Sending tab...
+      </message>
       <if expr="chromeos">
         <message name="IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME" desc="The name of screenshot notifier that is a system component">
           Screenshot
diff --git a/ui/strings/ui_strings_grd/IDS_MESSAGE_NOTIFICATION_SEND_TAB_TO_SELF_CONFIRMATION_SUCCESS.png.sha1 b/ui/strings/ui_strings_grd/IDS_MESSAGE_NOTIFICATION_SEND_TAB_TO_SELF_CONFIRMATION_SUCCESS.png.sha1
new file mode 100644
index 0000000..78cca86
--- /dev/null
+++ b/ui/strings/ui_strings_grd/IDS_MESSAGE_NOTIFICATION_SEND_TAB_TO_SELF_CONFIRMATION_SUCCESS.png.sha1
@@ -0,0 +1 @@
+81ac47988e7b25274c7281f2ccb43b3e12f7ecfb
\ No newline at end of file
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index a09510e..2603d5ab 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -1023,6 +1023,8 @@
     "controls/menu/menu_runner_cocoa_unittest.mm",
     "controls/menu/menu_runner_unittest.cc",
     "controls/menu/submenu_view_unittest.cc",
+    "controls/menu/test_menu_item_view.cc",
+    "controls/menu/test_menu_item_view.h",
     "controls/native/native_view_host_mac_unittest.mm",
     "controls/native/native_view_host_test_base.cc",
     "controls/native/native_view_host_test_base.h",
diff --git a/ui/views/animation/ink_drop_event_handler.cc b/ui/views/animation/ink_drop_event_handler.cc
index d9604eb..19180f1 100644
--- a/ui/views/animation/ink_drop_event_handler.cc
+++ b/ui/views/animation/ink_drop_event_handler.cc
@@ -90,6 +90,20 @@
   }
 }
 
+void InkDropEventHandler::OnViewVisibilityChanged(View* observed_view) {
+  DCHECK_EQ(host_view_, observed_view);
+  if (!host_view_->visible() && delegate_->HasInkDrop()) {
+    delegate_->GetInkDrop()->AnimateToState(InkDropState::HIDDEN);
+    delegate_->GetInkDrop()->SetHovered(false);
+  }
+}
+
+void InkDropEventHandler::OnViewBoundsChanged(View* observed_view) {
+  DCHECK_EQ(host_view_, observed_view);
+  if (delegate_->HasInkDrop())
+    delegate_->GetInkDrop()->HostSizeChanged(host_view_->size());
+}
+
 void InkDropEventHandler::OnViewFocused(View* observed_view) {
   DCHECK_EQ(host_view_, observed_view);
   delegate_->GetInkDrop()->SetFocused(true);
diff --git a/ui/views/animation/ink_drop_event_handler.h b/ui/views/animation/ink_drop_event_handler.h
index af15f2e..c7d91c2 100644
--- a/ui/views/animation/ink_drop_event_handler.h
+++ b/ui/views/animation/ink_drop_event_handler.h
@@ -31,6 +31,9 @@
    public:
     // Gets the InkDrop (or stub) that should react to incoming events.
     virtual InkDrop* GetInkDrop() = 0;
+
+    virtual bool HasInkDrop() const = 0;
+
     // Start animating the InkDrop to another target state.
     // TODO(pbos): Consider moving the implementation of
     // InkDropHostView::AnimateInkDrop into InkDropEventHandler. In this case
@@ -51,6 +54,8 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
 
   // ViewObserver:
+  void OnViewVisibilityChanged(View* observed_view) override;
+  void OnViewBoundsChanged(View* observed_view) override;
   void OnViewFocused(View* observed_view) override;
   void OnViewBlurred(View* observed_view) override;
 
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc
index 967c513..c199cc5 100644
--- a/ui/views/animation/ink_drop_host_view.cc
+++ b/ui/views/animation/ink_drop_host_view.cc
@@ -26,9 +26,14 @@
     InkDropHostViewEventHandlerDelegate(InkDropHostView* host_view)
     : host_view_(host_view) {}
 
+bool InkDropHostView::InkDropHostViewEventHandlerDelegate::HasInkDrop() const {
+  return host_view_->HasInkDrop();
+}
+
 InkDrop* InkDropHostView::InkDropHostViewEventHandlerDelegate::GetInkDrop() {
   return host_view_->GetInkDrop();
 }
+
 void InkDropHostView::InkDropHostViewEventHandlerDelegate::AnimateInkDrop(
     InkDropState state,
     const ui::LocatedEvent* event) {
@@ -135,6 +140,8 @@
     const ViewHierarchyChangedDetails& details) {
   // If we're being removed hide the ink-drop so if we're highlighted now the
   // highlight won't be active if we're added back again.
+  // TODO(pbos): Consider adding this to the ViewObserver model so that we can
+  // observe when the host gets removed.
   if (!details.is_add && details.child == this && ink_drop_) {
     GetInkDrop()->SnapToHidden();
     GetInkDrop()->SetHovered(false);
@@ -142,19 +149,6 @@
   View::ViewHierarchyChanged(details);
 }
 
-void InkDropHostView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  if (ink_drop_)
-    ink_drop_->HostSizeChanged(size());
-}
-
-void InkDropHostView::VisibilityChanged(View* starting_from, bool is_visible) {
-  View::VisibilityChanged(starting_from, is_visible);
-  if (GetWidget() && !is_visible) {
-    GetInkDrop()->AnimateToState(InkDropState::HIDDEN);
-    GetInkDrop()->SetHovered(false);
-  }
-}
-
 std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() {
   auto ink_drop = std::make_unique<InkDropImpl>(this, size());
   ink_drop->SetAutoHighlightMode(
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h
index 9bb24ba..0574cad 100644
--- a/ui/views/animation/ink_drop_host_view.h
+++ b/ui/views/animation/ink_drop_host_view.h
@@ -130,8 +130,6 @@
   // View:
   void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) override;
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
-  void VisibilityChanged(View* starting_from, bool is_visible) override;
 
   // Returns an InkDropImpl suitable for use with a square ink drop.
   // TODO(pbos): Rename to CreateDefaultSquareInkDropImpl.
@@ -201,6 +199,7 @@
 
     // InkDropEventHandler:
     InkDrop* GetInkDrop() override;
+    bool HasInkDrop() const override;
     void AnimateInkDrop(InkDropState state,
                         const ui::LocatedEvent* event) override;
 
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 2f349a2..0eab270 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -274,13 +274,13 @@
     Type type,
     ui::MenuSeparatorType separator_style) {
   DCHECK_NE(type, EMPTY);
-  DCHECK_LE(0, index);
+  DCHECK_GE(index, 0);
   if (!submenu_)
     CreateSubmenu();
   DCHECK_GE(submenu_->child_count(), index);
   if (type == SEPARATOR) {
     submenu_->AddChildViewAt(new MenuSeparator(separator_style), index);
-    return NULL;
+    return nullptr;
   }
   MenuItemView* item = new MenuItemView(this, item_id, type);
   if (label.empty() && GetDelegate())
@@ -307,14 +307,14 @@
 
 void MenuItemView::RemoveMenuItemAt(int index) {
   DCHECK(submenu_);
-  DCHECK_LE(0, index);
-  DCHECK_GT(submenu_->child_count(), index);
+  DCHECK_GE(index, 0);
+  DCHECK_LT(index, submenu_->child_count());
 
   View* item = submenu_->child_at(index);
   DCHECK(item);
-  submenu_->RemoveChildView(item);
-
   removed_items_.push_back(item);
+
+  submenu_->RemoveChildView(item);
 }
 
 void MenuItemView::RemoveAllMenuItems() {
diff --git a/ui/views/controls/menu/menu_item_view_unittest.cc b/ui/views/controls/menu/menu_item_view_unittest.cc
index bd355ecb..eae17ab 100644
--- a/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -15,6 +15,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/controls/menu/submenu_view.h"
+#include "ui/views/controls/menu/test_menu_item_view.h"
 #include "ui/views/test/menu_test_utils.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/vector_icons.h"
@@ -37,23 +38,8 @@
 
 }  // namespace
 
-// A MenuItemView implementation with a public destructor (so we can clean up
-// in tests).
-class TestMenuItemView : public MenuItemView {
- public:
-  TestMenuItemView() : MenuItemView(NULL) {}
-  ~TestMenuItemView() override {}
-
-  void AddEmptyMenus() { MenuItemView::AddEmptyMenus(); }
-
-  void SetHasMnemonics(bool has_mnemonics) { has_mnemonics_ = has_mnemonics; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
-};
-
 TEST(MenuItemViewUnitTest, TestMenuItemViewWithFlexibleWidthChild) {
-  TestMenuItemView root_menu;
+  views::TestMenuItemView root_menu;
   root_menu.set_owned_by_client();
 
   // Append a normal MenuItemView.
@@ -92,7 +78,7 @@
 // Tests that the top-level menu item with hidden children should contain the
 // "(empty)" menu item to display.
 TEST(MenuItemViewUnitTest, TestEmptyTopLevelWhenAllItemsAreHidden) {
-  TestMenuItemView root_menu;
+  views::TestMenuItemView root_menu;
   views::MenuItemView* item1 =
       root_menu.AppendMenuItemWithLabel(1, base::ASCIIToUTF16("item 1"));
   views::MenuItemView* item2 =
@@ -123,7 +109,7 @@
 // Tests that submenu with hidden children should contain the "(empty)" menu
 // item to display.
 TEST(MenuItemViewUnitTest, TestEmptySubmenuWhenAllChildItemsAreHidden) {
-  TestMenuItemView root_menu;
+  views::TestMenuItemView root_menu;
   MenuItemView* submenu_item =
       root_menu.AppendSubMenu(1, base::ASCIIToUTF16("My Submenu"));
   MenuItemView* child1 = submenu_item->AppendMenuItemWithLabel(
@@ -159,13 +145,13 @@
 }
 
 TEST(MenuItemViewUnitTest, UseMnemonicOnPlatform) {
-  TestMenuItemView root_menu;
+  views::TestMenuItemView root_menu;
   views::MenuItemView* item1 =
       root_menu.AppendMenuItemWithLabel(1, base::ASCIIToUTF16("&Item 1"));
   views::MenuItemView* item2 =
       root_menu.AppendMenuItemWithLabel(2, base::ASCIIToUTF16("I&tem 2"));
 
-  root_menu.SetHasMnemonics(true);
+  root_menu.set_has_mnemonics(true);
 
   if (MenuConfig::instance().use_mnemonics) {
     EXPECT_EQ('i', item1->GetMnemonic());
diff --git a/ui/views/controls/menu/menu_runner.h b/ui/views/controls/menu/menu_runner.h
index 549d859..4d8f79a 100644
--- a/ui/views/controls/menu/menu_runner.h
+++ b/ui/views/controls/menu/menu_runner.h
@@ -104,6 +104,9 @@
     // propagate back to the parent so the combobox content can be edited even
     // while the menu is open.
     EDITABLE_COMBOBOX = 1 << 9,
+
+    // Indicates that the menu should show mnemonics.
+    SHOULD_SHOW_MNEMONICS = 1 << 10,
   };
 
   // Creates a new MenuRunner, which may use a native menu if available.
diff --git a/ui/views/controls/menu/menu_runner_impl.cc b/ui/views/controls/menu/menu_runner_impl.cc
index ad08635..c96ba576 100644
--- a/ui/views/controls/menu/menu_runner_impl.cc
+++ b/ui/views/controls/menu/menu_runner_impl.cc
@@ -140,7 +140,7 @@
   controller_ = controller->AsWeakPtr();
   menu_->set_controller(controller_.get());
   menu_->PrepareForRun(owns_controller_, has_mnemonics,
-                       !for_drop_ && ShouldShowMnemonics(button));
+                       !for_drop_ && ShouldShowMnemonics(button, run_types));
 
   controller->Run(parent, button, menu_, bounds, anchor,
                   (run_types & MenuRunner::CONTEXT_MENU) != 0,
@@ -203,9 +203,10 @@
     delete *i;
 }
 
-bool MenuRunnerImpl::ShouldShowMnemonics(MenuButton* button) {
+bool MenuRunnerImpl::ShouldShowMnemonics(MenuButton* button,
+                                         int32_t run_types) {
+  bool show_mnemonics = run_types & MenuRunner::SHOULD_SHOW_MNEMONICS;
   // Show mnemonics if the button has focus or alt is pressed.
-  bool show_mnemonics = button ? button->HasFocus() : false;
 #if defined(OS_WIN)
   show_mnemonics |= ui::win::IsAltPressed();
 #elif defined(USE_X11)
diff --git a/ui/views/controls/menu/menu_runner_impl.h b/ui/views/controls/menu/menu_runner_impl.h
index a3f97c3..2667d3c 100644
--- a/ui/views/controls/menu/menu_runner_impl.h
+++ b/ui/views/controls/menu/menu_runner_impl.h
@@ -60,7 +60,7 @@
   ~MenuRunnerImpl() override;
 
   // Returns true if mnemonics should be shown in the menu.
-  bool ShouldShowMnemonics(MenuButton* button);
+  bool ShouldShowMnemonics(MenuButton* button, int32_t run_types);
 
   // The menu. We own this. We don't use scoped_ptr as the destructor is
   // protected and we're a friend.
diff --git a/ui/views/controls/menu/menu_runner_unittest.cc b/ui/views/controls/menu/menu_runner_unittest.cc
index a5972e65..10237b3 100644
--- a/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/ui/views/controls/menu/menu_runner_unittest.cc
@@ -21,6 +21,7 @@
 #include "ui/views/controls/menu/menu_runner_impl.h"
 #include "ui/views/controls/menu/menu_types.h"
 #include "ui/views/controls/menu/submenu_view.h"
+#include "ui/views/controls/menu/test_menu_item_view.h"
 #include "ui/views/test/menu_test_utils.h"
 #include "ui/views/test/test_views.h"
 #include "ui/views/test/test_views_delegate.h"
@@ -35,28 +36,26 @@
 // occurring immediately during the release of ViewsDelegate.
 class DeletingTestViewsDelegate : public views::TestViewsDelegate {
  public:
-  DeletingTestViewsDelegate() : menu_runner_(nullptr) {}
-  ~DeletingTestViewsDelegate() override {}
+  DeletingTestViewsDelegate() = default;
+  ~DeletingTestViewsDelegate() override = default;
 
   void set_menu_runner(views::internal::MenuRunnerImpl* menu_runner) {
     menu_runner_ = menu_runner;
   }
 
   // views::ViewsDelegate:
-  void ReleaseRef() override;
+  void ReleaseRef() override {
+    if (menu_runner_)
+      menu_runner_->Release();
+  }
 
  private:
   // Not owned, deletes itself.
-  views::internal::MenuRunnerImpl* menu_runner_;
+  views::internal::MenuRunnerImpl* menu_runner_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(DeletingTestViewsDelegate);
 };
 
-void DeletingTestViewsDelegate::ReleaseRef() {
-  if (menu_runner_)
-    menu_runner_->Release();
-}
-
 }  // namespace
 
 namespace views {
@@ -64,33 +63,58 @@
 
 class MenuRunnerTest : public ViewsTestBase {
  public:
-  MenuRunnerTest();
-  ~MenuRunnerTest() override;
+  MenuRunnerTest() = default;
+  ~MenuRunnerTest() override = default;
 
   // Initializes the delegates and views needed for a menu. It does not create
   // the MenuRunner.
-  void InitMenuViews();
+  void InitMenuViews() {
+    menu_delegate_ = std::make_unique<TestMenuDelegate>();
+    menu_item_view_ = new views::TestMenuItemView(menu_delegate_.get());
+    menu_item_view_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
+    menu_item_view_->AppendMenuItemWithLabel(
+        2, base::WideToUTF16(L"\x062f\x0648"));
+
+    owner_ = std::make_unique<Widget>();
+    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    owner_->Init(params);
+    owner_->Show();
+  }
 
   // Initializes all delegates and views needed for a menu. A MenuRunner is also
   // created with |run_types|, it takes ownership of |menu_item_view_|.
-  void InitMenuRunner(int32_t run_types);
+  void InitMenuRunner(int32_t run_types) {
+    InitMenuViews();
+    menu_runner_ = std::make_unique<MenuRunner>(menu_item_view_, run_types);
+  }
 
-  MenuItemView* menu_item_view() { return menu_item_view_; }
+  views::TestMenuItemView* menu_item_view() { return menu_item_view_; }
   TestMenuDelegate* menu_delegate() { return menu_delegate_.get(); }
   MenuRunner* menu_runner() { return menu_runner_.get(); }
   Widget* owner() { return owner_.get(); }
 
   // ViewsTestBase:
-  void TearDown() override;
+  void TearDown() override {
+    if (owner_)
+      owner_->CloseNow();
+    ViewsTestBase::TearDown();
+  }
 
   bool IsItemSelected(int command_id) {
     MenuItemView* item = menu_item_view()->GetMenuItemByID(command_id);
     return item ? item->IsSelected() : false;
   }
 
+  // Menus that use prefix selection don't support mnemonics - the input is
+  // always part of the prefix.
+  bool MenuSupportsMnemonics() {
+    return !MenuConfig::instance().all_menus_use_prefix_selection;
+  }
+
  private:
   // Owned by menu_runner_.
-  MenuItemView* menu_item_view_ = nullptr;
+  views::TestMenuItemView* menu_item_view_ = nullptr;
 
   std::unique_ptr<TestMenuDelegate> menu_delegate_;
   std::unique_ptr<MenuRunner> menu_runner_;
@@ -99,35 +123,6 @@
   DISALLOW_COPY_AND_ASSIGN(MenuRunnerTest);
 };
 
-MenuRunnerTest::MenuRunnerTest() {}
-
-MenuRunnerTest::~MenuRunnerTest() {}
-
-void MenuRunnerTest::InitMenuViews() {
-  menu_delegate_.reset(new TestMenuDelegate);
-  menu_item_view_ = new MenuItemView(menu_delegate_.get());
-  menu_item_view_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One"));
-  menu_item_view_->AppendMenuItemWithLabel(2,
-                                           base::WideToUTF16(L"\x062f\x0648"));
-
-  owner_.reset(new Widget);
-  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
-  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  owner_->Init(params);
-  owner_->Show();
-}
-
-void MenuRunnerTest::InitMenuRunner(int32_t run_types) {
-  InitMenuViews();
-  menu_runner_.reset(new MenuRunner(menu_item_view_, run_types));
-}
-
-void MenuRunnerTest::TearDown() {
-  if (owner_)
-    owner_->CloseNow();
-  ViewsTestBase::TearDown();
-}
-
 // Tests that MenuRunner is still running after the call to RunMenuAt when
 // initialized with , and that MenuDelegate is notified upon
 // the closing of the menu.
@@ -165,9 +160,7 @@
 // Tests that a key press on a US keyboard layout activates the correct menu
 // item.
 TEST_F(MenuRunnerTest, LatinMnemonic) {
-  // Menus that use prefix selection don't support mnemonics - the input is
-  // always part of the prefix.
-  if (MenuConfig::instance().all_menus_use_prefix_selection)
+  if (!MenuSupportsMnemonics())
     return;
 
   views::test::DisableMenuClosureAnimations();
@@ -191,9 +184,7 @@
 // Tests that a key press on a non-US keyboard layout activates the correct menu
 // item. Disabled on Windows because a WM_CHAR event does not activate an item.
 TEST_F(MenuRunnerTest, NonLatinMnemonic) {
-  // Menus that use prefix selection don't support mnemonics - the input is
-  // always part of the prefix.
-  if (MenuConfig::instance().all_menus_use_prefix_selection)
+  if (!MenuSupportsMnemonics())
     return;
 
   views::test::DisableMenuClosureAnimations();
@@ -215,6 +206,30 @@
 }
 #endif  // !defined(OS_WIN)
 
+TEST_F(MenuRunnerTest, MenuItemViewShowsMnemonics) {
+  if (!MenuSupportsMnemonics())
+    return;
+
+  InitMenuRunner(MenuRunner::HAS_MNEMONICS | MenuRunner::SHOULD_SHOW_MNEMONICS);
+
+  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+                           ui::MENU_SOURCE_NONE);
+
+  EXPECT_TRUE(menu_item_view()->show_mnemonics());
+}
+
+TEST_F(MenuRunnerTest, MenuItemViewDoesNotShowMnemonics) {
+  if (!MenuSupportsMnemonics())
+    return;
+
+  InitMenuRunner(MenuRunner::HAS_MNEMONICS);
+
+  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+                           ui::MENU_SOURCE_NONE);
+
+  EXPECT_FALSE(menu_item_view()->show_mnemonics());
+}
+
 TEST_F(MenuRunnerTest, PrefixSelect) {
   if (!MenuConfig::instance().all_menus_use_prefix_selection)
     return;
diff --git a/ui/views/controls/menu/test_menu_item_view.cc b/ui/views/controls/menu/test_menu_item_view.cc
new file mode 100644
index 0000000..76cb42c
--- /dev/null
+++ b/ui/views/controls/menu/test_menu_item_view.cc
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/test_menu_item_view.h"
+
+namespace views {
+
+TestMenuItemView::TestMenuItemView() : MenuItemView(nullptr) {}
+
+TestMenuItemView::TestMenuItemView(MenuDelegate* delegate)
+    : MenuItemView(delegate) {}
+
+TestMenuItemView::~TestMenuItemView() = default;
+
+}  // namespace views
diff --git a/ui/views/controls/menu/test_menu_item_view.h b/ui/views/controls/menu/test_menu_item_view.h
new file mode 100644
index 0000000..23acc34
--- /dev/null
+++ b/ui/views/controls/menu/test_menu_item_view.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_CONTROLS_MENU_TEST_MENU_ITEM_VIEW_H_
+#define UI_VIEWS_CONTROLS_MENU_TEST_MENU_ITEM_VIEW_H_
+
+#include "ui/views/controls/menu/menu_item_view.h"
+
+namespace views {
+
+class MenuDelegate;
+
+// A MenuItemView implementation with a public destructor (so we can clean up
+// in tests).
+class TestMenuItemView : public MenuItemView {
+ public:
+  TestMenuItemView();
+  explicit TestMenuItemView(MenuDelegate* delegate);
+  ~TestMenuItemView() override;
+
+  using MenuItemView::AddEmptyMenus;
+
+  void set_has_mnemonics(bool has_mnemonics) { has_mnemonics_ = has_mnemonics; }
+
+  bool show_mnemonics() { return show_mnemonics_; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_MENU_TEST_MENU_ITEM_VIEW_H_
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index 22a3a4b..d06ca35 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -398,17 +398,6 @@
 
   if (!params.accept_events)
     window()->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::NONE);
-
-  // Sets the has-content info for the occlusion tracker that runs on the Window
-  // Service side.
-  // TODO(edcourtney): Remove this once we plumb through the window's
-  // transparent value through mus. That, in combination with the layer type
-  // will let the occlusion tracker determine if the window should affect
-  // occlusion.
-  content_window()->SetProperty(
-      aura::client::kClientWindowHasContent,
-      params.layer_type != ui::LAYER_NOT_DRAWN &&
-          params.opacity == Widget::InitParams::OPAQUE_WINDOW);
 }
 
 void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
diff --git a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index d39534a..07c19a3 100644
--- a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -463,40 +463,26 @@
   }
 }
 
-TEST_F(DesktopWindowTreeHostMusTest, ClientWindowHasContent) {
-  // Opaque window has content.
-  {
+TEST_F(DesktopWindowTreeHostMusTest, ClientWindowLayerDrawnSet) {
+  struct {
+    ui::LayerType layer_type;
+    bool expected_layer_drawn;
+  } kTestCases[] = {
+      {ui::LayerType::LAYER_TEXTURED, true},
+      {ui::LayerType::LAYER_SOLID_COLOR, true},
+      {ui::LayerType::LAYER_NINE_PATCH, true},
+      {ui::LayerType::LAYER_NOT_DRAWN, false},
+  };
+
+  for (const auto& test : kTestCases) {
     Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
     params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    params.layer_type = test.layer_type;
 
     Widget widget;
     widget.Init(params);
-    EXPECT_TRUE(widget.GetNativeWindow()->GetProperty(
-        aura::client::kClientWindowHasContent));
-  }
-
-  // Translucent window does not have content.
-  {
-    Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
-    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-
-    Widget widget;
-    widget.Init(params);
-    EXPECT_FALSE(widget.GetNativeWindow()->GetProperty(
-        aura::client::kClientWindowHasContent));
-  }
-
-  // Window with LAYER_NOT_DRAWN does not have content.
-  {
-    Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
-    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-    params.layer_type = ui::LAYER_NOT_DRAWN;
-
-    Widget widget;
-    widget.Init(params);
-    EXPECT_FALSE(widget.GetNativeWindow()->GetProperty(
-        aura::client::kClientWindowHasContent));
+    EXPECT_EQ(test.expected_layer_drawn, widget.GetNativeWindow()->GetProperty(
+                                             aura::client::kWindowLayerDrawn));
   }
 }
 
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 610ff68..6953d53 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -209,8 +209,10 @@
 }
 
 int View::GetIndexOf(const View* view) const {
-  auto i(std::find(children_.begin(), children_.end(), view));
-  return i != children_.end() ? static_cast<int>(i - children_.begin()) : -1;
+  const auto i = std::find(children_.cbegin(), children_.cend(), view);
+  return i == children_.cend()
+             ? -1
+             : static_cast<int>(std::distance(children_.cbegin(), i));
 }
 
 // Size and disposition --------------------------------------------------------
@@ -1900,17 +1902,19 @@
   DCHECK_GE(index, 0);
   DCHECK_LE(index, child_count());
 
-  // If |view| has a parent, remove it from its parent.
+  // TODO(https://crbug.com/942298): Should just DCHECK(!view->parent_);.
   View* parent = view->parent_;
+  if (parent == this) {
+    ReorderChildView(view, index);
+    return;
+  }
+
+  // Remove |view| from its parent, if any.
   ui::NativeTheme* old_theme = nullptr;
   Widget* old_widget = nullptr;
   if (parent) {
     old_theme = view->GetNativeTheme();
     old_widget = view->GetWidget();
-    if (parent == this) {
-      ReorderChildView(view, index);
-      return;
-    }
     parent->DoRemoveChildView(view, true, true, false, this);
   }
 
@@ -1975,8 +1979,8 @@
                              View* new_parent) {
   DCHECK(view);
 
-  const Views::iterator i(std::find(children_.begin(), children_.end(), view));
-  if (i == children_.end())
+  const auto i = std::find(children_.cbegin(), children_.cend(), view);
+  if (i == children_.cend())
     return;
 
   std::unique_ptr<View> view_to_be_deleted;
diff --git a/ui/views/view.h b/ui/views/view.h
index 96a0c004..3fd9795 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -309,7 +309,7 @@
   // the view at the end.
   void ReorderChildView(View* view, int index);
 
-  // Removes |view| from this view. The view's parent will change to NULL.
+  // Removes |view| from this view. The view's parent will change to null.
   void RemoveChildView(View* view);
 
   // Removes all the children from this view. If |delete_children| is true,
@@ -454,7 +454,7 @@
   // subclass if the paint order should differ from that of |children_|.
   // This order is taken into account by painting and targeting implementations.
   // NOTE: see SetPaintToLayer() for details on painting and views with layers.
-  virtual View::Views GetChildrenInZOrder();
+  virtual Views GetChildrenInZOrder();
 
   // Transformations -----------------------------------------------------------
 
@@ -719,16 +719,16 @@
   // RTL painting --------------------------------------------------------------
 
   // This method determines whether the gfx::Canvas object passed to
-  // View::Paint() needs to be transformed such that anything drawn on the
-  // canvas object during View::Paint() is flipped horizontally.
+  // Paint() needs to be transformed such that anything drawn on the canvas
+  // object during Paint() is flipped horizontally.
   bool flip_canvas_on_paint_for_rtl_ui() const {
     return flip_canvas_on_paint_for_rtl_ui_;
   }
 
-  // Enables or disables flipping of the gfx::Canvas during View::Paint().
-  // Note that if canvas flipping is enabled, the canvas will be flipped only
-  // if the UI layout is right-to-left; that is, the canvas will be flipped
-  // only if base::i18n::IsRTL() returns true.
+  // Enables or disables flipping of the gfx::Canvas during Paint(). Note that
+  // if canvas flipping is enabled, the canvas will be flipped only if the UI
+  // layout is right-to-left; that is, the canvas will be flipped only if
+  // base::i18n::IsRTL() returns true.
   //
   // Enabling canvas flipping is useful for leaf views that draw an image that
   // needs to be flipped horizontally when the UI layout is right-to-left
@@ -1234,9 +1234,9 @@
   // an opportunity to do a fresh layout if that makes sense.
   virtual void ChildVisibilityChanged(View* child) {}
 
-  // Invalidates the layout and calls ChildPreferredSizeChanged on the parent
-  // if there is one. Be sure to call View::PreferredSizeChanged when
-  // overriding such that the layout is properly invalidated.
+  // Invalidates the layout and calls ChildPreferredSizeChanged() on the parent
+  // if there is one. Be sure to call PreferredSizeChanged() when overriding
+  // such that the layout is properly invalidated.
   virtual void PreferredSizeChanged();
 
   // Override returning true when the view needs to be notified when its visible
@@ -1805,8 +1805,8 @@
 
   // RTL painting --------------------------------------------------------------
 
-  // Indicates whether or not the gfx::Canvas object passed to View::Paint()
-  // is going to be flipped horizontally (using the appropriate transform) on
+  // Indicates whether or not the gfx::Canvas object passed to Paint() is going
+  // to be flipped horizontally (using the appropriate transform) on
   // right-to-left locales for this View.
   bool flip_canvas_on_paint_for_rtl_ui_ = false;
 
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index 50a8a92..b101a0a 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -78,11 +78,10 @@
   const views::View* v = view;
   const views::View* parent = v->parent();
   if (!parent)
-    return NULL;
-  int next = parent->GetIndexOf(v) + 1;
-  if (next != parent->child_count())
-    return FirstView(parent->child_at(next));
-  return parent;
+    return nullptr;
+  const int next = parent->GetIndexOf(v) + 1;
+  return (next == parent->child_count()) ? parent
+                                         : FirstView(parent->child_at(next));
 }
 
 // Convenience functions for walking a Layer tree.
@@ -183,10 +182,12 @@
     int a = base::RandInt(0, count - 1);
     int b = base::RandInt(0, count - 1);
 
-    views::View* view_a = view->child_at(a);
-    views::View* view_b = view->child_at(b);
-    view->ReorderChildView(view_a, b);
-    view->ReorderChildView(view_b, a);
+    if (a != b) {
+      views::View* view_a = view->child_at(a);
+      views::View* view_b = view->child_at(b);
+      view->ReorderChildView(view_a, b);
+      view->ReorderChildView(view_b, a);
+    }
   }
 
   if (!view->layer() && base::RandDouble() < 0.1)
@@ -3550,19 +3551,19 @@
   View* foo1 = new View;
   child1->AddChildView(foo1);
 
-  EXPECT_EQ(-1, root.GetIndexOf(NULL));
+  EXPECT_EQ(-1, root.GetIndexOf(nullptr));
   EXPECT_EQ(-1, root.GetIndexOf(&root));
   EXPECT_EQ(0, root.GetIndexOf(child1));
   EXPECT_EQ(1, root.GetIndexOf(child2));
   EXPECT_EQ(-1, root.GetIndexOf(foo1));
 
-  EXPECT_EQ(-1, child1->GetIndexOf(NULL));
+  EXPECT_EQ(-1, child1->GetIndexOf(nullptr));
   EXPECT_EQ(-1, child1->GetIndexOf(&root));
   EXPECT_EQ(-1, child1->GetIndexOf(child1));
   EXPECT_EQ(-1, child1->GetIndexOf(child2));
   EXPECT_EQ(0, child1->GetIndexOf(foo1));
 
-  EXPECT_EQ(-1, child2->GetIndexOf(NULL));
+  EXPECT_EQ(-1, child2->GetIndexOf(nullptr));
   EXPECT_EQ(-1, child2->GetIndexOf(&root));
   EXPECT_EQ(-1, child2->GetIndexOf(child2));
   EXPECT_EQ(-1, child2->GetIndexOf(child1));
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index e63b5ed..014b2f5 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -295,6 +295,19 @@
   DISALLOW_COPY_AND_ASSIGN(CustomTooltipView);
 };
 
+// A Widget subclass that exposes counts to calls made to OnMouseEvent().
+class MouseTrackingWidget : public Widget {
+ public:
+  int GetMouseEventCount(ui::EventType type) { return counts_[type]; }
+  void OnMouseEvent(ui::MouseEvent* event) override {
+    ++counts_[event->type()];
+    Widget::OnMouseEvent(event);
+  }
+
+ private:
+  std::map<int, int> counts_;
+};
+
 // Test visibility states triggered externally.
 TEST_F(NativeWidgetMacTest, HideAndShowExternally) {
   Widget* widget = CreateTopLevelPlatformWidget();
@@ -1075,6 +1088,52 @@
   widget_below->CloseNow();
 }
 
+// Ensure captured mouse events correctly update dragging state in BaseView.
+// Regression test for https://crbug.com/942452.
+TEST_F(NativeWidgetMacTest, CapturedMouseUpClearsDrag) {
+  MouseTrackingWidget* widget = new MouseTrackingWidget;
+  Widget::InitParams init_params(Widget::InitParams::TYPE_WINDOW);
+  widget->Init(init_params);
+
+  NSWindow* window = widget->GetNativeWindow().GetNativeNSWindow();
+  BridgedContentView* native_view = [window contentView];
+
+  // Note: using native coordinates for consistency.
+  [window setFrame:NSMakeRect(50, 50, 100, 100) display:YES animate:NO];
+  NSEvent* enter_event = cocoa_test_event_utils::EnterEvent({50, 50}, window);
+  NSEvent* exit_event = cocoa_test_event_utils::ExitEvent({200, 200}, window);
+
+  widget->Show();
+  EXPECT_EQ(0, widget->GetMouseEventCount(ui::ET_MOUSE_ENTERED));
+  EXPECT_EQ(0, widget->GetMouseEventCount(ui::ET_MOUSE_EXITED));
+
+  [native_view mouseEntered:enter_event];
+  EXPECT_EQ(1, widget->GetMouseEventCount(ui::ET_MOUSE_ENTERED));
+  EXPECT_EQ(0, widget->GetMouseEventCount(ui::ET_MOUSE_EXITED));
+
+  [native_view mouseExited:exit_event];
+  EXPECT_EQ(1, widget->GetMouseEventCount(ui::ET_MOUSE_ENTERED));
+  EXPECT_EQ(1, widget->GetMouseEventCount(ui::ET_MOUSE_EXITED));
+
+  // Send a click. Note a click may initiate a drag, so the mouse-up is sent as
+  // a captured event.
+  std::pair<NSEvent*, NSEvent*> click =
+      cocoa_test_event_utils::MouseClickInView(native_view, 1);
+  [native_view mouseDown:click.first];
+  [native_view processCapturedMouseEvent:click.second];
+
+  // After a click, Enter/Exit should still work.
+  [native_view mouseEntered:enter_event];
+  EXPECT_EQ(2, widget->GetMouseEventCount(ui::ET_MOUSE_ENTERED));
+  EXPECT_EQ(1, widget->GetMouseEventCount(ui::ET_MOUSE_EXITED));
+
+  [native_view mouseExited:exit_event];
+  EXPECT_EQ(2, widget->GetMouseEventCount(ui::ET_MOUSE_ENTERED));
+  EXPECT_EQ(2, widget->GetMouseEventCount(ui::ET_MOUSE_EXITED));
+
+  widget->CloseNow();
+}
+
 namespace {
 
 // Delegate to make Widgets of a provided ui::ModalType.
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 3f52bcdc..b754ea2 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -221,12 +221,6 @@
   return TRUE;
 }
 
-bool IsDwmCompositionEnabled() {
-  BOOL is_dwm_composition_enabled;
-  DwmIsCompositionEnabled(&is_dwm_composition_enabled);
-  return static_cast<bool>(is_dwm_composition_enabled);
-}
-
 // The thickness of an auto-hide taskbar in pixels.
 const int kAutoHideTaskbarThicknessPx = 2;
 
@@ -402,7 +396,7 @@
       touch_down_contexts_(0),
       last_mouse_hwheel_time_(0),
       dwm_transition_desired_(false),
-      dwm_composition_enabled_(IsDwmCompositionEnabled()),
+      dwm_composition_enabled_(ui::win::IsDwmCompositionEnabled()),
       sent_window_size_changing_(false),
       left_button_down_on_caption_(false),
       background_fullscreen_hack_(false),
@@ -1639,7 +1633,7 @@
     return 0;
   }
 
-  bool dwm_composition_enabled = IsDwmCompositionEnabled();
+  bool dwm_composition_enabled = ui::win::IsDwmCompositionEnabled();
   if (dwm_composition_enabled_ != dwm_composition_enabled) {
     // Do not cause the Window to be hidden and shown unless there was
     // an actual change in the theme. This filter is necessary because
diff --git a/ui/views/window/non_client_view.cc b/ui/views/window/non_client_view.cc
index 0f637b09..ca5bf7e0 100644
--- a/ui/views/window/non_client_view.cc
+++ b/ui/views/window/non_client_view.cc
@@ -181,9 +181,8 @@
 
 void NonClientView::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
-  // Add our two child views here as we are added to the Widget so that if we
-  // are subsequently resized all the parent-child relationships are
-  // established.
+  // Add our child views here as we are added to the Widget so that if we are
+  // subsequently resized all the parent-child relationships are established.
   if (details.is_add && GetWidget() && details.child == this) {
     AddChildViewAt(frame_view_.get(), kFrameViewIndex);
     AddChildViewAt(client_view_, kClientViewIndex);
diff --git a/ui/views_bridge_mac/bridged_content_view.mm b/ui/views_bridge_mac/bridged_content_view.mm
index 46e0bf89..345b110 100644
--- a/ui/views_bridge_mac/bridged_content_view.mm
+++ b/ui/views_bridge_mac/bridged_content_view.mm
@@ -286,11 +286,13 @@
 
   // If it's the view's window, process normally.
   if ([target isEqual:source]) {
-    if (isScrollEvent)
+    if (isScrollEvent) {
       [self scrollWheel:theEvent];
-    else
+    } else {
       [self mouseEvent:theEvent];
-
+      if ([theEvent type] == NSLeftMouseUp)
+        [self handleLeftMouseUp:theEvent];
+    }
     return;
   }