diff --git a/.gn b/.gn
index ec3d387..c1a1113 100644
--- a/.gn
+++ b/.gn
@@ -84,6 +84,68 @@
   #"//chrome/*",  # Epic number of errors.
   "//chrome/app/*",
   "//chrome/app_shim/*",
+
+  #"//chrome/browser/android/*",  # Only metrics and vr have errors.
+  "//chrome/browser/android/accessibility/*",
+  "//chrome/browser/android/autofill_assistant/*",
+  "//chrome/browser/android/bookmarks/*",
+  "//chrome/browser/android/bottombar/*",
+  "//chrome/browser/android/browserservices/*",
+  "//chrome/browser/android/browsing_data/*",
+  "//chrome/browser/android/component_updater/*",
+  "//chrome/browser/android/compositor/*",
+  "//chrome/browser/android/compositor/layer/*",
+  "//chrome/browser/android/compositor/resources/*",
+  "//chrome/browser/android/compositor/scene_layer/*",
+  "//chrome/browser/android/consent_auditor/*",
+  "//chrome/browser/android/content/*",
+  "//chrome/browser/android/contextualsearch/*",
+  "//chrome/browser/android/contextual_suggestions/*",
+  "//chrome/browser/android/cookies/*",
+  "//chrome/browser/android/crash/*",
+  "//chrome/browser/android/customtabs/*",
+  "//chrome/browser/android/digital_asset_links/*",
+  "//chrome/browser/android/document/*",
+  "//chrome/browser/android/dom_distiller/*",
+  "//chrome/browser/android/download/*",
+  "//chrome/browser/android/download/items/*",
+  "//chrome/browser/android/download/service/*",
+  "//chrome/browser/android/explore_sites/*",
+  "//chrome/browser/android/feature_engagement/*",
+  "//chrome/browser/android/feed/*",
+  "//chrome/browser/android/feedback/*",
+  "//chrome/browser/android/find_in_page/*",
+  "//chrome/browser/android/history/*",
+  "//chrome/browser/android/history_report/*",
+  "//chrome/browser/android/instantapps/*",
+  "//chrome/browser/android/locale/*",
+  "//chrome/browser/android/mojo/*",
+  "//chrome/browser/android/net/*",
+  "//chrome/browser/android/ntp/*",
+  "//chrome/browser/android/omnibox/*",
+  "//chrome/browser/android/oom_intervention/*",
+  "//chrome/browser/android/password_manager/*",
+  "//chrome/browser/android/payments/*",
+  "//chrome/browser/android/policy/*",
+  "//chrome/browser/android/preferences/*",
+  "//chrome/browser/android/preferences/autofill/*",
+  "//chrome/browser/android/profiles/*",
+  "//chrome/browser/android/proto/*",
+  "//chrome/browser/android/provider/*",
+  "//chrome/browser/android/rappor/*",
+  "//chrome/browser/android/rlz/*",
+  "//chrome/browser/android/search_permissions/*",
+  "//chrome/browser/android/sessions/*",
+  "//chrome/browser/android/signin/*",
+  "//chrome/browser/android/subresource_filter/*",
+  "//chrome/browser/android/tasks/*",
+  "//chrome/browser/android/thumbnail/*",
+  "//chrome/browser/android/usb/*",
+  "//chrome/browser/android/vr/arcore_device/*",
+  "//chrome/browser/android/webapk/*",
+  "//chrome/browser/android/webapps/*",
+  "//chrome/browser/android/widget/*",
+
   "//chrome/browser/chromeos/*",
   "//chrome/browser/extensions/*",
   "//chrome/browser/resource_coordinator/*",
diff --git a/BUILD.gn b/BUILD.gn
index 5479f5f..45b912d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -142,7 +142,7 @@
       "//ppapi/examples/video_encode",
       "//printing:printing_unittests",
       "//third_party/SPIRV-Tools/src:SPIRV-Tools",
-      "//third_party/SPIRV-Tools/src/testing/fuzzers",
+      "//third_party/SPIRV-Tools/src/test/fuzzers",
       "//third_party/cacheinvalidation:cacheinvalidation_unittests",
       "//third_party/pdfium/samples:pdfium_test",
       "//third_party/webrtc/rtc_tools:frame_analyzer",
diff --git a/DEPS b/DEPS
index 7f2fc89d..ae1d4d54 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,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': '01d9a344b575b95d982edcad52787e2bd62e6beb',
+  'skia_revision': 'f5402004c4a6871ecbd8bb4cf300d0e20155e867',
   # 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': '973f34ce78a25a64567f0e12348d4114429c7342',
+  'v8_revision': '36315c26d3c0ae9867c6ca2f970aaced75f0c599',
   # 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.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '6ba9754f4a5668936976ca7d8f5ec69de30f9aee',
+  'angle_revision': 'c93eeaab15269253593e929abce8cdfea52242ef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'f3a3393a2f96bb8c4cc275ee67921e2b7bddf540',
+  'pdfium_revision': 'f90277e7f4bd99bba419b53341c6c7bdca478eed',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -153,7 +153,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '821833667ccccf83b96b4fdaf2074c6e71f87544',
+  'nacl_revision': 'a87b168e08d3b69241b7f185e5ee3c96ed8bf478',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -165,7 +165,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': '3cb00fbd56816b13ff51170a811a5a2938b32750',
+  'catapult_revision': '9aa552b15750a6d530b34009589ad5d9b4d4ec83',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -213,7 +213,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'd38a0a3b4476798744c4223acbefab3af97698fd',
+  'spv_tools_revision': '2d9a325264e3fc81317acc0a68a098f0546c352d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -552,7 +552,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '06a50f7eab7c303fc962adbadc4e99a9208b83ae',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '94ec5e5e83b994b7361184ba24f17bdc645575c6',
       'condition': 'checkout_linux',
   },
 
@@ -577,7 +577,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2ebf9fdade33fa727490ed8593c3175bf60ab915',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'dd5051fa529e0935fe279279d39cb00cbf856c14',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -781,7 +781,7 @@
     Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'd955c63ec7048d59dffd20af25eeec23da878d27',
 
   'src/third_party/libaom/source/libaom': {
-    'url': Var('aomedia_git') + '/aom.git' + '@' +  'bc484c485277bc19c7a1b273c8cf5472f741b73a',
+    'url': Var('aomedia_git') + '/aom.git' + '@' +  '7a76b645a08ce45ef52dfb7fd719a26c1af1da85',
     'condition': 'checkout_libaom',
   },
 
@@ -925,7 +925,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '1ec93d0df7d1fc69c1901a7a417e50501df28105',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'b4b8aa6ebe724604ac3897b8341032a14ad0d304',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1047,7 +1047,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '21dbf06b5aa6c7dc8cf56314d4a3f96f57956c53',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'eb73a7bd16c725477ca2da6dc0e6fea236616d44',
+    Var('webrtc_git') + '/src.git' + '@' + 'c2342031f4d9c4f55b666115ad2430aec921df9c',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1081,7 +1081,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3cd5de0de3a14991f1133ff77e280b7faa688ea3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@36668c6ef51c6ea84bfffc9d96137008eb2a6e0f',
     'condition': 'checkout_src_internal',
   },
 
@@ -1538,6 +1538,17 @@
       'dep_type': 'cipd',
   },
 
+  'src/third_party/android_deps/libs/com_google_android_play_core': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_android_play_core',
+              'version': 'version:1.3.0-cr0',
+          },
+      ],
+      'condition': 'checkout_android',
+      'dep_type': 'cipd',
+  },
+
   # === ANDROID_DEPS Generated Code End ===
 }
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 78bb258f4..3e7c03a7 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -3323,22 +3323,20 @@
   """Checks that crbug(.com) links are correctly prefixed by https://,
    unless they come in the accepted form TODO(crbug.com/...)
   """
-  white_list = [r'.+%s' % _IMPLEMENTATION_EXTENSIONS]
-  black_list = (_EXCLUDED_PATHS + _TEST_CODE_EXCLUDED_PATHS)
-  sources = lambda f: input_api.FilterSourceFile(
-      f, white_list=white_list, black_list=black_list)
 
-  pattern = input_api.re.compile(r'//.*(?<!:\/\/)crbug[.com]*')
-  accepted_pattern = input_api.re.compile(r'//.*TODO\(crbug[.com]*')
+  # The cr bug strings are split to avoid matching in real presubmit
+  # checkings.
+  pattern = input_api.re.compile(r'//.*(?<!:\/\/)cr''bug[.com]*')
+  accepted_pattern = input_api.re.compile(r'//.*TODO\(cr''bug[.com]*')
   problems = []
-  for f in input_api.AffectedSourceFiles(sources):
+  for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
     for line_num, line in f.ChangedContents():
       if pattern.search(line) and not accepted_pattern.search(line):
         problems.append('    %s:%d %s' % (f.LocalPath(), line_num, line))
 
   if problems:
     return [output_api.PresubmitPromptWarning(
-      'Found unprefixed crbug.com URL(s), consider prepending https://\n'+
+      'Found unprefixed crbug.com URL(s), consider prepending https://\n' +
       '\n'.join(problems))]
   return []
 
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index f1be4edea..ce9e79b6 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -1659,23 +1659,38 @@
     self.assertEqual([], errors)
 
 
-class CrbugUrlFormatTest(unittest.TestCase):
-
-  def testCheckCrbugLinksHaveHttps(self):
+class CheckCrbugLinksHaveHttpsTest(unittest.TestCase):
+  def assertWarningsWithFile(self, content, expected_warnings, file_name):
     input_api = MockInputApi()
     input_api.files = [
-      MockFile('somewhere/file.cc',
-               ['// TODO(developer): crbug.com should be linkified',
-                '// TODO(developer): (crbug.com) should be linkified',
-                '// TODO(developer): crbug/123 should be well formed',
-                '// TODO(developer): http://crbug.com it\'s OK',
-                '// TODO(developer): https://crbug.com is just great',
-                '// TODO(crbug.com/123456): this pattern it\'s also OK']),
+      MockFile(file_name, [content])
     ]
 
     warnings = PRESUBMIT._CheckCrbugLinksHaveHttps(input_api, MockOutputApi())
-    self.assertEqual(1, len(warnings))
-    self.assertEqual(3, warnings[0].message.count('\n'))
+    self.assertEqual(expected_warnings, len(warnings))
+
+  def assertWarnings(self, content, expected_warnings):
+    for f in ['somewhere/file.cc', 'file.java', 'file.py', 'file_test.cc']:
+      self.assertWarningsWithFile(content, expected_warnings, f)
+
+  # The cr bug strings are split to avoid matching in real PRESUBMIT, so meta!
+  def testNoScheme(self):
+    self.assertWarnings('// TODO(dev): cr''bug.com should be linkified', 1)
+
+  def testNoScheme2(self):
+    self.assertWarnings('// TODO(dev): (cr''bug.com) should be linkified', 1)
+
+  def testNoCom(self):
+    self.assertWarnings('// TODO(dev): cr''bug/123 should be well formed', 1)
+
+  def testHttp(self):
+    self.assertWarnings('// TODO(dev): http://cr''bug.com it\'s OK', 0)
+
+  def testHttps(self):
+    self.assertWarnings('// TODO(dev): https://cr''bug.com is just great', 0)
+
+  def testTodo(self):
+    self.assertWarnings('// TODO(cr''bug.com/123456): it\'s also OK', 0)
 
 
 class BannedFunctionCheckTest(unittest.TestCase):
diff --git a/WATCHLISTS b/WATCHLISTS
index 30dfcaf..f07f6ea 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1971,10 +1971,12 @@
                       'msramek+watch@chromium.org'],
     'bubble': ['hcarmona+bubble@chromium.org'],
     'cache_storage': ['nhiroki@chromium.org'],
-    'cast': ['imcheng+watch@chromium.org',
+    'cast': ['aburago+watch@chromium.org',
+             'imcheng+watch@chromium.org',
              'isheriff+watch@chromium.org',
              'jasonroberts+watch@google.com',
              'miu+watch@chromium.org',
+             'pthatcher+watch@chromium.org',
              'xjz+watch@chromium.org'],
     'cast_certificate': ['dougsteed+watch@chromium.org',
                          'mfoltz+watch@chromium.org',
@@ -2178,12 +2180,15 @@
                    'xhwang+watch@chromium.org'],
     'media_recorder': ['emircan+watch+mediarecorder@chromium.org',
                        'mcasas+mediarecorder@chromium.org'],
-    'media_remoting': ['erickung+watch@chromium.org',
+    'media_remoting': ['aburago+watch@chromium.org',
+                       'erickung+watch@chromium.org',
                        'mfoltz+watch@chromium.org',
                        'miu+watch@chromium.org',
+                       'pthatcher+watch@chromium.org',
                        'xjz+watch@chromium.org'],
     'media_router': ['imcheng+watch@chromium.org',
                      'mfoltz+watch@chromium.org',
+                     'pthatcher+watch@chromium.org',
                      'takumif+watch@chromium.org'],
     'media_win': ['media-win-reviews@chromium.org'],
     'memory_coordinator': ['chrome-grc-reviews+memory@chromium.org'],
@@ -2319,6 +2324,7 @@
                'tzik@chromium.org'],
     'tab_alert_indicators': ['miu+watch@chromium.org'],
     'tab_capture': ['miu+watch@chromium.org',
+                    'pthatcher+watch@chromium.org',
                     'xjz+watch@chromium.org'],
     'tab_contents': ['ajwong+watch@chromium.org',
                      'avi@chromium.org',
diff --git a/android_webview/browser/tracing/aw_tracing_delegate.cc b/android_webview/browser/tracing/aw_tracing_delegate.cc
index 6b4cdeb..762495c 100644
--- a/android_webview/browser/tracing/aw_tracing_delegate.cc
+++ b/android_webview/browser/tracing/aw_tracing_delegate.cc
@@ -10,6 +10,7 @@
 #include "base/values.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/trace_uploader.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace android_webview {
 
@@ -17,7 +18,7 @@
 AwTracingDelegate::~AwTracingDelegate() {}
 
 std::unique_ptr<content::TraceUploader> AwTracingDelegate::GetTraceUploader(
-    net::URLRequestContextGetter* request_context) {
+    scoped_refptr<network::SharedURLLoaderFactory>) {
   NOTREACHED();
   return NULL;
 }
diff --git a/android_webview/browser/tracing/aw_tracing_delegate.h b/android_webview/browser/tracing/aw_tracing_delegate.h
index f40f001..27eb2d8 100644
--- a/android_webview/browser/tracing/aw_tracing_delegate.h
+++ b/android_webview/browser/tracing/aw_tracing_delegate.h
@@ -9,6 +9,10 @@
 
 #include "content/public/browser/tracing_delegate.h"
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 namespace android_webview {
 
 class AwTracingDelegate : public content::TracingDelegate {
@@ -18,7 +22,7 @@
 
   // content::TracingDelegate implementation:
   std::unique_ptr<content::TraceUploader> GetTraceUploader(
-      net::URLRequestContextGetter* request_context) override;
+      scoped_refptr<network::SharedURLLoaderFactory> factory) override;
   std::unique_ptr<base::DictionaryValue> GenerateMetadataDict() override;
 };
 
diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc
index 5e096dc..a013738 100644
--- a/android_webview/renderer/aw_render_view_ext.cc
+++ b/android_webview/renderer/aw_render_view_ext.cc
@@ -22,27 +22,18 @@
 }
 
 void AwRenderViewExt::DidCommitCompositorFrame() {
-  PostCheckContentsSize();
+  UpdateContentsSize();
 }
 
 void AwRenderViewExt::DidUpdateMainFrameLayout() {
-  PostCheckContentsSize();
+  UpdateContentsSize();
 }
 
 void AwRenderViewExt::OnDestruct() {
   delete this;
 }
 
-void AwRenderViewExt::PostCheckContentsSize() {
-  if (check_contents_size_timer_.IsRunning())
-    return;
-
-  check_contents_size_timer_.Start(FROM_HERE,
-      base::TimeDelta::FromMilliseconds(0), this,
-      &AwRenderViewExt::CheckContentsSize);
-}
-
-void AwRenderViewExt::CheckContentsSize() {
+void AwRenderViewExt::UpdateContentsSize() {
   blink::WebView* webview = render_view()->GetWebView();
   content::RenderFrame* main_render_frame = render_view()->GetMainRenderFrame();
 
diff --git a/android_webview/renderer/aw_render_view_ext.h b/android_webview/renderer/aw_render_view_ext.h
index 5e68fda..110af566 100644
--- a/android_webview/renderer/aw_render_view_ext.h
+++ b/android_webview/renderer/aw_render_view_ext.h
@@ -27,11 +27,9 @@
   void DidUpdateMainFrameLayout() override;
   void OnDestruct() override;
 
-  void CheckContentsSize();
-  void PostCheckContentsSize();
+  void UpdateContentsSize();
 
   gfx::Size last_sent_contents_size_;
-  base::OneShotTimer check_contents_size_timer_;
 
   DISALLOW_COPY_AND_ASSIGN(AwRenderViewExt);
 };
diff --git a/android_webview/support_library/OWNERS b/android_webview/support_library/OWNERS
index 80aa022f4..9db43a56 100644
--- a/android_webview/support_library/OWNERS
+++ b/android_webview/support_library/OWNERS
@@ -1,4 +1,3 @@
-gsennton@chromium.org
 ntfschr@chromium.org
 torne@chromium.org
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 6c91b45..bf50906 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -324,8 +324,6 @@
     "shell_state.h",
     "shutdown_controller.h",
     "shutdown_reason.h",
-    "sidebar/sidebar.h",
-    "sidebar/sidebar_widget.h",
     "sticky_keys/sticky_keys_controller.h",
     "sticky_keys/sticky_keys_overlay.h",
     "sticky_keys/sticky_keys_state.h",
@@ -604,6 +602,7 @@
     "wm/native_cursor_manager_ash_classic.h",
     "wm/non_client_frame_controller.h",
     "wm/overlay_event_filter.h",
+    "wm/overlay_layout_manager.h",
     "wm/overview/cleanup_animation_observer.h",
     "wm/overview/overview_animation_type.h",
     "wm/overview/overview_utils.h",
@@ -961,8 +960,6 @@
     "shell_state.cc",
     "shutdown_controller.cc",
     "shutdown_reason.cc",
-    "sidebar/sidebar.cc",
-    "sidebar/sidebar_widget.cc",
     "sticky_keys/sticky_keys_controller.cc",
     "sticky_keys/sticky_keys_overlay.cc",
     "system/accessibility/dictation_button_tray.cc",
@@ -1213,6 +1210,7 @@
     "wm/native_cursor_manager_ash_classic.cc",
     "wm/non_client_frame_controller.cc",
     "wm/overlay_event_filter.cc",
+    "wm/overlay_layout_manager.cc",
     "wm/overview/cleanup_animation_observer.cc",
     "wm/overview/overview_utils.cc",
     "wm/overview/overview_window_drag_controller.cc",
@@ -1825,6 +1823,7 @@
     "system/enterprise/tray_enterprise_unittest.cc",
     "system/flag_warning/flag_warning_tray_unittest.cc",
     "system/ime/tray_ime_chromeos_unittest.cc",
+    "system/ime/ime_feature_pod_controller_unittest.cc",
     "system/ime_menu/ime_menu_tray_unittest.cc",
     "system/keyboard_brightness/tray_keyboard_brightness_unittest.cc",
     "system/media_security/multi_profile_media_tray_item_unittest.cc",
@@ -1927,6 +1926,7 @@
     "wm/native_cursor_manager_ash_unittest.cc",
     "wm/non_client_frame_controller_unittest.cc",
     "wm/overlay_event_filter_unittest.cc",
+    "wm/overlay_layout_manager_unittest.cc",
     "wm/overview/cleanup_animation_observer_unittest.cc",
     "wm/overview/window_selector_unittest.cc",
     "wm/resize_shadow_and_cursor_unittest.cc",
diff --git a/ash/DEPS b/ash/DEPS
index 21bb83e..70cb01f 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -131,15 +131,6 @@
   "shell.cc": [
     "+ash/host/ash_window_tree_host_init_params.h"
   ],
-  "shell_port_classic.cc": [
-    "+ash/host/ash_window_tree_host.h",
-    "+ash/host/ash_window_tree_host_init_params.h",
-    "+ui/ozone/public"
-  ],
-  "shell_port_mash\.cc": [
-    "+ash/host/ash_window_tree_host_init_params.h",
-    "+ash/host/ash_window_tree_host_mus.h",
-  ],
   "window_manager.cc": [
     "+ash/host/ash_window_tree_host.h"
   ],
diff --git a/ash/app_list/pagination_model.cc b/ash/app_list/pagination_model.cc
index 5ac15ab..43e30ee 100644
--- a/ash/app_list/pagination_model.cc
+++ b/ash/app_list/pagination_model.cc
@@ -236,7 +236,7 @@
   NotifyTransitionStarted();
   SetTransition(transition);
 
-  transition_animation_.reset(new gfx::SlideAnimation(this));
+  transition_animation_ = std::make_unique<gfx::SlideAnimation>(this);
   transition_animation_->SetDampeningValue(kPageTransitionDurationDampening);
   transition_animation_->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
   transition_animation_->Reset(transition_.progress);
diff --git a/ash/app_list/views/app_list_main_view_unittest.cc b/ash/app_list/views/app_list_main_view_unittest.cc
index 934f031..a6ec296d 100644
--- a/ash/app_list/views/app_list_main_view_unittest.cc
+++ b/ash/app_list/views/app_list_main_view_unittest.cc
@@ -48,7 +48,7 @@
     check_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(50),
                        base::Bind(&GridViewVisibleWaiter::OnTimerCheck,
                                   base::Unretained(this)));
-    run_loop_.reset(new base::RunLoop);
+    run_loop_ = std::make_unique<base::RunLoop>();
     run_loop_->Run();
     check_timer_.Stop();
   }
@@ -82,7 +82,7 @@
     // list (http://crbug.com/759779).
     views::ViewsTestBase::SetUp();
 #if 0
-    delegate_.reset(new AppListTestViewDelegate);
+    delegate_ = std::make_unique<AppListTestViewDelegate>();
     main_view_ = new AppListMainView(delegate_.get(), nullptr);
     main_view_->SetPaintToLayer();
 
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index 2200902..bd74c29 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -143,7 +143,7 @@
   void Initialize(int initial_apps_page,
                   bool is_tablet_mode,
                   bool is_side_shelf) {
-    delegate_.reset(new AppListTestViewDelegate);
+    delegate_ = std::make_unique<AppListTestViewDelegate>();
     view_ = new AppListView(delegate_.get());
     AppListView::InitParams params;
     params.parent = GetContext();
@@ -270,7 +270,7 @@
     }
 
     // Initialize app list view.
-    delegate_.reset(new AppListTestViewDelegate);
+    delegate_ = std::make_unique<AppListTestViewDelegate>();
     view_ = new AppListView(delegate_.get());
     AppListView::InitParams params;
     params.parent = GetContext();
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index f369dc4..95a485e 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -321,7 +321,7 @@
     if (features::IsBackgroundBlurEnabled()) {
       // TODO(newcomer): Improve implementation of the mask layer so we can
       // enable it on all devices crbug.com/765292.
-      fadeout_layer_delegate_.reset(new FadeoutLayerDelegate);
+      fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>();
       layer()->SetMaskLayer(fadeout_layer_delegate_->layer());
     }
 
@@ -335,10 +335,10 @@
 
   pagination_model_.AddObserver(this);
 
-  pagination_controller_.reset(new PaginationController(
+  pagination_controller_ = std::make_unique<PaginationController>(
       &pagination_model_, folder_delegate_
                               ? PaginationController::SCROLL_AXIS_HORIZONTAL
-                              : PaginationController::SCROLL_AXIS_VERTICAL));
+                              : PaginationController::SCROLL_AXIS_VERTICAL);
 }
 
 AppsGridView::~AppsGridView() {
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index f0feeab..0078e62 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -70,7 +70,7 @@
     DCHECK(!wait_);
     wait_ = true;
 
-    ui_run_loop_.reset(new base::RunLoop);
+    ui_run_loop_ = std::make_unique<base::RunLoop>();
     ui_run_loop_->Run();
     wait_ = false;
   }
@@ -212,7 +212,7 @@
     gfx::NativeView parent = GetContext();
     // Ensure that parent is big enough to show the full AppListView.
     parent->SetBounds(gfx::Rect(gfx::Point(0, 0), gfx::Size(1024, 768)));
-    delegate_.reset(new AppListTestViewDelegate);
+    delegate_ = std::make_unique<AppListTestViewDelegate>();
     app_list_view_ = new AppListView(delegate_.get());
     AppListView::InitParams params;
     params.parent = parent;
@@ -241,7 +241,7 @@
     app_list_view_->SetState(AppListViewState::FULLSCREEN_ALL_APPS);
     app_list_view_->Layout();
 
-    test_api_.reset(new AppsGridViewTestApi(apps_grid_view_));
+    test_api_ = std::make_unique<AppsGridViewTestApi>(apps_grid_view_);
   }
   void TearDown() override {
     app_list_view_->GetWidget()->Close();
diff --git a/ash/app_list/views/expand_arrow_view.cc b/ash/app_list/views/expand_arrow_view.cc
index 2c701f5..e42c9a5 100644
--- a/ash/app_list/views/expand_arrow_view.cc
+++ b/ash/app_list/views/expand_arrow_view.cc
@@ -108,7 +108,7 @@
 
   SetAccessibleName(l10n_util::GetStringUTF16(IDS_APP_LIST_EXPAND_BUTTON));
 
-  animation_.reset(new gfx::SlideAnimation(this));
+  animation_ = std::make_unique<gfx::SlideAnimation>(this);
   animation_->SetTweenType(gfx::Tween::LINEAR);
   animation_->SetSlideDuration(kCycleDurationInMs * 2 + kCycleIntervalInMs);
   ResetHintingAnimation();
diff --git a/ash/app_list/views/horizontal_page_container.cc b/ash/app_list/views/horizontal_page_container.cc
index 0ac3349..8e70d17 100644
--- a/ash/app_list/views/horizontal_page_container.cc
+++ b/ash/app_list/views/horizontal_page_container.cc
@@ -23,8 +23,8 @@
   pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs,
                                            kOverscrollPageTransitionDurationMs);
   pagination_model_.AddObserver(this);
-  pagination_controller_.reset(new PaginationController(
-      &pagination_model_, PaginationController::SCROLL_AXIS_HORIZONTAL));
+  pagination_controller_ = std::make_unique<PaginationController>(
+      &pagination_model_, PaginationController::SCROLL_AXIS_HORIZONTAL);
 
   // Add horizontal pages.
   apps_container_view_ = new AppsContainerView(contents_view_, model);
diff --git a/ash/app_list/views/search_box_view_unittest.cc b/ash/app_list/views/search_box_view_unittest.cc
index af69a7e0..8f38756 100644
--- a/ash/app_list/views/search_box_view_unittest.cc
+++ b/ash/app_list/views/search_box_view_unittest.cc
@@ -70,7 +70,8 @@
     app_list_view()->Initialize(params);
 
     widget_ = CreateTopLevelPlatformWidget();
-    view_.reset(new SearchBoxView(this, &view_delegate_, app_list_view()));
+    view_ =
+        std::make_unique<SearchBoxView>(this, &view_delegate_, app_list_view());
     view_->Init();
     widget_->SetBounds(gfx::Rect(0, 0, 300, 200));
     counter_view_ = new KeyPressCounterView(app_list_view_);
diff --git a/ash/app_list/views/search_result_list_view_unittest.cc b/ash/app_list/views/search_result_list_view_unittest.cc
index 43d6736e..614aced 100644
--- a/ash/app_list/views/search_result_list_view_unittest.cc
+++ b/ash/app_list/views/search_result_list_view_unittest.cc
@@ -36,7 +36,7 @@
   // Overridden from testing::Test:
   void SetUp() override {
     views::ViewsTestBase::SetUp();
-    view_.reset(new SearchResultListView(nullptr, &view_delegate_));
+    view_ = std::make_unique<SearchResultListView>(nullptr, &view_delegate_);
     view_->SetResults(view_delegate_.GetSearchModel()->results());
   }
 
diff --git a/ash/app_list/views/search_result_page_view_unittest.cc b/ash/app_list/views/search_result_page_view_unittest.cc
index e271f953..5c008c4 100644
--- a/ash/app_list/views/search_result_page_view_unittest.cc
+++ b/ash/app_list/views/search_result_page_view_unittest.cc
@@ -66,7 +66,7 @@
     ASSERT_EQ(test_with_answer_card, features::IsAnswerCardEnabled());
 
     // Setting up views.
-    delegate_.reset(new AppListTestViewDelegate);
+    delegate_ = std::make_unique<AppListTestViewDelegate>();
     app_list_view_ = new AppListView(delegate_.get());
     AppListView::InitParams params;
     params.parent = GetContext();
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 0778d93..5e1a98dc 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1505,7 +1505,7 @@
         Not recognized
       </message>
       <message name="IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_DISABLED_MESSAGE" desc="Text shown in the user pod to tell user that fingerprint unlock has reached maximum attempt">
-        Too many attempts. Try again later.
+        Too many attempts
       </message>
       <message name="IDS_ASH_LOGIN_TAKE_BREAK_MESSAGE" desc="Message shown to user when unlocking the device is not allowed because the time limit of using the device has reached.">
         Take a break!
diff --git a/ash/assistant/assistant_controller.cc b/ash/assistant/assistant_controller.cc
index 7c23e60..a4e6173a 100644
--- a/ash/assistant/assistant_controller.cc
+++ b/ash/assistant/assistant_controller.cc
@@ -21,7 +21,8 @@
 namespace ash {
 
 AssistantController::AssistantController()
-    : assistant_interaction_controller_(
+    : assistant_volume_control_binding_(this),
+      assistant_interaction_controller_(
           std::make_unique<AssistantInteractionController>(this)),
       assistant_notification_controller_(
           std::make_unique<AssistantNotificationController>(this)),
@@ -36,9 +37,11 @@
 
   AddObserver(this);
   NotifyConstructed();
+  chromeos::CrasAudioHandler::Get()->AddAudioObserver(this);
 }
 
 AssistantController::~AssistantController() {
+  chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this);
   NotifyDestroying();
   RemoveObserver(this);
 }
@@ -48,6 +51,11 @@
   assistant_controller_bindings_.AddBinding(this, std::move(request));
 }
 
+void AssistantController::BindRequest(
+    mojom::AssistantVolumeControlRequest request) {
+  assistant_volume_control_binding_.Bind(std::move(request));
+}
+
 void AssistantController::AddObserver(AssistantControllerObserver* observer) {
   observers_.AddObserver(observer);
 }
@@ -189,6 +197,40 @@
   OpenUrl(url);
 }
 
+void AssistantController::SetVolume(int volume, bool user_initiated) {
+  volume = std::min(100, volume);
+  volume = std::max(volume, 0);
+  chromeos::CrasAudioHandler::Get()->SetOutputVolumePercent(volume);
+}
+
+void AssistantController::SetMuted(bool muted) {
+  chromeos::CrasAudioHandler::Get()->SetOutputMute(muted);
+}
+
+void AssistantController::AddVolumeObserver(mojom::VolumeObserverPtr observer) {
+  volume_observer_.AddPtr(std::move(observer));
+
+  int output_volume =
+      chromeos::CrasAudioHandler::Get()->GetOutputVolumePercent();
+  bool mute = chromeos::CrasAudioHandler::Get()->IsOutputMuted();
+  OnOutputMuteChanged(mute, false /* system_adjust */);
+  OnOutputNodeVolumeChanged(0 /* node */, output_volume);
+}
+
+void AssistantController::OnOutputMuteChanged(bool mute_on,
+                                              bool system_adjust) {
+  volume_observer_.ForAllPtrs([mute_on](mojom::VolumeObserver* observer) {
+    observer->OnMuteStateChanged(mute_on);
+  });
+}
+
+void AssistantController::OnOutputNodeVolumeChanged(uint64_t node, int volume) {
+  // |node| refers to the active volume device, which we don't care here.
+  volume_observer_.ForAllPtrs([volume](mojom::VolumeObserver* observer) {
+    observer->OnVolumeChanged(volume);
+  });
+}
+
 void AssistantController::OpenUrl(const GURL& url) {
   if (assistant::util::IsDeepLinkUrl(url)) {
     NotifyDeepLinkReceived(url);
diff --git a/ash/assistant/assistant_controller.h b/ash/assistant/assistant_controller.h
index add8f73..6bdcdc5 100644
--- a/ash/assistant/assistant_controller.h
+++ b/ash/assistant/assistant_controller.h
@@ -14,13 +14,16 @@
 #include "ash/public/interfaces/assistant_controller.mojom.h"
 #include "ash/public/interfaces/assistant_image_downloader.mojom.h"
 #include "ash/public/interfaces/assistant_setup.mojom.h"
+#include "ash/public/interfaces/assistant_volume_control.mojom.h"
 #include "ash/public/interfaces/voice_interaction_controller.mojom.h"
 #include "ash/public/interfaces/web_contents_manager.mojom.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/services/assistant/public/mojom/assistant.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace base {
@@ -38,12 +41,15 @@
     : public mojom::AssistantController,
       public AssistantControllerObserver,
       public mojom::ManagedWebContentsOpenUrlDelegate,
-      public mojom::VoiceInteractionObserver {
+      public mojom::VoiceInteractionObserver,
+      public mojom::AssistantVolumeControl,
+      public chromeos::CrasAudioHandler::AudioObserver {
  public:
   AssistantController();
   ~AssistantController() override;
 
   void BindRequest(mojom::AssistantControllerRequest request);
+  void BindRequest(mojom::AssistantVolumeControlRequest request);
 
   // Adds/removes the specified |observer|.
   void AddObserver(AssistantControllerObserver* observer);
@@ -95,6 +101,15 @@
   // mojom::ManagedWebContentsOpenUrlDelegate:
   void OnOpenUrlFromTab(const GURL& url) override;
 
+  // mojom::VolumeControl:
+  void SetVolume(int volume, bool user_initiated) override;
+  void SetMuted(bool muted) override;
+  void AddVolumeObserver(mojom::VolumeObserverPtr observer) override;
+
+  // chromeos::CrasAudioHandler::AudioObserver:
+  void OnOutputMuteChanged(bool mute_on, bool system_adjust) override;
+  void OnOutputNodeVolumeChanged(uint64_t node, int volume) override;
+
   // Opens the specified |url| in a new browser tab.
   // TODO(dmblack): Support opening specific URLs in the Assistant container.
   void OpenUrl(const GURL& url);
@@ -146,6 +161,10 @@
   mojo::BindingSet<mojom::ManagedWebContentsOpenUrlDelegate>
       web_contents_open_url_delegate_bindings_;
 
+  mojo::Binding<mojom::AssistantVolumeControl>
+      assistant_volume_control_binding_;
+  mojo::InterfacePtrSet<mojom::VolumeObserver> volume_observer_;
+
   chromeos::assistant::mojom::AssistantPtr assistant_;
 
   mojom::AssistantImageDownloaderPtr assistant_image_downloader_;
diff --git a/ash/assistant/ui/assistant_mini_view.cc b/ash/assistant/ui/assistant_mini_view.cc
index 0917078..43a2436f 100644
--- a/ash/assistant/ui/assistant_mini_view.cc
+++ b/ash/assistant/ui/assistant_mini_view.cc
@@ -24,7 +24,10 @@
 
 // Appearance.
 constexpr int kIconSizeDip = 20;
+constexpr int kLineHeightDip = 20;
 constexpr int kMaxWidthDip = 512;
+constexpr int kPaddingLeftDip = 14;
+constexpr int kPaddingRightDip = 24;
 constexpr int kPreferredHeightDip = 48;
 
 }  // namespace
@@ -62,7 +65,8 @@
   views::BoxLayout* layout_manager =
       SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal,
-          gfx::Insets(0, kPaddingDip), 2 * kSpacingDip));
+          gfx::Insets(0, kPaddingLeftDip, 0, kPaddingRightDip),
+          2 * kSpacingDip));
 
   layout_manager->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
@@ -76,9 +80,11 @@
 
   // Label.
   label_->SetAutoColorReadabilityEnabled(false);
+  label_->SetEnabledColor(kTextColorPrimary);
   label_->SetFontList(
-      assistant::ui::GetDefaultFontList().DeriveWithSizeDelta(4));
+      assistant::ui::GetDefaultFontList().DeriveWithSizeDelta(1));
   label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
+  label_->SetLineHeight(kLineHeightDip);
   AddChildView(label_);
 
   // Trigger input modality changed event to initialize view state.
diff --git a/ash/assistant/ui/assistant_ui_constants.h b/ash/assistant/ui/assistant_ui_constants.h
index 02a3825..1fa8764 100644
--- a/ash/assistant/ui/assistant_ui_constants.h
+++ b/ash/assistant/ui/assistant_ui_constants.h
@@ -32,7 +32,7 @@
 // TODO(dmblack): Remove when enabling. This is used to gate aspects of the
 // motion spec which are being developed in pieces which should be enabled
 // together.
-constexpr bool kIsMotionSpecEnabled = false;
+constexpr bool kIsMotionSpecEnabled = true;
 
 // Returns the default font list for Assistant UI.
 const gfx::FontList& GetDefaultFontList();
diff --git a/ash/assistant/ui/main_stage/assistant_main_stage.cc b/ash/assistant/ui/main_stage/assistant_main_stage.cc
index e9da888b..adaf2688 100644
--- a/ash/assistant/ui/main_stage/assistant_main_stage.cc
+++ b/ash/assistant/ui/main_stage/assistant_main_stage.cc
@@ -602,8 +602,8 @@
       views::CreateEmptyBorder(top_padding, 0, 0, 0));
 
   // Force a layout/paint pass.
-  content_layout_container_->Layout();
-  content_layout_container_->SchedulePaint();
+  ui_element_container_->Layout();
+  ui_element_container_->SchedulePaint();
 
   // Apply top padding to the overlay layout container by applying an empty
   // border to its children.
diff --git a/ash/assistant/util/deep_link_util.cc b/ash/assistant/util/deep_link_util.cc
index eeabc42..4f1478ed 100644
--- a/ash/assistant/util/deep_link_util.cc
+++ b/ash/assistant/util/deep_link_util.cc
@@ -40,8 +40,8 @@
 constexpr char kAssistantRemindersWebUrl[] = R"(data:text/html,
   <html>
     <body style="font-family:Google Sans,sans-serif;padding:0 32px;">
-      <h3>Assistant Reminders</h3>
-      <p>Coming soon. Meanwhile, please use your Android/iOS phone to access reminders.</p>
+      <h3>Google Assistant Reminders</h3>
+      <p>Please use your phone to access Reminders.</p>
     </body>
   </html>
 )";
@@ -50,8 +50,8 @@
 constexpr char kAssistantSettingsWebUrl[] = R"(data:text/html,
   <html>
     <body style="font-family:Google Sans,sans-serif;padding:0 32px;">
-      <h3>Assistant Settings</h3>
-      <p>Coming soon. Meanwhile, please use your Android/iOS phone to access settings.</p>
+      <h3>Google Assistant Settings</h3>
+      <p>Please use your phone to access Settings.</p>
     </body>
   </html>
 )";
diff --git a/ash/frame/header_view.cc b/ash/frame/header_view.cc
index 5afacb4..20b1089 100644
--- a/ash/frame/header_view.cc
+++ b/ash/frame/header_view.cc
@@ -250,8 +250,7 @@
 void HeaderView::OnTabletModeEnded() {
   caption_button_container_->UpdateCaptionButtonState(true /*=animate*/);
   parent()->Layout();
-  if (target_widget_->non_client_view())
-    target_widget_->non_client_view()->Layout();
+  target_widget_->non_client_view()->Layout();
 }
 
 void HeaderView::OnWindowPropertyChanged(aura::Window* window,
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index 38d36f18..cfce5b6 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -285,6 +285,16 @@
   NOTIMPLEMENTED();
 }
 
+void LoginScreenController::ShowWarningBanner(const base::string16& message) {
+  if (DataDispatcher())
+    DataDispatcher()->ShowWarningBanner(message);
+}
+
+void LoginScreenController::HideWarningBanner() {
+  if (DataDispatcher())
+    DataDispatcher()->HideWarningBanner();
+}
+
 void LoginScreenController::ClearErrors() {
   NOTIMPLEMENTED();
 }
@@ -306,8 +316,8 @@
     proximity_auth::mojom::AuthType auth_type,
     const base::string16& initial_value) {
   if (auth_type == proximity_auth::mojom::AuthType::USER_CLICK) {
-    DataDispatcher()->SetClickToUnlockEnabledForUser(account_id,
-                                                     true /*enabled*/);
+    DataDispatcher()->SetTapToUnlockEnabledForUser(account_id,
+                                                   true /*enabled*/);
   } else if (auth_type == proximity_auth::mojom::AuthType::ONLINE_SIGN_IN) {
     DataDispatcher()->SetForceOnlineSignInForUser(account_id);
   } else {
@@ -415,10 +425,8 @@
 }
 
 void LoginScreenController::NotifyOobeDialogVisibility(bool visible) {
-  Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
-      ->shelf_widget()
-      ->login_shelf_view()
-      ->SetLoginDialogVisible(visible);
+  for (auto& observer : observers_)
+    observer.OnOobeDialogVisibilityChanged(visible);
 }
 
 void LoginScreenController::SetAddUserButtonEnabled(bool enable) {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index 4e70e5e..3d36477 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -105,6 +105,8 @@
                         const std::string& error_text,
                         const std::string& help_link_text,
                         int32_t help_topic_id) override;
+  void ShowWarningBanner(const base::string16& message) override;
+  void HideWarningBanner() override;
   void ClearErrors() override;
   void ShowUserPodCustomIcon(const AccountId& account_id,
                              mojom::EasyUnlockIconOptionsPtr icon) override;
diff --git a/ash/login/login_screen_controller_observer.cc b/ash/login/login_screen_controller_observer.cc
index faf86b5..5b84343 100644
--- a/ash/login/login_screen_controller_observer.cc
+++ b/ash/login/login_screen_controller_observer.cc
@@ -2,10 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/login/login_screen_controller_observer.h"
+
 #include "ash/login/login_screen_controller.h"
 
 namespace ash {
 
 LoginScreenControllerObserver::~LoginScreenControllerObserver() = default;
 
+void LoginScreenControllerObserver::SetAvatarForUser(
+    const AccountId& account_id,
+    const mojom::UserAvatarPtr& avatar) {}
+
+void LoginScreenControllerObserver::OnFocusLeavingLockScreenApps(bool reverse) {
+}
+
+void LoginScreenControllerObserver::OnOobeDialogVisibilityChanged(
+    bool visible) {}
+
 }  // namespace ash
diff --git a/ash/login/login_screen_controller_observer.h b/ash/login/login_screen_controller_observer.h
index bd511dbc..0d5f10cb 100644
--- a/ash/login/login_screen_controller_observer.h
+++ b/ash/login/login_screen_controller_observer.h
@@ -20,11 +20,14 @@
 
   // Called when |avatar| for |account_id| has changed.
   virtual void SetAvatarForUser(const AccountId& account_id,
-                                const mojom::UserAvatarPtr& avatar) = 0;
+                                const mojom::UserAvatarPtr& avatar);
 
   // Called when focus is leaving a lock screen app window due to tabbing.
   // |reverse| - whether the tab order is reversed.
-  virtual void OnFocusLeavingLockScreenApps(bool reverse) = 0;
+  virtual void OnFocusLeavingLockScreenApps(bool reverse);
+
+  // Called when the visibility state of the OOBE dialog is changed.
+  virtual void OnOobeDialogVisibilityChanged(bool visible);
 };
 
 }  // namespace ash
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index af79f59..42002421 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -25,6 +25,7 @@
 #include "ash/login/ui/note_action_launch_button.h"
 #include "ash/login/ui/scrollable_users_list_view.h"
 #include "ash/login/ui/views_utils.h"
+#include "ash/public/cpp/ash_switches.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_widget.h"
@@ -33,6 +34,7 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_delegate.h"
 #include "ash/system/tray/system_tray_notifier.h"
+#include "base/command_line.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -299,6 +301,10 @@
   return view_->detachable_base_error_bubble_.get();
 }
 
+LoginBubble* LockContentsView::TestApi::warning_banner_bubble() const {
+  return view_->warning_banner_bubble_.get();
+}
+
 views::View* LockContentsView::TestApi::dev_channel_info() const {
   return view_->dev_channel_info_;
 }
@@ -347,6 +353,7 @@
   auth_error_bubble_ = std::make_unique<LoginBubble>();
   detachable_base_error_bubble_ = std::make_unique<LoginBubble>();
   tooltip_bubble_ = std::make_unique<LoginBubble>();
+  warning_banner_bubble_ = std::make_unique<LoginBubble>();
 
   // We reuse the focusable state on this view as a signal that focus should
   // switch to the system tray. LockContentsView should otherwise not be
@@ -543,6 +550,7 @@
   // The debug view will potentially call this method many times. Make sure to
   // invalidate any child references.
   main_view_->RemoveAllChildViews(true /*delete_children*/);
+  primary_big_view_ = nullptr;
   opt_secondary_big_view_ = nullptr;
   users_list_ = nullptr;
   layout_actions_.clear();
@@ -636,9 +644,8 @@
   }
 }
 
-void LockContentsView::OnClickToUnlockEnabledForUserChanged(
-    const AccountId& user,
-    bool enabled) {
+void LockContentsView::OnTapToUnlockEnabledForUserChanged(const AccountId& user,
+                                                          bool enabled) {
   LockContentsView::UserState* state = FindStateForUser(user);
   if (!state) {
     LOG(ERROR) << "Unable to find user enabling click to auth";
@@ -689,6 +696,31 @@
   }
 }
 
+void LockContentsView::OnShowWarningBanner(const base::string16& message) {
+  DCHECK(!message.empty());
+  if (!CurrentBigUserView() || !CurrentBigUserView()->auth_user()) {
+    LOG(ERROR) << "Unable to find the current active big user to show a "
+                  "warning banner.";
+    return;
+  }
+  warning_banner_bubble_->Close();
+  // Shows warning banner as a persistent error bubble.
+  views::Label* label =
+      new views::Label(message, views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT,
+                       views::style::STYLE_PRIMARY);
+  label->SetMultiLine(true);
+  label->SetAutoColorReadabilityEnabled(false);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetEnabledColor(SK_ColorWHITE);
+  warning_banner_bubble_->ShowErrorBubble(
+      label, CurrentBigUserView()->auth_user()->password_view() /*anchor_view*/,
+      LoginBubble::kFlagPersistent);
+}
+
+void LockContentsView::OnHideWarningBanner() {
+  warning_banner_bubble_->Close();
+}
+
 void LockContentsView::OnLockScreenNoteStateChanged(
     mojom::TrayActionState state) {
   if (disable_lock_screen_note_)
@@ -887,6 +919,11 @@
     FindFirstOrLastFocusableChild(this, reverse)->RequestFocus();
 }
 
+void LockContentsView::OnOobeDialogVisibilityChanged(bool visible) {
+  if (!visible && primary_big_view_)
+    primary_big_view_->RequestFocus();
+}
+
 void LockContentsView::OnFocusLeavingSystemTray(bool reverse) {
   // This function is called when the system tray is losing focus. We want to
   // focus the first or last child in this view, or a lock screen app window if
@@ -1422,7 +1459,7 @@
         CurrentBigUserView()->GetCurrentUser()->basic_user_info->account_id;
     Shell::Get()->login_screen_controller()->HardlockPod(user);
     // TODO(jdufault): This should get called as a result of HardlockPod.
-    OnClickToUnlockEnabledForUserChanged(user, false /*enabled*/);
+    OnTapToUnlockEnabledForUserChanged(user, false /*enabled*/);
   }
 }
 
@@ -1603,9 +1640,15 @@
       AcceleratorAction::kFocusNextUser;
   accel_map_[ui::Accelerator(ui::VKEY_LEFT, 0)] =
       AcceleratorAction::kFocusPreviousUser;
-  accel_map_[ui::Accelerator(
-      ui::VKEY_R, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)] =
-      AcceleratorAction::kShowResetScreen;
+
+  // Show reset conflicts with rotate screen when --ash-dev-shortcuts is passed.
+  // Favor --ash-dev-shortcuts since that is explicitly added.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshDeveloperShortcuts)) {
+    accel_map_[ui::Accelerator(
+        ui::VKEY_R, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN |
+                        ui::EF_ALT_DOWN)] = AcceleratorAction::kShowResetScreen;
+  }
 
   AcceleratorController* controller = Shell::Get()->accelerator_controller();
   for (const auto& item : accel_map_)
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 38df4973..ebaf06e 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -84,6 +84,7 @@
     LoginBubble* tooltip_bubble() const;
     LoginBubble* auth_error_bubble() const;
     LoginBubble* detachable_base_error_bubble() const;
+    LoginBubble* warning_banner_bubble() const;
     views::View* dev_channel_info() const;
     LoginExpandedPublicAccountView* expanded_view() const;
     views::View* main_view() const;
@@ -135,6 +136,7 @@
   void SetAvatarForUser(const AccountId& account_id,
                         const mojom::UserAvatarPtr& avatar) override;
   void OnFocusLeavingLockScreenApps(bool reverse) override;
+  void OnOobeDialogVisibilityChanged(bool visible) override;
 
   // LoginDataDispatcher::Observer:
   void OnUsersChanged(
@@ -145,12 +147,14 @@
       bool enabled,
       const base::Optional<base::Time>& auth_reenabled_time) override;
   void OnLockScreenNoteStateChanged(mojom::TrayActionState state) override;
-  void OnClickToUnlockEnabledForUserChanged(const AccountId& user,
-                                            bool enabled) override;
+  void OnTapToUnlockEnabledForUserChanged(const AccountId& user,
+                                          bool enabled) override;
   void OnForceOnlineSignInForUser(const AccountId& user) override;
   void OnShowEasyUnlockIcon(
       const AccountId& user,
       const mojom::EasyUnlockIconOptionsPtr& icon) override;
+  void OnShowWarningBanner(const base::string16& message) override;
+  void OnHideWarningBanner() override;
   void OnDevChannelInfoChanged(const std::string& os_version_label_text,
                                const std::string& enterprise_info_text,
                                const std::string& bluetooth_name) override;
@@ -387,6 +391,9 @@
 
   std::unique_ptr<LoginBubble> tooltip_bubble_;
 
+  // Bubble for displaying warning banner message.
+  std::unique_ptr<LoginBubble> warning_banner_bubble_;
+
   int unlock_attempt_ = 0;
 
   // Whether a lock screen app is currently active (i.e. lock screen note action
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc
index d9e275b2..ed7d6fb 100644
--- a/ash/login/ui/lock_contents_view_unittest.cc
+++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -1823,4 +1823,51 @@
           ->visible());
 }
 
+TEST_F(LockContentsViewUnitTest, ShowHideWarningBannerBubble) {
+  // Build lock screen with a single user.
+  auto* lock = new LockContentsView(
+      mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLock,
+      data_dispatcher(),
+      std::make_unique<FakeLoginDetachableBaseModel>(data_dispatcher()));
+  SetUserCount(1);
+  SetWidget(CreateWidgetWithContent(lock));
+
+  const AccountId& kUserAccountId = users()[0]->basic_user_info->account_id;
+
+  LockContentsView::TestApi test_api(lock);
+  ui::test::EventGenerator* generator = GetEventGenerator();
+
+  // Creating lock screen does not show warning banner bubble.
+  EXPECT_FALSE(test_api.warning_banner_bubble()->IsVisible());
+
+  // Verifies that a warning banner is shown by giving a non-empty message.
+  data_dispatcher()->ShowWarningBanner(base::ASCIIToUTF16("foo"));
+  EXPECT_TRUE(test_api.warning_banner_bubble()->IsVisible());
+
+  // Verifies that a warning banner is hidden by HideWarningBanner().
+  data_dispatcher()->HideWarningBanner();
+  EXPECT_FALSE(test_api.warning_banner_bubble()->IsVisible());
+
+  // Shows a warning banner again.
+  data_dispatcher()->ShowWarningBanner(base::ASCIIToUTF16("foo"));
+  EXPECT_TRUE(test_api.warning_banner_bubble()->IsVisible());
+
+  // Attempt and fail user auth - an auth error is expected to be shown.
+  // The warning banner should not be hidden.
+  std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient();
+  client->set_authenticate_user_callback_result(false);
+  EXPECT_CALL(*client, AuthenticateUser_(kUserAccountId, _, false, _));
+
+  // Submit password.
+  LoginAuthUserView::TestApi(test_api.primary_big_view()->auth_user())
+      .password_view()
+      ->RequestFocus();
+  generator->PressKey(ui::KeyboardCode::VKEY_A, 0);
+  generator->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(test_api.auth_error_bubble()->IsVisible());
+  EXPECT_TRUE(test_api.warning_banner_bubble()->IsVisible());
+}
+
 }  // namespace ash
diff --git a/ash/login/ui/lock_debug_view.cc b/ash/login/ui/lock_debug_view.cc
index 0550fb9..5b89fce0 100644
--- a/ash/login/ui/lock_debug_view.cc
+++ b/ash/login/ui/lock_debug_view.cc
@@ -50,7 +50,9 @@
   kGlobalCycleDetachableBaseStatus,
   kGlobalCycleDetachableBaseId,
   kGlobalCycleAuthErrorMessage,
+  kGlobalToggleWarningBanner,
   kPerUserTogglePin,
+  kPerUserToggleTap,
   kPerUserCycleEasyUnlockState,
   kPerUserCycleFingerprintState,
   kPerUserForceOnlineSignIn,
@@ -94,7 +96,7 @@
   AccountId account_id;
   std::string display_name;
   bool enable_pin = false;
-  bool enable_click_to_unlock = false;
+  bool enable_tap_to_unlock = false;
   bool enable_auth = true;
   user_manager::UserType type = user_manager::USER_TYPE_REGULAR;
   mojom::EasyUnlockIconId easy_unlock_id = mojom::EasyUnlockIconId::NONE;
@@ -250,6 +252,15 @@
                                            debug_user->enable_pin);
   }
 
+  // Activates or deactivates tap unlock for the user at |user_index|.
+  void ToggleTapStateForUserIndex(size_t user_index) {
+    DCHECK(user_index >= 0 && user_index < debug_users_.size());
+    UserMetadata* debug_user = &debug_users_[user_index];
+    debug_user->enable_tap_to_unlock = !debug_user->enable_tap_to_unlock;
+    debug_dispatcher_.SetTapToUnlockEnabledForUser(
+        debug_user->account_id, debug_user->enable_tap_to_unlock);
+  }
+
   // Enables click to auth for the user at |user_index|.
   void CycleEasyUnlockForUserIndex(size_t user_index) {
     DCHECK(user_index >= 0 && user_index < debug_users_.size());
@@ -278,7 +289,7 @@
     debug_user->easy_unlock_id = get_next_id(debug_user->easy_unlock_id);
 
     // Enable/disable click to unlock.
-    debug_user->enable_click_to_unlock =
+    debug_user->enable_tap_to_unlock =
         debug_user->easy_unlock_id == mojom::EasyUnlockIconId::UNLOCKED;
 
     // Prepare icon that we will show.
@@ -300,8 +311,8 @@
 
     // Show icon and enable/disable click to unlock.
     debug_dispatcher_.ShowEasyUnlockIcon(debug_user->account_id, icon);
-    debug_dispatcher_.SetClickToUnlockEnabledForUser(
-        debug_user->account_id, debug_user->enable_click_to_unlock);
+    debug_dispatcher_.SetTapToUnlockEnabledForUser(
+        debug_user->account_id, debug_user->enable_tap_to_unlock);
   }
 
   // Enables fingerprint auth for the user at |user_index|.
@@ -399,6 +410,12 @@
                                         bluetooth_name);
   }
 
+  void ShowWarningBanner(const base::string16& message) {
+    debug_dispatcher_.ShowWarningBanner(message);
+  }
+
+  void HideWarningBanner() { debug_dispatcher_.HideWarningBanner(); }
+
   // LoginDataDispatcher::Observer:
   void OnUsersChanged(
       const std::vector<mojom::LoginUserInfoPtr>& users) override {
@@ -423,13 +440,13 @@
       }
     }
   }
-  void OnClickToUnlockEnabledForUserChanged(const AccountId& user,
-                                            bool enabled) override {
+  void OnTapToUnlockEnabledForUserChanged(const AccountId& user,
+                                          bool enabled) override {
     // Forward notification only if the user is currently being shown.
     for (size_t i = 0u; i < debug_users_.size(); ++i) {
       if (debug_users_[i].account_id == user) {
-        debug_users_[i].enable_click_to_unlock = enabled;
-        debug_dispatcher_.SetClickToUnlockEnabledForUser(user, enabled);
+        debug_users_[i].enable_tap_to_unlock = enabled;
+        debug_dispatcher_.SetTapToUnlockEnabledForUser(user, enabled);
         break;
       }
     }
@@ -663,6 +680,8 @@
       "Auth (allowed)", ButtonId::kGlobalToggleAuth, toggle_container);
   AddButton("Cycle auth error", ButtonId::kGlobalCycleAuthErrorMessage,
             toggle_container);
+  AddButton("Toggle warning banner", ButtonId::kGlobalToggleWarningBanner,
+            toggle_container);
 
   auto* kiosk_container = add_horizontal_container();
   AddButton("Add kiosk app", ButtonId::kGlobalAddKioskApp, kiosk_container);
@@ -895,10 +914,25 @@
     return;
   }
 
+  // Show or hide warning banner.
+  if (sender->id() == ButtonId::kGlobalToggleWarningBanner) {
+    if (is_warning_banner_shown_) {
+      debug_data_dispatcher_->HideWarningBanner();
+    } else {
+      debug_data_dispatcher_->ShowWarningBanner(base::ASCIIToUTF16(
+          "A critical update is ready to install. Sign in to get started."));
+    }
+    is_warning_banner_shown_ = !is_warning_banner_shown_;
+  }
+
   // Enable or disable PIN.
   if (sender->id() == ButtonId::kPerUserTogglePin)
     debug_data_dispatcher_->TogglePinStateForUserIndex(sender->tag());
 
+  // Enable or disable tap.
+  if (sender->id() == ButtonId::kPerUserToggleTap)
+    debug_data_dispatcher_->ToggleTapStateForUserIndex(sender->tag());
+
   // Cycle easy unlock.
   if (sender->id() == ButtonId::kPerUserCycleEasyUnlockState)
     debug_data_dispatcher_->CycleEasyUnlockForUserIndex(sender->tag());
@@ -948,6 +982,7 @@
     row->AddChildView(name);
 
     AddButton("Toggle PIN", ButtonId::kPerUserTogglePin, row)->set_tag(i);
+    AddButton("Toggle Tap", ButtonId::kPerUserToggleTap, row)->set_tag(i);
     AddButton("Cycle easy unlock", ButtonId::kPerUserCycleEasyUnlockState, row)
         ->set_tag(i);
     AddButton("Cycle fingerprint unlock",
diff --git a/ash/login/ui/lock_debug_view.h b/ash/login/ui/lock_debug_view.h
index 5ac5200..bd283d1 100644
--- a/ash/login/ui/lock_debug_view.h
+++ b/ash/login/ui/lock_debug_view.h
@@ -104,6 +104,9 @@
   // error" button is clicked.
   AuthErrorType next_auth_error_type_ = AuthErrorType::kFirstUnlockFailed;
 
+  // True if a warning banner is shown.
+  bool is_warning_banner_shown_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(LockDebugView);
 };
 
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index c7cf136..578afa6 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -491,6 +491,7 @@
   disabled_auth_message_->SetVisible(auth_disabled);
 
   password_view_->SetEnabled(has_password);
+  password_view_->SetEnabledOnEmptyPassword(has_tap);
   password_view_->SetFocusEnabledForChildViews(has_password);
   password_view_->SetVisible(!hide_auth);
   password_view_->layer()->SetOpacity(has_password ? 1 : 0);
diff --git a/ash/login/ui/login_data_dispatcher.cc b/ash/login/ui/login_data_dispatcher.cc
index 417544cd..52011060 100644
--- a/ash/login/ui/login_data_dispatcher.cc
+++ b/ash/login/ui/login_data_dispatcher.cc
@@ -20,7 +20,7 @@
     bool enabled,
     const base::Optional<base::Time>& auth_reenabled_time) {}
 
-void LoginDataDispatcher::Observer::OnClickToUnlockEnabledForUserChanged(
+void LoginDataDispatcher::Observer::OnTapToUnlockEnabledForUserChanged(
     const AccountId& user,
     bool enabled) {}
 
@@ -34,6 +34,11 @@
     const AccountId& user,
     const mojom::EasyUnlockIconOptionsPtr& icon) {}
 
+void LoginDataDispatcher::Observer::OnShowWarningBanner(
+    const base::string16& message) {}
+
+void LoginDataDispatcher::Observer::OnHideWarningBanner() {}
+
 void LoginDataDispatcher::Observer::OnDevChannelInfoChanged(
     const std::string& os_version_label_text,
     const std::string& enterprise_info_text,
@@ -95,10 +100,10 @@
   }
 }
 
-void LoginDataDispatcher::SetClickToUnlockEnabledForUser(const AccountId& user,
-                                                         bool enabled) {
+void LoginDataDispatcher::SetTapToUnlockEnabledForUser(const AccountId& user,
+                                                       bool enabled) {
   for (auto& observer : observers_)
-    observer.OnClickToUnlockEnabledForUserChanged(user, enabled);
+    observer.OnTapToUnlockEnabledForUserChanged(user, enabled);
 }
 
 void LoginDataDispatcher::SetForceOnlineSignInForUser(const AccountId& user) {
@@ -118,6 +123,16 @@
     observer.OnShowEasyUnlockIcon(user, icon);
 }
 
+void LoginDataDispatcher::ShowWarningBanner(const base::string16& message) {
+  for (auto& observer : observers_)
+    observer.OnShowWarningBanner(message);
+}
+
+void LoginDataDispatcher::HideWarningBanner() {
+  for (auto& observer : observers_)
+    observer.OnHideWarningBanner();
+}
+
 void LoginDataDispatcher::SetDevChannelInfo(
     const std::string& os_version_label_text,
     const std::string& enterprise_info_text,
diff --git a/ash/login/ui/login_data_dispatcher.h b/ash/login/ui/login_data_dispatcher.h
index 60e57c3a..b3b7086b 100644
--- a/ash/login/ui/login_data_dispatcher.h
+++ b/ash/login/ui/login_data_dispatcher.h
@@ -57,8 +57,8 @@
         const base::Optional<base::Time>& auth_reenabled_time);
 
     // Called when the given user can click their pod to unlock.
-    virtual void OnClickToUnlockEnabledForUserChanged(const AccountId& user,
-                                                      bool enabled);
+    virtual void OnTapToUnlockEnabledForUserChanged(const AccountId& user,
+                                                    bool enabled);
 
     // Called when |user| must authenticate online (e.g. when OAuth refresh
     // token is revoked).
@@ -72,6 +72,12 @@
         const AccountId& user,
         const mojom::EasyUnlockIconOptionsPtr& icon);
 
+    // Called when a warning banner message should be displayed.
+    virtual void OnShowWarningBanner(const base::string16& message);
+
+    // Called when a warning banner message should be hidden.
+    virtual void OnHideWarningBanner();
+
     // Called when the info shown for dev and canary channels are changed.
     virtual void OnDevChannelInfoChanged(
         const std::string& os_version_label_text,
@@ -121,11 +127,13 @@
   void SetAuthEnabledForUser(const AccountId& account_id,
                              bool is_enabled,
                              base::Optional<base::Time> auth_reenabled_time);
-  void SetClickToUnlockEnabledForUser(const AccountId& user, bool enabled);
+  void SetTapToUnlockEnabledForUser(const AccountId& user, bool enabled);
   void SetForceOnlineSignInForUser(const AccountId& user);
   void SetLockScreenNoteState(mojom::TrayActionState state);
   void ShowEasyUnlockIcon(const AccountId& user,
                           const mojom::EasyUnlockIconOptionsPtr& icon);
+  void ShowWarningBanner(const base::string16& message);
+  void HideWarningBanner();
   void SetDevChannelInfo(const std::string& os_version_label_text,
                          const std::string& enterprise_info_text,
                          const std::string& bluetooth_name);
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 8117ea0..d9da3c53 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -435,6 +435,11 @@
                           on_easy_unlock_icon_tapped);
 }
 
+void LoginPasswordView::SetEnabledOnEmptyPassword(bool enabled) {
+  enabled_on_empty_password_ = enabled;
+  UpdateUiState();
+}
+
 void LoginPasswordView::SetEasyUnlockIcon(
     mojom::EasyUnlockIconId id,
     const base::string16& accessibility_label) {
@@ -509,7 +514,8 @@
 }
 
 bool LoginPasswordView::OnKeyPressed(const ui::KeyEvent& event) {
-  if (event.key_code() == ui::KeyboardCode::VKEY_RETURN) {
+  if (event.key_code() == ui::KeyboardCode::VKEY_RETURN &&
+      submit_button_->enabled()) {
     SubmitPassword();
     return true;
   }
@@ -558,7 +564,8 @@
 }
 
 void LoginPasswordView::UpdateUiState() {
-  bool is_enabled = !textfield_->text().empty() && !textfield_->read_only();
+  bool is_enabled = !textfield_->read_only() &&
+                    (enabled_on_empty_password_ || !textfield_->text().empty());
   submit_button_->SetEnabled(is_enabled);
   SkColor color = is_enabled
                       ? login_constants::kButtonEnabledColor
@@ -575,6 +582,7 @@
 }
 
 void LoginPasswordView::SubmitPassword() {
+  DCHECK(submit_button_->enabled());
   if (textfield_->read_only())
     return;
   on_submit_.Run(textfield_->text());
diff --git a/ash/login/ui/login_password_view.h b/ash/login/ui/login_password_view.h
index 88d821e..536c3c46 100644
--- a/ash/login/ui/login_password_view.h
+++ b/ash/login/ui/login_password_view.h
@@ -75,6 +75,9 @@
             const OnEasyUnlockIconHovered& on_easy_unlock_icon_hovered,
             const OnEasyUnlockIconTapped& on_easy_unlock_icon_tapped);
 
+  // Is the password field enabled when there is no text?
+  void SetEnabledOnEmptyPassword(bool enabled);
+
   // Change the active icon for easy unlock.
   void SetEasyUnlockIcon(mojom::EasyUnlockIconId id,
                          const base::string16& accessibility_label);
@@ -137,6 +140,9 @@
   OnPasswordSubmit on_submit_;
   OnPasswordTextChanged on_password_text_changed_;
 
+  // Is the password field enabled when there is no text?
+  bool enabled_on_empty_password_ = false;
+
   views::View* password_row_ = nullptr;
 
   views::Textfield* textfield_ = nullptr;
diff --git a/ash/manifest.json b/ash/manifest.json
index db6b5c3..75a3ff2 100644
--- a/ash/manifest.json
+++ b/ash/manifest.json
@@ -15,6 +15,7 @@
           "ash.mojom.AppListController",
           "ash.mojom.AshMessageCenterController",
           "ash.mojom.AssistantController",
+          "ash.mojom.AssistantVolumeControl",
           "ash.mojom.CastConfig",
           "ash.mojom.ClientImageRegistry",
           "ash.mojom.CrosDisplayConfigController",
diff --git a/ash/message_center/ash_message_center_lock_screen_controller.cc b/ash/message_center/ash_message_center_lock_screen_controller.cc
index 36e05a4..d9cd14af 100644
--- a/ash/message_center/ash_message_center_lock_screen_controller.cc
+++ b/ash/message_center/ash_message_center_lock_screen_controller.cc
@@ -6,6 +6,7 @@
 
 #include "ash/login/ui/lock_screen.h"
 #include "ash/login/ui/lock_window.h"
+#include "ash/public/cpp/ash_features.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
@@ -19,6 +20,20 @@
 
 namespace ash {
 
+// static
+bool AshMessageCenterLockScreenController::IsEnabled() {
+  return GetMode() != Mode::HIDE;
+}
+
+// static
+AshMessageCenterLockScreenController::Mode
+AshMessageCenterLockScreenController::GetMode() {
+  if (!features::IsLockScreenNotificationsEnabled())
+    return Mode::HIDE;
+
+  return Mode::SHOW;
+}
+
 namespace {
 const char kToastId[] = "ash-lock-screen-manager";
 }  // anonymous namespace
diff --git a/ash/message_center/ash_message_center_lock_screen_controller.h b/ash/message_center/ash_message_center_lock_screen_controller.h
index af735a3d..46ac0c8 100644
--- a/ash/message_center/ash_message_center_lock_screen_controller.h
+++ b/ash/message_center/ash_message_center_lock_screen_controller.h
@@ -17,6 +17,16 @@
     : public message_center::LockScreenController,
       public SessionObserver {
  public:
+  // Modes of the lock screen notification.
+  enum class Mode { HIDE, SHOW, HIDE_SENSITIVE };
+
+  // Returns if the message center shows the notifications on the lock screen
+  // or not. True if it shows, false if doesn't.
+  static ASH_EXPORT bool IsEnabled();
+
+  // Returns the current mode of the lock screen notification.
+  static Mode GetMode();
+
   AshMessageCenterLockScreenController();
   ~AshMessageCenterLockScreenController() override;
 
diff --git a/ash/message_center/message_center_button_bar.cc b/ash/message_center/message_center_button_bar.cc
index 1148f23..d19d3f1e 100644
--- a/ash/message_center/message_center_button_bar.cc
+++ b/ash/message_center/message_center_button_bar.cc
@@ -4,9 +4,9 @@
 
 #include "ash/message_center/message_center_button_bar.h"
 
+#include "ash/message_center/ash_message_center_lock_screen_controller.h"
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/message_center_view.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/tray_constants.h"
@@ -121,7 +121,7 @@
   SetBorder(views::CreateEmptyBorder(kButtonBarBorder));
 
   notification_label_ = new views::Label(
-      GetTitle(!locked || features::IsLockScreenNotificationsEnabled()));
+      GetTitle(!locked || AshMessageCenterLockScreenController::IsEnabled()));
   notification_label_->SetAutoColorReadabilityEnabled(false);
   notification_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   notification_label_->SetEnabledColor(kTextColor);
@@ -272,7 +272,7 @@
 
 void MessageCenterButtonBar::SetIsLocked(bool locked) {
   SetButtonsVisible(locked);
-  UpdateLabel(!locked || features::IsLockScreenNotificationsEnabled());
+  UpdateLabel(!locked || AshMessageCenterLockScreenController::IsEnabled());
 }
 
 base::string16 MessageCenterButtonBar::GetTitle(
@@ -294,7 +294,7 @@
 
 void MessageCenterButtonBar::SetButtonsVisible(bool locked) {
   bool message_center_visible =
-      !locked || features::IsLockScreenNotificationsEnabled();
+      !locked || AshMessageCenterLockScreenController::IsEnabled();
   if (close_all_button_)
     close_all_button_->SetVisible(message_center_visible);
   separator_1_->SetVisible(message_center_visible);
diff --git a/ash/message_center/message_center_view.cc b/ash/message_center/message_center_view.cc
index 9496c08..bba5c357 100644
--- a/ash/message_center/message_center_view.cc
+++ b/ash/message_center/message_center_view.cc
@@ -7,12 +7,11 @@
 #include <list>
 #include <map>
 
+#include "ash/message_center/ash_message_center_lock_screen_controller.h"
 #include "ash/message_center/message_center_button_bar.h"
 #include "ash/message_center/message_center_scroll_bar.h"
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/notifier_settings_view.h"
-#include "ash/public/cpp/ash_features.h"
-#include "ash/public/cpp/ash_switches.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
@@ -189,7 +188,7 @@
     : message_center_(message_center),
       settings_visible_(initially_settings_visible),
       is_locked_(Shell::Get()->session_controller()->IsScreenLocked()) {
-  if (is_locked_ && !features::IsLockScreenNotificationsEnabled())
+  if (is_locked_ && !AshMessageCenterLockScreenController::IsEnabled())
     mode_ = Mode::LOCKED;
   else if (initially_settings_visible)
     mode_ = Mode::SETTINGS;
@@ -577,7 +576,7 @@
 void MessageCenterView::Update(bool animate) {
   bool no_message_views = (message_list_view_->GetNotificationCount() == 0);
 
-  if (is_locked_ && !features::IsLockScreenNotificationsEnabled())
+  if (is_locked_ && !AshMessageCenterLockScreenController::IsEnabled())
     SetVisibilityMode(Mode::LOCKED, animate);
   else if (settings_visible_)
     SetVisibilityMode(Mode::SETTINGS, animate);
diff --git a/ash/message_center/message_center_view_unittest.cc b/ash/message_center/message_center_view_unittest.cc
index 04cd09f..762851e 100644
--- a/ash/message_center/message_center_view_unittest.cc
+++ b/ash/message_center/message_center_view_unittest.cc
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/message_center/ash_message_center_lock_screen_controller.h"
 #include "ash/message_center/message_center_button_bar.h"
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/message_list_view.h"
@@ -236,8 +237,10 @@
 void MessageCenterViewTest::SetUp() {
   AshTestBase::SetUp();
 
-  if (is_lock_screen_notifications_enabled_)
+  if (is_lock_screen_notifications_enabled_) {
     SetLockScreenNotificationsEnabled();
+    ASSERT_TRUE(AshMessageCenterLockScreenController::IsEnabled());
+  }
 
   MessageCenterView::disable_animation_for_testing = true;
   message_center_.reset(new FakeMessageCenterImpl());
@@ -834,8 +837,9 @@
 
   // Lock!
   SetLockedState(true);
-  EXPECT_EQ(features::IsLockScreenNotificationsEnabled() ? Mode::NOTIFICATIONS
-                                                         : Mode::LOCKED,
+  EXPECT_EQ(AshMessageCenterLockScreenController::IsEnabled()
+                ? Mode::NOTIFICATIONS
+                : Mode::LOCKED,
             GetMessageCenterViewInternalMode());
 
   // Unlock!
@@ -848,7 +852,7 @@
 
   // Lock!
   SetLockedState(true);
-  EXPECT_EQ(features::IsLockScreenNotificationsEnabled()
+  EXPECT_EQ(AshMessageCenterLockScreenController::IsEnabled()
                 ? Mode::NO_NOTIFICATIONS
                 : Mode::LOCKED,
             GetMessageCenterViewInternalMode());
@@ -864,13 +868,14 @@
 
   // Lock!
   SetLockedState(true);
-  EXPECT_EQ(features::IsLockScreenNotificationsEnabled() ? Mode::NOTIFICATIONS
-                                                         : Mode::LOCKED,
+  EXPECT_EQ(AshMessageCenterLockScreenController::IsEnabled()
+                ? Mode::NOTIFICATIONS
+                : Mode::LOCKED,
             GetMessageCenterViewInternalMode());
 
   // Remove all existing notifications.
   RemoveDefaultNotifications();
-  EXPECT_EQ(features::IsLockScreenNotificationsEnabled()
+  EXPECT_EQ(AshMessageCenterLockScreenController::IsEnabled()
                 ? Mode::NO_NOTIFICATIONS
                 : Mode::LOCKED,
             GetMessageCenterViewInternalMode());
@@ -902,7 +907,7 @@
   // Lock!
   SetLockedState(true);
 
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
     EXPECT_TRUE(GetNotificationView(kNotificationId2)->IsDrawn());
   } else {
@@ -911,7 +916,7 @@
   }
 
   GetMessageCenterView()->SizeToPreferredSize();
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
     EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
   } else {
@@ -921,7 +926,7 @@
   RemoveNotification(kNotificationId1, false);
 
   GetMessageCenterView()->SizeToPreferredSize();
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
     EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
   } else {
@@ -931,7 +936,7 @@
   RemoveNotification(kNotificationId2, false);
 
   GetMessageCenterView()->SizeToPreferredSize();
-  if (features::IsLockScreenNotificationsEnabled())
+  if (AshMessageCenterLockScreenController::IsEnabled())
     EXPECT_EQ(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
   else
     EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
@@ -942,20 +947,20 @@
       base::UTF8ToUTF16("display source"), GURL(),
       NotifierId(NotifierId::APPLICATION, "extension_id"),
       message_center::RichNotificationData(), nullptr));
-  if (features::IsLockScreenNotificationsEnabled())
+  if (AshMessageCenterLockScreenController::IsEnabled())
     EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
   else
     EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
 
   GetMessageCenterView()->SizeToPreferredSize();
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
     EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
   } else {
     EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
   }
 
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_TRUE(close_button->visible());
     EXPECT_TRUE(quiet_mode_button->visible());
   } else {
@@ -981,20 +986,20 @@
   // Lock!
   SetLockedState(true);
 
-  if (features::IsLockScreenNotificationsEnabled())
+  if (AshMessageCenterLockScreenController::IsEnabled())
     EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
   else
     EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
 
   GetMessageCenterView()->SizeToPreferredSize();
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
     EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
   } else {
     EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
   }
 
-  if (features::IsLockScreenNotificationsEnabled()) {
+  if (AshMessageCenterLockScreenController::IsEnabled()) {
     EXPECT_TRUE(close_button->visible());
     EXPECT_TRUE(quiet_mode_button->visible());
   } else {
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc
index e4072b42..84a4c0b4 100644
--- a/ash/mojo_interface_factory.cc
+++ b/ash/mojo_interface_factory.cc
@@ -86,6 +86,11 @@
   Shell::Get()->assistant_controller()->BindRequest(std::move(request));
 }
 
+void BindAssistantVolumeControlRequestOnMainThread(
+    mojom::AssistantVolumeControlRequest request) {
+  Shell::Get()->assistant_controller()->BindRequest(std::move(request));
+}
+
 void BindCrosDisplayConfigControllerRequestOnMainThread(
     mojom::CrosDisplayConfigControllerRequest request) {
   Shell::Get()->cros_display_config()->BindRequest(std::move(request));
@@ -236,6 +241,9 @@
     registry->AddInterface(
         base::BindRepeating(&BindAssistantControllerRequestOnMainThread),
         main_thread_task_runner);
+    registry->AddInterface(
+        base::BindRepeating(&BindAssistantVolumeControlRequestOnMainThread),
+        main_thread_task_runner);
   }
   registry->AddInterface(
       base::BindRepeating(&BindAshDisplayControllerRequestOnMainThread),
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 56d02558..47b74e7 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -43,7 +43,7 @@
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kTrilinearFiltering{"TrilinearFiltering",
-                                        base::FEATURE_ENABLED_BY_DEFAULT};
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kViewsLogin{"ViewsLogin", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 9ed631e..9645824 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -225,6 +225,9 @@
 const char kPowerForceNonzeroBrightnessForUserActivity[] =
     "power.force_nonzero_brightness_for_user_activity";
 
+// Boolean controlling whether smart dim model is enabled.
+const char kPowerSmartDimEnabled[] = "power.smart_dim_enabled";
+
 // |kShelfAlignment| and |kShelfAutoHideBehavior| have a local variant. The
 // local variant is not synced and is used if set. If the local variant is not
 // set its value is set from the synced value (once prefs have been
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 0ec6312..230eab5 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -87,6 +87,7 @@
 ASH_PUBLIC_EXPORT extern const char kPowerWaitForInitialUserActivity[];
 ASH_PUBLIC_EXPORT extern const char
     kPowerForceNonzeroBrightnessForUserActivity[];
+ASH_PUBLIC_EXPORT extern const char kPowerSmartDimEnabled[];
 
 ASH_PUBLIC_EXPORT extern const char kShelfAlignment[];
 ASH_PUBLIC_EXPORT extern const char kShelfAlignmentLocal[];
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 636f414..3871828 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -49,10 +49,6 @@
 const char kAshEnablePaletteOnAllDisplays[] =
     "ash-enable-palette-on-all-displays";
 
-// Enables the sidebar.
-const char kAshSidebarEnabled[] = "enable-ash-sidebar";
-const char kAshSidebarDisabled[] = "disable-ash-sidebar";
-
 // Enables the observation of accelerometer events to enter tablet
 // mode.  The flag is "enable-touchview" not "enable-tabletmode" as this
 // is used to enable tablet mode on convertible devices.
@@ -144,11 +140,6 @@
 // Hides all Message Center notification popups (toasts). Used for testing.
 const char kSuppressMessageCenterPopups[] = "suppress-message-center-popups";
 
-bool IsSidebarEnabled() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kAshSidebarEnabled);
-}
-
 bool IsUsingViewsLock() {
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(kShowWebUiLock);
 }
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index 1ed68f4fc..1fdbbbb1 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -48,8 +48,6 @@
 ASH_PUBLIC_EXPORT extern const char kAshShelfColorSchemeNormalVibrant[];
 ASH_PUBLIC_EXPORT extern const char kAshShelfColorSchemeDarkMuted[];
 ASH_PUBLIC_EXPORT extern const char kAshShelfColorSchemeDarkVibrant[];
-ASH_PUBLIC_EXPORT extern const char kAshSidebarDisabled[];
-ASH_PUBLIC_EXPORT extern const char kAshSidebarEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAshTouchHud[];
 ASH_PUBLIC_EXPORT extern const char kAuraLegacyPowerButton[];
 ASH_PUBLIC_EXPORT extern const char kHasInternalStylus[];
@@ -59,7 +57,6 @@
 ASH_PUBLIC_EXPORT extern const char kSuppressMessageCenterPopups[];
 ASH_PUBLIC_EXPORT extern const char kTouchscreenUsableWhileScreenOff[];
 
-ASH_PUBLIC_EXPORT bool IsSidebarEnabled();
 ASH_PUBLIC_EXPORT bool IsTrilinearFilteringEnabled();
 ASH_PUBLIC_EXPORT bool IsUsingViewsLock();
 
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn
index 98485361..2d824fd1 100644
--- a/ash/public/interfaces/BUILD.gn
+++ b/ash/public/interfaces/BUILD.gn
@@ -21,6 +21,7 @@
     "assistant_controller.mojom",
     "assistant_image_downloader.mojom",
     "assistant_setup.mojom",
+    "assistant_volume_control.mojom",
     "cast_config.mojom",
     "client_image_registry.mojom",
     "constants.mojom",
diff --git a/ash/public/interfaces/assistant_volume_control.mojom b/ash/public/interfaces/assistant_volume_control.mojom
new file mode 100644
index 0000000..e8bf405
--- /dev/null
+++ b/ash/public/interfaces/assistant_volume_control.mojom
@@ -0,0 +1,27 @@
+// 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.
+
+module ash.mojom;
+
+// Interface to control system volume through Ash.
+interface AssistantVolumeControl {
+  // Sets system volume to |volume|, which is between 0 - 100.
+  SetVolume(int32 volume, bool user_initiated);
+
+  // Sets mute state to |muted|.
+  SetMuted(bool muted);
+
+  // Adds volume observer. The observer will be immediately notified of volume
+  // and mute status when added.
+  AddVolumeObserver(VolumeObserver observer);
+};
+
+// Observes volume state changes.
+interface VolumeObserver {
+  // Called when volume is updated.
+  OnVolumeChanged(int32 volume);
+
+  // Called when mute state changed.
+  OnMuteStateChanged(bool muted);
+};
diff --git a/ash/public/interfaces/login_screen.mojom b/ash/public/interfaces/login_screen.mojom
index 008256de..c4a2302a7 100644
--- a/ash/public/interfaces/login_screen.mojom
+++ b/ash/public/interfaces/login_screen.mojom
@@ -38,6 +38,18 @@
                    string help_link_text,
                    int32 help_topic_id);
 
+  // Shows a warning banner message on the login screen. A warning banner is
+  // used to notify users of important messages before they log in to their
+  // session. (e.g. Tell the user that an update of the user data will start
+  // on login)
+  // |message|: The message to show.
+  ShowWarningBanner(mojo_base.mojom.String16 message);
+
+  // Hide a warning banner if it is displayed.
+  // TODO(fukino): Ideally chrome-side should not have this level of UI
+  // control. Make the API simpler and let ash determine the UI behavior.
+  HideWarningBanner();
+
   // Requests to close any displayed error messages in ash lock screen.
   ClearErrors();
 
diff --git a/ash/public/interfaces/update.mojom b/ash/public/interfaces/update.mojom
index 243e380..134e360c 100644
--- a/ash/public/interfaces/update.mojom
+++ b/ash/public/interfaces/update.mojom
@@ -5,10 +5,17 @@
 module ash.mojom;
 
 // Urgency of a pending software update. Sets the system tray update icon color.
+// These correspond to values in UpgradeDetector's
+// UpgradeNotificationAnnoyanceLevel enum. Their use is platform-specific. On
+// Chrome OS, LOW severity is issued when an update is detected. ELEVATED
+// follows after two days, and HIGH two days after that. These time deltas may
+// be overridden by administrators via the RelaunchNotificationPeriod policy
+// setting.
 // TODO(jamescook): UpgradeDetector::UpgradeNotificationAnnoyanceLevel could be
 // replaced with this if this moves into a component shared with non-ash chrome.
 enum UpdateSeverity {
   NONE,
+  VERY_LOW,
   LOW,
   ELEVATED,
   HIGH,
diff --git a/ash/resources/vector_icons/unified_menu_brightness.icon b/ash/resources/vector_icons/unified_menu_brightness.icon
index b08e649..797d27a 100644
--- a/ash/resources/vector_icons/unified_menu_brightness.icon
+++ b/ash/resources/vector_icons/unified_menu_brightness.icon
@@ -40,8 +40,14 @@
 R_V_LINE_TO, -2,
 CLOSE,
 R_MOVE_TO, -4, 1,
-R_CUBIC_TO, 1.66f, 0, 3, -1.34f, 3, -3,
-R_CUBIC_TO, 0, -1.66f, -1.34f, -3, -3, -3,
-R_CUBIC_TO, -1.66f, 0, -3, 1.34f, -3, 3,
-R_CUBIC_TO, 0, 1.66f, 1.34f, 3, 3, 3,
+R_CUBIC_TO, -1.66f, 0, -3, -1.34f, -3, -3,
+R_CUBIC_TO, 0, -1.66f, 1.34f, -3, 3, -3,
+R_CUBIC_TO, 1.66f, 0, 3, 1.34f, 3, 3,
+R_CUBIC_TO, 0, 1.66f, -1.34f, 3, -3, 3,
+CLOSE,
+R_MOVE_TO, 0, -1.75f,
+R_CUBIC_TO, 0.69f, 0, 1.25f, -0.56f, 1.25f, -1.25f,
+R_CUBIC_TO, 0, -0.69f, -0.56f, -1.25f, -1.25f, -1.25f,
+R_CUBIC_TO, -0.69f, 0, -1.25f, 0.56f, -1.25f, 1.25f,
+R_CUBIC_TO, 0, 0.69f, 0.56f, 1.25f, 1.25f, 1.25f,
 CLOSE
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index e95b74d..629f173 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -34,7 +34,6 @@
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shelf/shelf_window_targeter.h"
 #include "ash/shell.h"
-#include "ash/shell_port.h"
 #include "ash/shell_state.h"
 #include "ash/system/status_area_layout_manager.h"
 #include "ash/system/status_area_widget.h"
@@ -49,6 +48,7 @@
 #include "ash/wm/fullscreen_window_finder.h"
 #include "ash/wm/lock_action_handler_layout_manager.h"
 #include "ash/wm/lock_layout_manager.h"
+#include "ash/wm/overlay_layout_manager.h"
 #include "ash/wm/root_window_layout_manager.h"
 #include "ash/wm/stacking_controller.h"
 #include "ash/wm/switchable_windows.h"
@@ -629,7 +629,6 @@
       window_tree_host_(ash_host ? ash_host->AsWindowTreeHost()
                                  : window_tree_host),
       shelf_(std::make_unique<Shelf>()),
-      sidebar_(std::make_unique<Sidebar>()),
       lock_screen_action_background_controller_(
           LockScreenActionBackgroundController::Create()) {
   DCHECK((ash_host && !window_tree_host) || (!ash_host && window_tree_host));
@@ -657,8 +656,6 @@
   shell->InitRootWindow(root_window);
 
   CreateContainers();
-  ShellPort::Get()->OnCreatedRootWindowContainers(this);
-
   CreateSystemWallpaper(root_window_type);
 
   InitLayoutManagers();
@@ -698,7 +695,6 @@
   DCHECK(!shelf_->shelf_widget());
   aura::Window* root = GetRootWindow();
   shelf_->CreateShelfWidget(root);
-  sidebar_->SetShelf(shelf_.get());
 
   root_window_layout_manager_ = new wm::RootWindowLayoutManager(root);
   root->SetLayoutManager(root_window_layout_manager_);
@@ -953,6 +949,8 @@
                       lock_screen_related_containers);
   wm::SetSnapsChildrenToPhysicalPixelBoundary(overlay_container);
   overlay_container->SetProperty(::wm::kUsesScreenCoordinatesKey, true);
+  overlay_container->SetLayoutManager(
+      new OverlayLayoutManager(overlay_container));  // Takes ownership.
 
   CreateContainer(kShellWindowId_DockedMagnifierContainer,
                   "DockedMagnifierContainer", lock_screen_related_containers);
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 41f05dc..49b702b 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -11,7 +11,6 @@
 
 #include "ash/ash_export.h"
 #include "ash/public/cpp/shelf_types.h"
-#include "ash/sidebar/sidebar.h"
 #include "ash/wm/workspace/workspace_types.h"
 #include "base/macros.h"
 #include "ui/aura/window.h"
@@ -49,7 +48,6 @@
 enum class LoginStatus;
 class Shelf;
 class ShelfLayoutManager;
-class Sidebar;
 class StackingController;
 class StatusAreaWidget;
 class SystemModalContainerLayoutManager;
@@ -116,9 +114,6 @@
 
   Shelf* shelf() const { return shelf_.get(); }
 
-  // Returns the instance of the sidebar.
-  Sidebar* sidebar() { return sidebar_.get(); }
-
   TouchHudDebug* touch_hud_debug() const { return touch_hud_debug_; }
   void set_touch_hud_debug(TouchHudDebug* hud) { touch_hud_debug_ = hud; }
 
@@ -288,7 +283,6 @@
   // of the RootWindowController so that it is safe for observers to be added
   // to it during construction of the shelf widget and status tray.
   std::unique_ptr<Shelf> shelf_;
-  std::unique_ptr<Sidebar> sidebar_;
 
   // TODO(jamescook): Eliminate this. It is left over from legacy shelf code and
   // doesn't mean anything in particular.
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index 6830f611..84b54b6 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -274,7 +274,8 @@
     : lock_screen_action_background_(lock_screen_action_background),
       tray_action_observer_(this),
       lock_screen_action_background_observer_(this),
-      shutdown_controller_observer_(this) {
+      shutdown_controller_observer_(this),
+      login_screen_controller_observer_(this) {
   // We reuse the focusable state on this view as a signal that focus should
   // switch to the lock screen or status area. This view should otherwise not
   // be focusable.
@@ -309,6 +310,8 @@
   tray_action_observer_.Add(Shell::Get()->tray_action());
   shutdown_controller_observer_.Add(Shell::Get()->shutdown_controller());
   lock_screen_action_background_observer_.Add(lock_screen_action_background);
+  login_screen_controller_observer_.Add(
+      Shell::Get()->login_screen_controller());
   UpdateUi();
 }
 
@@ -433,6 +436,10 @@
   UpdateUi();
 }
 
+void LoginShelfView::OnOobeDialogVisibilityChanged(bool visible) {
+  SetLoginDialogVisible(visible);
+}
+
 bool LoginShelfView::LockScreenActionBackgroundAnimating() const {
   return lock_screen_action_background_->state() ==
              LockScreenActionBackgroundState::kShowing ||
diff --git a/ash/shelf/login_shelf_view.h b/ash/shelf/login_shelf_view.h
index 4dee6504..1fa68a3 100644
--- a/ash/shelf/login_shelf_view.h
+++ b/ash/shelf/login_shelf_view.h
@@ -9,6 +9,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/lock_screen_action/lock_screen_action_background_observer.h"
+#include "ash/login/login_screen_controller_observer.h"
 #include "ash/public/interfaces/kiosk_app_info.mojom.h"
 #include "ash/shutdown_controller.h"
 #include "ash/tray_action/tray_action_observer.h"
@@ -29,6 +30,7 @@
 class LockScreenActionBackgroundController;
 enum class LockScreenActionBackgroundState;
 class TrayAction;
+class LoginScreenController;
 
 class KioskAppsButton;
 
@@ -38,7 +40,8 @@
                                   public views::ButtonListener,
                                   public TrayActionObserver,
                                   public LockScreenActionBackgroundObserver,
-                                  public ShutdownController::Observer {
+                                  public ShutdownController::Observer,
+                                  public LoginScreenControllerObserver {
  public:
   enum ButtonId {
     kShutdown = 1,    // Shut down the device.
@@ -93,6 +96,9 @@
   // ShutdownController::Observer:
   void OnShutdownPolicyChanged(bool reboot_on_shutdown) override;
 
+  // LoginScreenControllerObserver:
+  void OnOobeDialogVisibilityChanged(bool visible) override;
+
  private:
   bool LockScreenActionBackgroundAnimating() const;
 
@@ -114,6 +120,9 @@
   ScopedObserver<ShutdownController, ShutdownController::Observer>
       shutdown_controller_observer_;
 
+  ScopedObserver<LoginScreenController, LoginScreenControllerObserver>
+      login_screen_controller_observer_;
+
   KioskAppsButton* kiosk_apps_button_ = nullptr;  // Owned by view hierarchy
 
   DISALLOW_COPY_AND_ASSIGN(LoginShelfView);
diff --git a/ash/shelf/shelf_background_animator.cc b/ash/shelf/shelf_background_animator.cc
index ca2e35c..a6355f7 100644
--- a/ash/shelf/shelf_background_animator.cc
+++ b/ash/shelf/shelf_background_animator.cc
@@ -18,6 +18,7 @@
 #include "base/command_line.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/color_analysis.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 
 using ColorProfile = color_utils::ColorProfile;
@@ -289,14 +290,23 @@
     ShelfBackgroundType background_type,
     AnimationValues* shelf_background_values,
     AnimationValues* item_background_values) const {
-  // Shelf has a transparent background except when session state is ACTIVE.
   // Shell may not have instance in tests.
-  if (Shell::HasInstance() &&
-      Shell::Get()->session_controller()->GetSessionState() !=
-          session_manager::SessionState::ACTIVE) {
-    shelf_background_values->SetTargetValues(SK_ColorTRANSPARENT);
-    item_background_values->SetTargetValues(SK_ColorTRANSPARENT);
-    return;
+  if (Shell::HasInstance()) {
+    auto session_state = Shell::Get()->session_controller()->GetSessionState();
+
+    // OOBE always uses a fixed shelf color.
+    if (session_state == session_manager::SessionState::OOBE) {
+      shelf_background_values->SetTargetValues(SK_ColorTRANSPARENT);
+      item_background_values->SetTargetValues(gfx::kGoogleGrey100);
+      return;
+    }
+
+    // All other non-active sessions use transparent colors.
+    if (session_state != session_manager::SessionState::ACTIVE) {
+      shelf_background_values->SetTargetValues(SK_ColorTRANSPARENT);
+      item_background_values->SetTargetValues(SK_ColorTRANSPARENT);
+      return;
+    }
   }
 
   std::pair<int, int> target_color_alpha_values =
diff --git a/ash/shelf/shelf_background_animator_unittest.cc b/ash/shelf/shelf_background_animator_unittest.cc
index 9719e0d..59ad4b1f 100644
--- a/ash/shelf/shelf_background_animator_unittest.cc
+++ b/ash/shelf/shelf_background_animator_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/gfx/animation/slide_animation.h"
+#include "ui/gfx/color_palette.h"
 
 namespace ash {
 namespace {
@@ -369,7 +370,7 @@
   EXPECT_EQ(GetBaseColor(test_api_->shelf_background_target_color()),
             GetBaseColor(SK_ColorTRANSPARENT));
   EXPECT_EQ(GetBaseColor(test_api_->item_background_target_color()),
-            GetBaseColor(SK_ColorTRANSPARENT));
+            GetBaseColor(gfx::kGoogleGrey100));
 
   NotifySessionStateChanged(session_manager::SessionState::LOGIN_PRIMARY);
   EXPECT_EQ(GetBaseColor(test_api_->shelf_background_target_color()),
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 1e84a3b..b8b43f60 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -23,7 +23,6 @@
 #include "ash/shelf/shelf_layout_manager_observer.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
-#include "ash/sidebar/sidebar.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/wm/fullscreen_window_finder.h"
 #include "ash/wm/lock_state_controller.h"
@@ -972,12 +971,6 @@
   if (shelf_widget_->IsShowingAppList())
     return SHELF_AUTO_HIDE_SHOWN;
 
-  Sidebar* sidebar =
-      RootWindowController::ForWindow(shelf_widget_->GetNativeView())
-          ->sidebar();
-  if (sidebar && sidebar->IsVisible())
-    return SHELF_AUTO_HIDE_SHOWN;
-
   if (shelf_widget_->status_area_widget() &&
       shelf_widget_->status_area_widget()->ShouldShowShelf())
     return SHELF_AUTO_HIDE_SHOWN;
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index a656182b..29610af 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -38,7 +38,6 @@
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/auto_reset.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/chromeos_switches.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -324,18 +323,20 @@
       bounds_animator_(std::make_unique<views::BoundsAnimator>(this)),
       tooltip_(this),
       focus_search_(std::make_unique<ShelfFocusSearch>(this)),
-      tablet_mode_observer_(this),
       shelf_item_background_color_(kShelfDefaultBaseColor),
       weak_factory_(this) {
   DCHECK(model_);
   DCHECK(shelf_);
   DCHECK(shelf_widget_);
-  tablet_mode_observer_.Add(Shell::Get()->tablet_mode_controller());
+  Shell::Get()->tablet_mode_controller()->AddObserver(this);
   bounds_animator_->AddObserver(this);
   set_context_menu_controller(this);
 }
 
 ShelfView::~ShelfView() {
+  // Shell destroys the TabletModeController before destroying all root windows.
+  if (Shell::Get()->tablet_mode_controller())
+    Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
   bounds_animator_->RemoveObserver(this);
   model_->RemoveObserver(this);
 }
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 42597bf..735a6faf 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -29,10 +29,6 @@
 #include "ui/views/view.h"
 #include "ui/views/view_model.h"
 
-namespace ash {
-class TabletModeController;
-}
-
 namespace ui {
 class SimpleMenuModel;
 }
@@ -539,10 +535,6 @@
   // The view which gets replaced by our drag icon proxy.
   views::View* drag_replaced_view_ = nullptr;
 
-  // Observes tablet mode changing.
-  ScopedObserver<ash::TabletModeController, ash::TabletModeObserver>
-      tablet_mode_observer_;
-
   // True when the icon was dragged off the shelf.
   bool dragged_off_shelf_ = false;
 
diff --git a/ash/shell.cc b/ash/shell.cc
index bf6c846..e3e79f2 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -399,7 +399,7 @@
 
 // static
 Config Shell::GetAshConfig() {
-  return Get()->shell_port_->GetAshConfig();
+  return Config::CLASSIC;
 }
 
 // static
@@ -950,8 +950,6 @@
     ui::ContextFactoryPrivate* context_factory_private,
     std::unique_ptr<base::Value> initial_display_prefs,
     std::unique_ptr<ui::ws2::GpuInterfaceProvider> gpu_interface_provider) {
-  const Config config = shell_port_->GetAshConfig();
-
   // This creates the MessageCenter object which is used by some other objects
   // initialized here, so it needs to come early.
   message_center_controller_ = std::make_unique<MessageCenterController>();
@@ -1027,15 +1025,13 @@
 
   InitializeDisplayManager();
 
-  if (config == Config::CLASSIC) {
-    // This will initialize aura::Env which requires |display_manager_| to
-    // be initialized first.
-    if (context_factory)
-      aura::Env::GetInstance()->set_context_factory(context_factory);
-    if (context_factory_private) {
-      aura::Env::GetInstance()->set_context_factory_private(
-          context_factory_private);
-    }
+  // This will initialize aura::Env which requires |display_manager_| to
+  // be initialized first.
+  if (context_factory)
+    aura::Env::GetInstance()->set_context_factory(context_factory);
+  if (context_factory_private) {
+    aura::Env::GetInstance()->set_context_factory_private(
+        context_factory_private);
   }
 
   // Night Light depends on the display manager, the display color manager, and
@@ -1175,7 +1171,10 @@
   viz::mojom::VideoDetectorObserverPtr observer;
   video_detector_ =
       std::make_unique<VideoDetector>(mojo::MakeRequest(&observer));
-  shell_port_->AddVideoDetectorObserver(std::move(observer));
+  aura::Env::GetInstance()
+      ->context_factory_private()
+      ->GetHostFrameSinkManager()
+      ->AddVideoDetectorObserver(std::move(observer));
 
   tooltip_controller_.reset(new views::corewm::TooltipController(
       std::unique_ptr<views::corewm::Tooltip>(new views::corewm::TooltipAura)));
@@ -1218,12 +1217,10 @@
       std::make_unique<SystemNotificationController>();
 
   window_tree_host_manager_->InitHosts();
-  shell_port_->OnHostsInitialized();
 
   // Needs to be created after InitDisplays() since it may cause the virtual
   // keyboard to be deployed.
-  if (config != Config::MASH_DEPRECATED)
-    virtual_keyboard_controller_.reset(new VirtualKeyboardController);
+  virtual_keyboard_controller_ = std::make_unique<VirtualKeyboardController>();
 
   cursor_manager_->HideCursor();  // Hide the mouse cursor on startup.
   cursor_manager_->SetCursor(ui::CursorType::kPointer);
@@ -1448,8 +1445,6 @@
         break;
     }
   }
-
-  shell_port_->UpdateSystemModalAndBlockingContainers();
 }
 
 void Shell::OnLoginStatusChanged(LoginStatus login_status) {
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 9883d6c..5829ca9 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -264,7 +264,6 @@
   }
 
   void DismissAppList() override {
-    DCHECK(ShellPort::HasInstance());
     Shell::Get()->app_list_controller()->DismissAppList();
   }
 
diff --git a/ash/shell_init_params.cc b/ash/shell_init_params.cc
index ec16ce4..258e93b3 100644
--- a/ash/shell_init_params.cc
+++ b/ash/shell_init_params.cc
@@ -6,6 +6,7 @@
 
 #include "ash/shell_delegate.h"
 #include "ash/shell_port.h"
+#include "base/values.h"
 #include "services/ui/ws2/gpu_interface_provider.h"
 
 namespace ash {
diff --git a/ash/shell_port.h b/ash/shell_port.h
index b446ec6..b895a04 100644
--- a/ash/shell_port.h
+++ b/ash/shell_port.h
@@ -5,14 +5,7 @@
 #ifndef ASH_SHELL_PORT_H_
 #define ASH_SHELL_PORT_H_
 
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
 #include "ash/ash_export.h"
-#include "services/viz/public/interfaces/compositing/video_detector_observer.mojom.h"
-#include "ui/aura/client/window_types.h"
 #include "ui/base/ui_base_types.h"
 
 namespace gfx {
@@ -25,9 +18,6 @@
 }
 
 namespace ash {
-class RootWindowController;
-
-enum class Config;
 
 // Porting layer for Shell. This class contains the part of Shell that are
 // different in classic ash and mus/mash.
@@ -38,12 +28,9 @@
   virtual ~ShellPort();
 
   static ShellPort* Get();
-  static bool HasInstance() { return instance_ != nullptr; }
 
   virtual void Shutdown();
 
-  virtual Config GetAshConfig() const = 0;
-
   // Shows the context menu for the wallpaper or shelf at |location_in_screen|.
   void ShowContextMenu(const gfx::Point& location_in_screen,
                        ui::MenuSourceType source_type);
@@ -58,33 +45,11 @@
                                  views::PointerWatcherEventTypes events) = 0;
   virtual void RemovePointerWatcher(views::PointerWatcher* watcher) = 0;
 
-  // True if any touch points are down.
-  virtual bool IsTouchDown() = 0;
-
-  // TODO(jamescook): Remove this when VirtualKeyboardController has been moved.
-  virtual void ToggleIgnoreExternalKeyboard() = 0;
-
   virtual void CreatePointerWatcherAdapter() = 0;
 
-  // Called after the containers of |root_window_controller| have been created.
-  // Allows ShellPort to install any additional state on the containers.
-  virtual void OnCreatedRootWindowContainers(
-      RootWindowController* root_window_controller) = 0;
-
-  // Called any time the set up system modal and blocking containers needs to
-  // sent to the server.
-  virtual void UpdateSystemModalAndBlockingContainers() = 0;
-
-  // Adds an observer for viz::VideoDetector.
-  virtual void AddVideoDetectorObserver(
-      viz::mojom::VideoDetectorObserverPtr observer) = 0;
-
  protected:
   ShellPort();
 
-  // Called after WindowTreeHostManager::InitHosts().
-  virtual void OnHostsInitialized() = 0;
-
  private:
   friend class Shell;
 
diff --git a/ash/shell_port_classic.cc b/ash/shell_port_classic.cc
index d2707751..192fb11 100644
--- a/ash/shell_port_classic.cc
+++ b/ash/shell_port_classic.cc
@@ -5,14 +5,8 @@
 #include "ash/shell_port_classic.h"
 
 #include <memory>
-#include <utility>
 
-#include "ash/keyboard/virtual_keyboard_controller.h"
 #include "ash/pointer_watcher_adapter_classic.h"
-#include "ash/public/cpp/config.h"
-#include "ash/shell.h"
-#include "components/viz/host/host_frame_sink_manager.h"
-#include "ui/aura/env.h"
 
 namespace ash {
 
@@ -20,22 +14,12 @@
 
 ShellPortClassic::~ShellPortClassic() = default;
 
-// static
-ShellPortClassic* ShellPortClassic::Get() {
-  CHECK(Shell::GetAshConfig() == Config::CLASSIC);
-  return static_cast<ShellPortClassic*>(ShellPort::Get());
-}
-
 void ShellPortClassic::Shutdown() {
   pointer_watcher_adapter_.reset();
 
   ShellPort::Shutdown();
 }
 
-Config ShellPortClassic::GetAshConfig() const {
-  return Config::CLASSIC;
-}
-
 void ShellPortClassic::AddPointerWatcher(
     views::PointerWatcher* watcher,
     views::PointerWatcherEventTypes events) {
@@ -46,31 +30,8 @@
   pointer_watcher_adapter_->RemovePointerWatcher(watcher);
 }
 
-bool ShellPortClassic::IsTouchDown() {
-  return aura::Env::GetInstance()->is_touch_down();
-}
-
-void ShellPortClassic::ToggleIgnoreExternalKeyboard() {
-  Shell::Get()->virtual_keyboard_controller()->ToggleIgnoreExternalKeyboard();
-}
-
 void ShellPortClassic::CreatePointerWatcherAdapter() {
   pointer_watcher_adapter_ = std::make_unique<PointerWatcherAdapterClassic>();
 }
 
-void ShellPortClassic::OnCreatedRootWindowContainers(
-    RootWindowController* root_window_controller) {}
-
-void ShellPortClassic::UpdateSystemModalAndBlockingContainers() {}
-
-void ShellPortClassic::OnHostsInitialized() {}
-
-void ShellPortClassic::AddVideoDetectorObserver(
-    viz::mojom::VideoDetectorObserverPtr observer) {
-  aura::Env::GetInstance()
-      ->context_factory_private()
-      ->GetHostFrameSinkManager()
-      ->AddVideoDetectorObserver(std::move(observer));
-}
-
 }  // namespace ash
diff --git a/ash/shell_port_classic.h b/ash/shell_port_classic.h
index 019e61dd..4bddff5 100644
--- a/ash/shell_port_classic.h
+++ b/ash/shell_port_classic.h
@@ -6,7 +6,6 @@
 #define ASH_SHELL_PORT_CLASSIC_H_
 
 #include <memory>
-#include <vector>
 
 #include "ash/ash_export.h"
 #include "ash/shell_port.h"
@@ -25,23 +24,12 @@
   ShellPortClassic();
   ~ShellPortClassic() override;
 
-  static ShellPortClassic* Get();
-
   // ShellPort:
   void Shutdown() override;
-  Config GetAshConfig() const override;
   void AddPointerWatcher(views::PointerWatcher* watcher,
                          views::PointerWatcherEventTypes events) override;
   void RemovePointerWatcher(views::PointerWatcher* watcher) override;
-  bool IsTouchDown() override;
-  void ToggleIgnoreExternalKeyboard() override;
   void CreatePointerWatcherAdapter() override;
-  void OnCreatedRootWindowContainers(
-      RootWindowController* root_window_controller) override;
-  void UpdateSystemModalAndBlockingContainers() override;
-  void OnHostsInitialized() override;
-  void AddVideoDetectorObserver(
-      viz::mojom::VideoDetectorObserverPtr observer) override;
 
  private:
   std::unique_ptr<PointerWatcherAdapterClassic> pointer_watcher_adapter_;
diff --git a/ash/sidebar/sidebar.cc b/ash/sidebar/sidebar.cc
deleted file mode 100644
index a17b867a..0000000
--- a/ash/sidebar/sidebar.cc
+++ /dev/null
@@ -1,53 +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 "ash/sidebar/sidebar.h"
-
-#include "ash/public/cpp/ash_switches.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/shelf/shelf.h"
-#include "ash/shell.h"
-#include "ash/sidebar/sidebar_widget.h"
-#include "ui/aura/window.h"
-
-namespace ash {
-
-Sidebar::Sidebar() {}
-Sidebar::~Sidebar() {}
-
-void Sidebar::SetShelf(Shelf* shelf) {
-  DCHECK(!widget_);
-  DCHECK(!shelf_);
-
-  shelf_ = shelf;
-}
-
-void Sidebar::Show(SidebarInitMode mode) {
-  CHECK(switches::IsSidebarEnabled());
-  DCHECK(shelf_);
-
-  if (!widget_) {
-    aura::Window* container =
-        shelf_->GetWindow()->GetRootWindow()->GetChildById(
-            kShellWindowId_ShelfBubbleContainer);
-    widget_ = new SidebarWidget(container, this, shelf_, mode);
-    widget_->Show();
-  } else {
-    widget_->Reinitialize(mode);
-  }
-}
-
-void Sidebar::Hide() {
-  CHECK(switches::IsSidebarEnabled());
-  DCHECK(widget_);
-
-  widget_->Close();
-  widget_ = nullptr;
-}
-
-bool Sidebar::IsVisible() const {
-  return widget_ && widget_->IsVisible();
-}
-
-}  // namespace ash
diff --git a/ash/sidebar/sidebar.h b/ash/sidebar/sidebar.h
deleted file mode 100644
index 53b45435..0000000
--- a/ash/sidebar/sidebar.h
+++ /dev/null
@@ -1,48 +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 ASH_SIDEBAR_SIDEBAR_H_
-#define ASH_SIDEBAR_SIDEBAR_H_
-
-#include <memory>
-
-#include "ash/sidebar/sidebar_params.h"
-#include "base/macros.h"
-
-namespace ash {
-
-class Shelf;
-class SidebarWidget;
-
-/**
- * Class to handle and manage the sidebar and its components (eg. window and
- * widget).
- *
- * This class is used as an interface of Sidebar for external components.
- */
-class Sidebar {
- public:
-  Sidebar();
-  virtual ~Sidebar();
-
-  void SetShelf(Shelf* shelf);
-  void Show(SidebarInitMode mode);
-  void Hide();
-  bool IsVisible() const;
-
- private:
-  // The widget of Sidebar, which has the views of Sidebar. Not owned by this,
-  // but by its native widget (NATIVE_WIDGET_OWNS_WIDGET).
-  SidebarWidget* widget_ = nullptr;
-
-  // The shelf associated with the sidebar widget. This is the value set by
-  // SetRootAndShelf(). Not owned by this.
-  Shelf* shelf_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(Sidebar);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SIDEBAR_SIDEBAR_H_
diff --git a/ash/sidebar/sidebar_params.h b/ash/sidebar/sidebar_params.h
deleted file mode 100644
index fd40ef3..0000000
--- a/ash/sidebar/sidebar_params.h
+++ /dev/null
@@ -1,19 +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 ASH_SIDEBAR_SIDEBAR_PARAMS_H_
-#define ASH_SIDEBAR_SIDEBAR_PARAMS_H_
-
-namespace ash {
-
-enum class SidebarInitMode {
-  // Normal mode: show message center and notifications
-  NORMAL,
-  // Settings: show settings panel
-  MESSAGE_CENTER_SETTINGS
-};
-
-}  // namespace ash
-
-#endif  // ASH_SIDEBAR_SIDEBAR_PARAMS_H_
diff --git a/ash/sidebar/sidebar_widget.cc b/ash/sidebar/sidebar_widget.cc
deleted file mode 100644
index 2e18f9cf..0000000
--- a/ash/sidebar/sidebar_widget.cc
+++ /dev/null
@@ -1,177 +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 "ash/sidebar/sidebar_widget.h"
-
-#include <memory>
-#include <utility>
-
-#include "ash/app_list/views/app_list_view.h"
-#include "ash/message_center/message_center_view.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/root_window_controller.h"
-#include "ash/screen_util.h"
-#include "ash/session/session_controller.h"
-#include "ash/shelf/shelf.h"
-#include "ash/shelf/shelf_widget.h"
-#include "ash/shell.h"
-#include "ash/system/message_center/notification_tray.h"
-#include "ash/system/status_area_widget.h"
-#include "ash/system/tray/tray_constants.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/aura/window.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/widget/widget_observer.h"
-
-namespace ash {
-
-namespace {
-
-display::Display GetCurrentDisplay(aura::Window* window) {
-  return display::Screen::GetScreen()->GetDisplayNearestWindow(window);
-}
-
-const SkColor kLightShadingColor = SkColorSetARGB(200, 0, 0, 0);
-
-// The blur radius of the background.
-constexpr int kSidebarBackgroundBlurRadius = 30;
-
-gfx::Rect CalculateBounds(const gfx::Rect& display_bounds) {
-  return gfx::Rect(display_bounds.x() + display_bounds.width() -
-                       message_center::kNotificationWidth,
-                   display_bounds.y(), message_center::kNotificationWidth,
-                   display_bounds.height());
-}
-
-}  // namespace
-
-class SidebarWidget::DelegateView : public views::WidgetDelegateView,
-                                    public views::ButtonListener {
- public:
-  DelegateView(Shelf* shelf, SidebarInitMode mode)
-      : container_(new views::View()), background_(new views::View) {
-    bool is_background_blur_enabled =
-        app_list::features::IsBackgroundBlurEnabled();
-
-    background_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
-    background_->layer()->SetFillsBoundsOpaquely(false);
-    background_->layer()->SetColor(kLightShadingColor);
-    background_->layer()->SetOpacity(
-        is_background_blur_enabled
-            ? app_list::AppListView::kAppListOpacityWithBlur
-            : app_list::AppListView::kAppListOpacity);
-    if (is_background_blur_enabled)
-      background_->layer()->SetBackgroundBlur(kSidebarBackgroundBlurRadius);
-
-    auto* message_center = message_center::MessageCenter::Get();
-    gfx::Rect display_bounds = shelf->GetUserWorkAreaBounds();
-    bool initially_message_center_settings_visible =
-        (mode == SidebarInitMode::MESSAGE_CENTER_SETTINGS);
-    message_center_view_ =
-        new MessageCenterView(message_center, display_bounds.height(),
-                              initially_message_center_settings_visible);
-    message_center_view_->SetNotifications(
-        message_center->GetVisibleNotifications());
-
-    auto container_layout =
-        std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical);
-    container_->SetPaintToLayer();
-    container_->layer()->SetFillsBoundsOpaquely(false);
-    container_->AddChildView(message_center_view_);
-    container_layout->SetFlexForView(message_center_view_, 1);
-    container_->SetLayoutManager(std::move(container_layout));
-
-    AddChildView(background_);
-    AddChildView(container_);
-  }
-
-  // Overridden from View:
-  void Layout() override {
-    DCHECK(message_center_view_);
-
-    background_->SetBoundsRect(GetLocalBounds());
-    container_->SetBoundsRect(GetLocalBounds());
-
-    int message_center_height = height();
-    message_center_view_->SetBounds(0, 0, width(), message_center_height);
-  }
-
-  // Overridden from ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override {}
-
-  ash::MessageCenterView* message_center_view() { return message_center_view_; }
-
- private:
-  views::View* container_;
-  views::View* background_;
-  ash::MessageCenterView* message_center_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(DelegateView);
-};
-
-SidebarWidget::SidebarWidget(aura::Window* sidebar_container,
-                             Sidebar* sidebar,
-                             Shelf* shelf,
-                             SidebarInitMode mode)
-    : sidebar_(sidebar),
-      shelf_(shelf),
-      delegate_view_(new DelegateView(shelf, mode)) {
-  DCHECK(sidebar_container);
-  DCHECK(sidebar_);
-  DCHECK(shelf_);
-
-  display::Screen::GetScreen()->AddObserver(this);
-
-  views::Widget::InitParams params(
-      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  params.name = "SidebarWidget";
-  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-  params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP;
-  params.delegate = delegate_view_;
-  params.parent = sidebar_container;
-  Init(params);
-
-  SetContentsView(delegate_view_);
-
-  gfx::Rect display_bounds = shelf->GetUserWorkAreaBounds();
-  SetBounds(CalculateBounds(display_bounds));
-}
-
-SidebarWidget::~SidebarWidget() {
-  display::Screen::GetScreen()->RemoveObserver(this);
-}
-
-void SidebarWidget::Reinitialize(SidebarInitMode mode) {
-  switch (mode) {
-    case SidebarInitMode::NORMAL:
-      delegate_view_->message_center_view()->SetSettingsVisible(false);
-      break;
-    case SidebarInitMode::MESSAGE_CENTER_SETTINGS:
-      delegate_view_->message_center_view()->SetSettingsVisible(true);
-      break;
-  }
-}
-
-void SidebarWidget::OnDisplayAdded(const display::Display& new_display) {}
-
-void SidebarWidget::OnDisplayRemoved(const display::Display& old_display) {}
-
-void SidebarWidget::OnDisplayMetricsChanged(const display::Display& display,
-                                            uint32_t metrics) {
-  if (GetCurrentDisplay(GetNativeView()).id() == display.id()) {
-    gfx::Rect display_bounds = shelf_->GetUserWorkAreaBounds();
-    SetBounds(CalculateBounds(display_bounds));
-  }
-}
-
-}  // namespace ash
diff --git a/ash/sidebar/sidebar_widget.h b/ash/sidebar/sidebar_widget.h
deleted file mode 100644
index 1acbfc7..0000000
--- a/ash/sidebar/sidebar_widget.h
+++ /dev/null
@@ -1,54 +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 ASH_SIDEBAR_SIDEBAR_WIDGET_H_
-#define ASH_SIDEBAR_SIDEBAR_WIDGET_H_
-
-#include "ash/sidebar/sidebar_params.h"
-#include "ui/display/display_observer.h"
-#include "ui/views/widget/widget.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ash {
-class Sidebar;
-class Shelf;
-
-class SidebarWidget : public views::Widget, public display::DisplayObserver {
- public:
-  SidebarWidget(aura::Window* sidebar_container,
-                Sidebar* sidebar,
-                Shelf* shelf,
-                SidebarInitMode mode);
-  ~SidebarWidget() override;
-
-  void Reinitialize(SidebarInitMode mode);
-
-  // Overridden from display::DisplayObserver:
-  void OnDisplayAdded(const display::Display& new_display) override;
-  void OnDisplayRemoved(const display::Display& old_display) override;
-  void OnDisplayMetricsChanged(const display::Display& display,
-                               uint32_t metrics) override;
-
-  void SetSystemTrayView(views::View* view);
-
- private:
-  class DelegateView;
-
-  // The sidebar instance managing this widget.
-  Sidebar* sidebar_;
-  // The shelf which this widget belongs to.
-  Shelf* shelf_;
-  // DelegateView for this widget. Owned by the hierarchy (it means this is
-  // indirectly owned by this widget).
-  DelegateView* delegate_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(SidebarWidget);
-};
-
-}  // namespace ash
-
-#endif  // ASH_SIDEBAR_SIDEBAR_WIDGET_H_
diff --git a/ash/strings/ash_strings_am.xtb b/ash/strings/ash_strings_am.xtb
index b3fd212..331fcbc 100644
--- a/ash/strings/ash_strings_am.xtb
+++ b/ash/strings/ash_strings_am.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" />ን አግብር</translation>
 <translation id="6910714959251846841">ይህ ዝማኔ የመሣሪያዎን powerwashing ይጠይቃል። ስለቅርብ ጊዜው <ph name="SYSTEM_APP_NAME" /> ዝማኔ የበለጠ ይረዱ።</translation>
 <translation id="6911468394164995108">ሌላ ይቀላቀሉ...</translation>
+<translation id="6972754398087986839">አስጀማሪ መመሪያ</translation>
 <translation id="6981982820502123353">ተደራሽነት</translation>
 <translation id="698231206551913481">አንዴ ይህ ተጠቃሚ ከተወገደ በኋላ ከዚህ ተጠቃሚ ጋር የተጎዳኙ ሁሉም ፋይሎች እና አካባቢያዊ ውሂብ በቋሚነት ይሰረዛሉ።</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> ላይ ተመልሰው ይምጡ።</translation>
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index 12079965..f350b41 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -204,7 +204,7 @@
 <translation id="4508225577814909926"><ph name="NAME" />: جارٍ الاتصال...</translation>
 <translation id="4513946894732546136">تعليقات</translation>
 <translation id="4527045527269911712">يريد جهاز بلوتوث "<ph name="DEVICE_NAME" />" الحصول على إذن للإقران.</translation>
-<translation id="453661520163887813">يتبقى <ph name="TIME" /> حتى الاكتمال</translation>
+<translation id="453661520163887813"><ph name="TIME" /> حتى اكتمال الشحن</translation>
 <translation id="4544944664594876241">لقد تغير اختصار قفل الشاشة. يُرجى استخدام <ph name="NEW_SHORTCUT" /> بدلاً من <ph name="OLD_SHORTCUT" />.</translation>
 <translation id="4564869809620998694">خدمة الخطوط</translation>
 <translation id="4570957409596482333">زر "سماع الاختيار"</translation>
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">تفعيل <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">‏يتطلَّب هذا التحديث إجراء عملية Powerwash لجهازك. مزيد من المعلومات حول آخر تحديث لتطبيق <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">الانضمام إلى شبكة أخرى...</translation>
+<translation id="6972754398087986839">البدء</translation>
 <translation id="6981982820502123353">إمكانية الدخول</translation>
 <translation id="698231206551913481">سيتم حذف جميع الملفات والبيانات المحلية المرتبطة بهذا المستخدم نهائيًا بمجرد إزالة هذا المستخدم.</translation>
 <translation id="7015766095477679451">يمكنك العودة لاستخدام الجهاز في <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_bg.xtb b/ash/strings/ash_strings_bg.xtb
index 8a584bb2..9b98619 100644
--- a/ash/strings/ash_strings_bg.xtb
+++ b/ash/strings/ash_strings_bg.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Активиране на <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Тази актуализация изисква Powerwash на устройството ви. Научете повече за най-новата актуализация на <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Присъединяване другаде...</translation>
+<translation id="6972754398087986839">Първи стъпки</translation>
 <translation id="6981982820502123353">Достъпност</translation>
 <translation id="698231206551913481">След като този потребител бъде премахнат, всички свързани с него файлове и локални данни ще се изтрият за постоянно.</translation>
 <translation id="7015766095477679451">Ще бъда отново на ваше разположение в <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_bn.xtb b/ash/strings/ash_strings_bn.xtb
index e05b3d50..0f5c4bc 100644
--- a/ash/strings/ash_strings_bn.xtb
+++ b/ash/strings/ash_strings_bn.xtb
@@ -7,6 +7,7 @@
 <translation id="1037492556044956303"><ph name="DEVICE_NAME" /> যোগ করা হয়েছে</translation>
 <translation id="1056775291175587022">কোনও নেটওয়ার্ক নেই</translation>
 <translation id="1059194134494239015"><ph name="DISPLAY_NAME" />: <ph name="RESOLUTION" /></translation>
+<translation id="1104084341931202936">অ্যাক্সেসেবিলিটি সেটিংস দেখান</translation>
 <translation id="1104621072296271835">আপনার ডিভাইসগুলি একসাথে আরও ভাল কাজ করে</translation>
 <translation id="112308213915226829">তাককে স্বয়ংক্রিয়ভাবে লুকান</translation>
 <translation id="1153356358378277386">যুক্ত করা ডিভাইসগুলি</translation>
@@ -20,17 +21,20 @@
 <translation id="1279938420744323401"><ph name="DISPLAY_NAME" /> (<ph name="ANNOTATION" />)</translation>
 <translation id="1290331692326790741">সিগন্যালটি ভাল নয়</translation>
 <translation id="1293264513303784526">USB-C ডিভাইস (বাঁ পোর্ট)</translation>
+<translation id="1302880136325416935">ব্লুটুথ সেটিংস দেখান। <ph name="STATE_TEXT" /></translation>
 <translation id="1346748346194534595">ডানে</translation>
 <translation id="1351937230027495976">মেনুটি আড়াল করুন</translation>
 <translation id="1383876407941801731">সার্চ করুন</translation>
 <translation id="1467432559032391204">বামে</translation>
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">লঞ্চার</translation>
+<translation id="1520303207432623762">{NUM_APPS,plural, =1{বিজ্ঞপ্তির সেটিংস দেখান। একটি অ্যাপের জন্য বিজ্ঞপ্তির নোটিফিকেশন বন্ধ আছে}one{বিজ্ঞপ্তির সেটিংস দেখান। #টি অ্যাপের জন্য নোটিফিকেশন বন্ধ আছে}other{বিজ্ঞপ্তির সেটিংস দেখান। #টি অ্যাপের জন্য নোটিফিকেশন বন্ধ আছে}}</translation>
 <translation id="1525508553941733066">খারিজ করুন</translation>
 <translation id="1537254971476575106">ফুলস্ক্রিন ম্যাগনিফায়ার</translation>
 <translation id="15373452373711364">বড় মাউস কার্সার</translation>
 <translation id="1550523713251050646">আরও বিকল্পের জন্য ক্লিক করুন</translation>
 <translation id="1567387640189251553">আপনি যখন শেষবার পাসওয়ার্ডটি লিখেছিলেন তার পরে অন্য একটি কীবোর্ডে কানেক্ট করা হয়েছিল। এটি আপনার পাসওয়ার্ড চুরি করার চেষ্টা করতে পারে।</translation>
+<translation id="1570871743947603115">ব্লুটুথ টগল করুন। <ph name="STATE_TEXT" /></translation>
 <translation id="1608626060424371292">এই ব্যবহারকারীকে সরান</translation>
 <translation id="1621499497873603021">ব্যাটারি শেষ হতে <ph name="TIME_LEFT" /> সময় বাকি আছে</translation>
 <translation id="1658406695958299976">দুঃখিত, আপনার পাসওয়ার্ড এখনও পর্যন্ত যাচাই করা যায়নি। দ্রষ্টব্য: আপনি যদি সম্প্রতি আপনার পাসওয়ার্ড পরিবর্তন করে থাকেন, তাহলে আপনি সাইন-আউট করার পর আপনার নতুন পাসওয়ার্ড প্রয়োগ করা হবে, অনুগ্রহ করে এখানে পুরানো পাসওয়ার্ড ব্যবহার করুন।</translation>
@@ -40,6 +44,7 @@
 <translation id="1743570585616704562">শনাক্ত করা যায়নি</translation>
 <translation id="1746730358044914197">আপনার প্রশাসক ইনপুটের পদ্ধতিগুলি কনফিগার করে।</translation>
 <translation id="1747827819627189109">অন-স্ক্রিন কীবোর্ড সক্ষম করা রয়েছে</translation>
+<translation id="1761222317188459878">নেটওয়ার্ক কানেকশন টগল করুন। <ph name="STATE_TEXT" /></translation>
 <translation id="1823873187264960516">ইথারনেট: <ph name="ADDRESS" /></translation>
 <translation id="1836215606488044471">সহায়ক (লোড হচ্ছে...)</translation>
 <translation id="1841545962859478868">ডিভাইস প্রশাসক নিম্নল্লিখিত বিষয়গুলি পর্যবেক্ষণ করতে পারেন:</translation>
@@ -63,6 +68,7 @@
 <translation id="2049639323467105390">এই ডিভাইস <ph name="DOMAIN" /> দ্বারা পরিচালিত হয়৷</translation>
 <translation id="2050339315714019657">প্রতিকৃতি</translation>
 <translation id="2067602449040652523">কীবোর্ডের উজ্জ্বলতা</translation>
+<translation id="2075212959500165896">অনেকবার চেষ্টা করা হয়েছে। পরে আবার চেষ্টা করুন।</translation>
 <translation id="2081529251031312395">এখনও $1 পরে সাইন-ইন করতে পারেন।</translation>
 <translation id="2127372758936585790">নিম্ন শক্তির চার্জার</translation>
 <translation id="2135456203358955318">ডক করা ম্যাগনিফায়ার</translation>
@@ -76,12 +82,15 @@
 <translation id="2303600792989757991">উইন্ডোর ওভারভিউ টগল করুন</translation>
 <translation id="2338501278241028356">আশেপাশের ডিভাইস খুঁজে পেতে ব্লুটুথ চালু করুন</translation>
 <translation id="2339073806695260576">একটি নোট, স্ক্রিনশট নিতে, লেজার পয়েন্টার বা ম্যাগনিফিকেশনের কাচ ব্যবহার করার জন্য শেল্ফের স্টাইলাস বোতামটি ট্যাপ করুন।</translation>
+<translation id="2341729377289034582">স্ক্রিনটি পোট্রেট মোডে লক করা আছে</translation>
 <translation id="2352467521400612932">স্টাইলাস সেটিংস</translation>
 <translation id="2354174487190027830"><ph name="NAME" /> সক্রিয় করা হচ্ছে</translation>
 <translation id="2359808026110333948">অবিরত</translation>
 <translation id="2365393535144473978">মোবাইল ডেটা সক্ষম করলে ব্লুটুথও সক্ষম হয়ে যাবে।</translation>
 <translation id="2391579633712104609">১৮০°</translation>
+<translation id="239188844683466770">'বিরক্ত করবেন না' মোড টগল করুন</translation>
 <translation id="2412593942846481727">আপডেট উপলভ্য</translation>
+<translation id="2416346634399901812"><ph name="NETWORK_NAME" />-এর সাথে কানেক্ট হয়েছে</translation>
 <translation id="2429753432712299108">ব্লুটুথ ডিভাইস "<ph name="DEVICE_NAME" />" যুক্ত করার অনুমতি চাইছে। স্বীকার করার আগে, দয়া করে এই পাস কীটি যে ডিভাইসে প্রদর্শিত হয়েছে তা নিশ্চিত করুন: <ph name="PASSKEY" /></translation>
 <translation id="2482878487686419369">বিজ্ঞপ্তিগুলি</translation>
 <translation id="2484513351006226581">কীবোর্ড লে-আউট পরিবর্তন করতে <ph name="KEYBOARD_SHORTCUT" /> টিপুন।</translation>
@@ -114,6 +123,7 @@
 <translation id="2946119680249604491">সংযোগ জুড়ুন</translation>
 <translation id="2961963223658824723">কিছু সমস্যা হয়েছে। কয়েক সেকেন্ডের মধ্যে আবার চেষ্টা করুন।</translation>
 <translation id="2963773877003373896">mod3</translation>
+<translation id="2995447421581609334">কাস্ট ডিভাইসগুলি দেখান।</translation>
 <translation id="2996462380875591307">ডক করা ম্যাগনিফায়ার চালু আছে। আবার Ctrl+Search+D প্রেস করে সেটিকে বন্ধ করুন।</translation>
 <translation id="2999742336789313416"><ph name="DISPLAY_NAME" /> হল <ph name="DOMAIN" /> এর দ্বারা পরিচালিত একটি সর্বজনীন সেশন</translation>
 <translation id="3000461861112256445">মোনো অডিও</translation>
@@ -128,6 +138,7 @@
 <translation id="315116470104423982">মোবাইল ডেটা</translation>
 <translation id="3151786313568798007">সজ্জা</translation>
 <translation id="3153444934357957346">একধিক সাইন-ইনে আপনার কেবলমাত্র <ph name="MULTI_PROFILE_USER_LIMIT" />টি পর্যন্ত অ্যাকাউন্ট থাকতে পারে।</translation>
+<translation id="3202010236269062730">{NUM_DEVICES,plural, =1{একটি ডিভাইসে কানেক্ট রয়েছে}one{#টি ডিভাইসে কানেক্ট রয়েছে}other{#টি ডিভাইসে কানেক্ট রয়েছে}}</translation>
 <translation id="3236488194889173876">কোনো মোবাইল নেটওয়ার্ক উপলব্ধ নেই</translation>
 <translation id="3238765806255363838"><ph name="USERNAME" /> <ph name="MAIL" /></translation>
 <translation id="3294437725009624529">অতিথি</translation>
@@ -159,6 +170,7 @@
 <translation id="3784455785234192852">লক করুন</translation>
 <translation id="3798670284305777884">স্পিকার (অভ্যন্তরীণ)</translation>
 <translation id="380165613292957338">হাই, আমি কীভাবে সাহায্য করতে পারি?</translation>
+<translation id="383629559565718788">কীবোর্ড সেটিংস দেখান</translation>
 <translation id="3846575436967432996">কোনো নেটওয়ার্ক সংক্রান্ত তথ্য উপলব্ধ নেই</translation>
 <translation id="385051799172605136">ফিরুন</translation>
 <translation id="3891340733213178823">প্রস্থান করার জন্য দুবার Ctrl+Shift+Q টিপুন৷</translation>
@@ -174,8 +186,10 @@
 <translation id="4072264167173457037">মাঝারি সিগন্যাল</translation>
 <translation id="4200057768455216496">ডক করা ম্যাগনিফায়ারের জন্য আপনি শর্টকাট প্রেস করেছেন। আপনি কি এটি চালু করতে চান?</translation>
 <translation id="4217571870635786043">ডিক্টেশন</translation>
+<translation id="4261870227682513959">বিজ্ঞপ্তি সেটিংস দেখান। বিজ্ঞপ্তি বন্ধ আছে</translation>
 <translation id="4274921305979314545">আপনার ফোনের সাথে Chromebook কানেক্ট করুন</translation>
 <translation id="4279490309300973883">অনুকরণ করা হচ্ছে</translation>
+<translation id="4292681942966152062"><ph name="NETWORK_NAME" /> চালু করা হচ্ছে</translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4331809312908958774">Chrome OS</translation>
 <translation id="4338109981321384717">আতস কাচ</translation>
@@ -239,6 +253,7 @@
 <translation id="5673434351075758678">সেটিংস সিঙ্ক করার পরে "<ph name="FROM_LOCALE" />" থেকে "<ph name="TO_LOCALE" />" সেট করা হয়েছে।</translation>
 <translation id="574392208103952083">মাঝারি</translation>
 <translation id="5744083938413354016">ট্যাপ করে টেনে আনা</translation>
+<translation id="5750765938512549687">ব্লুটুথ বন্ধ আছে</translation>
 <translation id="5777841717266010279">স্ক্রিন শেয়ার করা থামাবেন?</translation>
 <translation id="57838592816432529">নিঃশব্দ করুন</translation>
 <translation id="5805697420284793859">উইন্ডো ম্যানেজার</translation>
@@ -273,12 +288,14 @@
 <translation id="6164005077879661055">একবার এই তত্ত্বাবধানে থাকা ব্যবহারকারী সরানো হলে এর সঙ্গে সংশ্লিষ্ট সমস্ত ফাইল এবং
 স্থানীয় ডেটা স্থায়ীভাবে মুছে ফেলা হবে৷ এই তত্ত্বাবধানে থাকা ব্যবহারকারীর জন্য পরিদর্শিত এবং সেটিংস <ph name="MANAGEMENT_URL" /> এ পরিচালকের কাছে এখনো দৃশ্যমান হতে পারে৷</translation>
 <translation id="6165508094623778733">আরও জানুন</translation>
+<translation id="6254629735336163724">স্ক্রিনটি ল্যান্ডস্কেপ মোডে লক করা আছে</translation>
 <translation id="6259254695169772643">বেছে নিতে স্টাইলাস ব্যবহার করুন</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: সক্রিয় করা হচ্ছে...</translation>
 <translation id="6284232397434400372">রেজোলিউশন পরিবর্তন করা হয়েছে</translation>
 <translation id="6297287540776456956">একটি অঞ্চল নির্বাচন করতে লেখনী ব্যবহার করুন</translation>
 <translation id="6310121235600822547"><ph name="DISPLAY_NAME" /> <ph name="ROTATION" /> আবর্তিত হয়েছে</translation>
 <translation id="632744581670418035">কীবোর্ড ওভারলে</translation>
+<translation id="6376931439017688372">ব্লুটুথ চালু আছে</translation>
 <translation id="639644700271529076">CAPS LOCK বন্ধ আছে</translation>
 <translation id="6406704438230478924">altgr</translation>
 <translation id="643147933154517414">সব সম্পন্ন!</translation>
@@ -314,6 +331,7 @@
 <translation id="6857811139397017780">সক্রিয় করুন <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">এই আপডেটটির জন্য আপনার ডিভাইস পাওয়ারওয়াশ করা প্রয়োজন। সাম্প্রতিক <ph name="SYSTEM_APP_NAME" /> আপডেট সম্পর্কে আরও জানুন।</translation>
 <translation id="6911468394164995108">অন্যতে যোগদান করুন ...</translation>
+<translation id="6972754398087986839">শুরু করুন</translation>
 <translation id="6981982820502123353">অ্যাক্সেযোগ্যতা</translation>
 <translation id="698231206551913481">একবার এই ব্যবহারকারীকে সরানো হলে এর সঙ্গে সংশ্লিষ্ট সমস্ত ফাইল এবং স্থানীয় ডেটা স্থায়ীভাবে মুছে ফেলা হবে।</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" />-এ আবার ব্যবহার করতে পারবেন।</translation>
@@ -322,6 +340,7 @@
 <translation id="7066646422045619941">এই নেটওয়ার্কটি আপনার প্রশাসকের দ্বারা অক্ষম করা হয়েছে৷</translation>
 <translation id="7067196344162293536">স্বতঃ ঘূর্ণন</translation>
 <translation id="7076293881109082629">প্রবেশ করুন হচ্ছে</translation>
+<translation id="7092922358121866860">নাইট লাইট সেটিংস দেখান</translation>
 <translation id="7098389117866926363">USB-C ডিভাইস (পিছনের বাঁ পোর্ট)</translation>
 <translation id="7131634465328662194">আপনি নিজে থেকেই সাইন-আউট হয়ে যাবেন।</translation>
 <translation id="7143207342074048698">সংযুক্ত হচ্ছে</translation>
@@ -357,6 +376,7 @@
 <translation id="7798302898096527229">Search টিপুন বা বাতিল করতে Shift টিপুন</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> এবং <ph name="MINUTE" /></translation>
 <translation id="7829386189513694949">জোরালো সিগন্যাল</translation>
+<translation id="7842211907556571265"><ph name="NETWORK_NAME" />-এ কানেক্ট করা হচ্ছে</translation>
 <translation id="7842569679327885685">সতর্কতা: পরীক্ষামূলক বৈশিষ্ট্য</translation>
 <translation id="7846634333498149051">কীবোর্ড</translation>
 <translation id="790040513076446191">গোপনীয়তা-সংক্রান্ত সেটিংস নিপূণভাবে ব্যবহার করুন</translation>
@@ -397,18 +417,24 @@
 <translation id="8484916590211895857"><ph name="NAME" />: আবার সংযোগ করছে...</translation>
 <translation id="8513108775083588393">নিজে থেকে ঘুরবে</translation>
 <translation id="8517041960877371778">আপনার <ph name="DEVICE_TYPE" /> চালু থাকা অবস্থায় চার্জ নাও হতে পারে।</translation>
+<translation id="8627191004499078455"><ph name="DEVICE_NAME" />-এর সাথে কানেক্ট হয়েছে</translation>
 <translation id="8639760480004882931"><ph name="PERCENTAGE" /> বাকি আছে</translation>
 <translation id="8649101189709089199">বাছুন ও শুনুন</translation>
 <translation id="8652175077544655965">সেটিংস বন্ধ করুন</translation>
+<translation id="8653151467777939995">বিজ্ঞপ্তি সেটিংস দেখান। বিজ্ঞপ্তি চালু আছে</translation>
+<translation id="8664753092453405566">নেটওয়ার্ক তালিকা দেখান। <ph name="STATE_TEXT" /></translation>
 <translation id="8673028979667498656">২৭০°</translation>
 <translation id="8676770494376880701">নিম্ন শক্তির চার্জার সংযুক্ত করা হয়েছে</translation>
 <translation id="8683506306463609433">পারফরম্যান্স ট্রেস করার বিকল্প চালু আছে</translation>
 <translation id="8734991477317290293">এটি আপনার পাসওয়ার্ড চুরি করার চেষ্টা করতে পারে</translation>
+<translation id="8735953464173050365">কীবোর্ড সেটিংস দেখান। <ph name="KEYBOARD_NAME" /> বেছে নেওয়া হয়েছে</translation>
+<translation id="875593634123171288">VPN সেটিংস দেখান</translation>
 <translation id="8809737090443522491">একটি অ্যাপ বা ডকুমেন্টের নাম টাইপ করুন</translation>
 <translation id="8814190375133053267">ওয়াই-ফাই</translation>
 <translation id="8825534185036233643">দুটির বেশি প্রদর্শনের সাথে মিররিং সমর্থিত নয়।</translation>
 <translation id="8828714802988429505">৯০°</translation>
 <translation id="8841375032071747811">ফিরে যাওয়ার বোতাম</translation>
+<translation id="8843682306134542540">রোটেশন লক টগল করুন। <ph name="STATE_TEXT" /></translation>
 <translation id="8850991929411075241">Search+Esc</translation>
 <translation id="8870509716567206129">অ্যাপ্লিকেশনটি বিভক্ত-স্ক্রিন সমর্থন করে না৷</translation>
 <translation id="8874184842967597500">সংযুক্ত নয়</translation>
diff --git a/ash/strings/ash_strings_ca.xtb b/ash/strings/ash_strings_ca.xtb
index a54aa8a..8f9be39 100644
--- a/ash/strings/ash_strings_ca.xtb
+++ b/ash/strings/ash_strings_ca.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Activa <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Aquesta actualització requereix executar la funció Powerwash al dispositiu. Obtén més informació sobre l'última actualització de <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Connecta't a una altra xarxa...</translation>
+<translation id="6972754398087986839">Comença</translation>
 <translation id="6981982820502123353">Accessibilitat</translation>
 <translation id="698231206551913481">Tots els fitxers i les dades locals associats amb aquest usuari se suprimiran definitivament quan aquest usuari se suprimeixi.</translation>
 <translation id="7015766095477679451">Pots tornar a aquesta hora: <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_cs.xtb b/ash/strings/ash_strings_cs.xtb
index e1093b1..7b18fd7 100644
--- a/ash/strings/ash_strings_cs.xtb
+++ b/ash/strings/ash_strings_cs.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktivovat: <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Kvůli této aktualizaci je potřeba zařízení pomocí funkce Powerwash obnovit do továrního nastavení. Viz další informace o nejnovější aktualizaci systému <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Připojit k jiné...</translation>
+<translation id="6972754398087986839">Začínáme</translation>
 <translation id="6981982820502123353">Usnadnění</translation>
 <translation id="698231206551913481">Po odebrání tohoto uživatele budou trvale smazány všechny soubory a místní data, která jsou k němu přiřazena.</translation>
 <translation id="7015766095477679451">Vraťte se v <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_da.xtb b/ash/strings/ash_strings_da.xtb
index 16b9242e..1f38646 100644
--- a/ash/strings/ash_strings_da.xtb
+++ b/ash/strings/ash_strings_da.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Aktivér <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Denne opdatering kræver, at der udføres en powerwash på din enhed. Få flere oplysninger om den nyeste <ph name="SYSTEM_APP_NAME" />-opdatering.</translation>
 <translation id="6911468394164995108">Vælg et andet...</translation>
+<translation id="6972754398087986839">Kom godt i gang</translation>
 <translation id="6981982820502123353">Hjælpefunktioner</translation>
 <translation id="698231206551913481">Alle filer og lokale data, der er knyttet til denne bruger, slettes permanent, når brugeren fjernes.</translation>
 <translation id="7015766095477679451">Vend tilbage kl. <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_de.xtb b/ash/strings/ash_strings_de.xtb
index 66bb766..d389bf5 100644
--- a/ash/strings/ash_strings_de.xtb
+++ b/ash/strings/ash_strings_de.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> aktivieren</translation>
 <translation id="6910714959251846841">Damit dieses Update installiert werden kann, muss auf Ihrem Gerät ein Powerwash durchgeführt werden. Informieren Sie sich über das aktuelle <ph name="SYSTEM_APP_NAME" />-Update.</translation>
 <translation id="6911468394164995108">Andere Netzwerke...</translation>
+<translation id="6972754398087986839">Erste Schritte</translation>
 <translation id="6981982820502123353">Bedienungshilfen</translation>
 <translation id="698231206551913481">Durch das Entfernen des Nutzers werden alle mit ihm verknüpften Dateien und lokalen Daten endgültig gelöscht.</translation>
 <translation id="7015766095477679451">Um <ph name="COME_BACK_TIME" /> können Sie weitermachen.</translation>
diff --git a/ash/strings/ash_strings_el.xtb b/ash/strings/ash_strings_el.xtb
index d32cb29..33be9dbb 100644
--- a/ash/strings/ash_strings_el.xtb
+++ b/ash/strings/ash_strings_el.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Ενεργοποίηση <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Αυτή η ενημέρωση απαιτεί την εκτέλεση powerwash στη συσκευή σας. Μάθετε περισσότερα σχετικά με την πιο πρόσφατη ενημέρωση της εφαρμογής <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Συμμετοχή σε άλλο…</translation>
+<translation id="6972754398087986839">Έναρξη</translation>
 <translation id="6981982820502123353">Προσβασιμότητα</translation>
 <translation id="698231206551913481">Όλα τα αρχεία και τα τοπικά δεδομένα που σχετίζονται με τον χρήστη θα διαγραφούν οριστικά μόλις καταργηθεί ο χρήστης.</translation>
 <translation id="7015766095477679451">Επιστρέψτε ξανά στις <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_en-GB.xtb b/ash/strings/ash_strings_en-GB.xtb
index 1d8a1f1..4f1663b6 100644
--- a/ash/strings/ash_strings_en-GB.xtb
+++ b/ash/strings/ash_strings_en-GB.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Activate <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">This update requires powerwashing of your device. Learn more about the latest <ph name="SYSTEM_APP_NAME" /> update.</translation>
 <translation id="6911468394164995108">Join other ...</translation>
+<translation id="6972754398087986839">Get Started</translation>
 <translation id="6981982820502123353">Accessibility</translation>
 <translation id="698231206551913481">All files and local data associated with this user will be permanently deleted once this user is removed.</translation>
 <translation id="7015766095477679451">Come back at <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_es-419.xtb b/ash/strings/ash_strings_es-419.xtb
index 2904486e..c959b90 100644
--- a/ash/strings/ash_strings_es-419.xtb
+++ b/ash/strings/ash_strings_es-419.xtb
@@ -7,6 +7,7 @@
 <translation id="1037492556044956303">Se agregó <ph name="DEVICE_NAME" /></translation>
 <translation id="1056775291175587022">No hay redes</translation>
 <translation id="1059194134494239015"><ph name="DISPLAY_NAME" />: <ph name="RESOLUTION" /></translation>
+<translation id="1104084341931202936">Mostrar la configuración de accesibilidad</translation>
 <translation id="1104621072296271835">Tus dispositivos funcionan incluso mejor juntos</translation>
 <translation id="112308213915226829">Ocultar la biblioteca automáticamente</translation>
 <translation id="1153356358378277386">Dispositivos sincronizados</translation>
@@ -20,17 +21,20 @@
 <translation id="1279938420744323401"><ph name="DISPLAY_NAME" /> (<ph name="ANNOTATION" />)</translation>
 <translation id="1290331692326790741">Señal débil</translation>
 <translation id="1293264513303784526">Dispositivo USB-C (puerto izquierdo)</translation>
+<translation id="1302880136325416935">Mostrar la configuración de Bluetooth: <ph name="STATE_TEXT" /></translation>
 <translation id="1346748346194534595">Derecha</translation>
 <translation id="1351937230027495976">Contraer menú</translation>
 <translation id="1383876407941801731">Buscar</translation>
 <translation id="1467432559032391204">Izquierda</translation>
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">Selector</translation>
+<translation id="1520303207432623762">{NUM_APPS,plural, =1{Mostrar la configuración de las notificaciones: Están desactivadas para una app}other{Mostrar la configuración de las notificaciones: Están desactivadas para # apps}}</translation>
 <translation id="1525508553941733066">IGNORAR</translation>
 <translation id="1537254971476575106">Lupa de pantalla completa</translation>
 <translation id="15373452373711364">Cursor del mouse grande</translation>
 <translation id="1550523713251050646">Haz clic para obtener más opciones</translation>
 <translation id="1567387640189251553">Se conectó otro teclado desde la última vez que ingresaste tu contraseña. Es posible que alguien esté intentando determinar qué teclas presionaste.</translation>
+<translation id="1570871743947603115">Activar o desactivar Bluetooth: <ph name="STATE_TEXT" /></translation>
 <translation id="1608626060424371292">Eliminar este usuario</translation>
 <translation id="1621499497873603021">Tiempo restante hasta que se agote la batería: <ph name="TIME_LEFT" /></translation>
 <translation id="1658406695958299976">Todavía no se pudo verificar tu contraseña. Ten en cuenta que, si cambiaste tu contraseña recientemente, podrás usar la nueva cuando salgas. Aquí deberás usar la contraseña anterior.</translation>
@@ -40,6 +44,7 @@
 <translation id="1743570585616704562">No se reconoció</translation>
 <translation id="1746730358044914197">Tu administrador configura los métodos de entrada.</translation>
 <translation id="1747827819627189109">Teclado en pantalla habilitado</translation>
+<translation id="1761222317188459878">Activar o desactivar la conexión de red: <ph name="STATE_TEXT" /></translation>
 <translation id="1823873187264960516">Ethernet: <ph name="ADDRESS" /></translation>
 <translation id="1836215606488044471">Asistente (cargando…)</translation>
 <translation id="1841545962859478868">Es posible que el administrador de dispositivos supervise lo siguiente:</translation>
@@ -63,6 +68,7 @@
 <translation id="2049639323467105390"><ph name="DOMAIN" /> administra esta cuenta.</translation>
 <translation id="2050339315714019657">Vertical</translation>
 <translation id="2067602449040652523">Brillo del teclado</translation>
+<translation id="2075212959500165896">Realizaste demasiados intentos. Pruébalo de nuevo más tarde.</translation>
 <translation id="2081529251031312395">$1 podrá acceder más tarde.</translation>
 <translation id="2127372758936585790">Carga lenta</translation>
 <translation id="2135456203358955318">Lupa con vista acoplada</translation>
@@ -76,12 +82,15 @@
 <translation id="2303600792989757991">Activar vista general de ventanas</translation>
 <translation id="2338501278241028356">Activar Bluetooth para buscar los dispositivos cercanos</translation>
 <translation id="2339073806695260576">Presiona el botón de la pluma stylus en la biblioteca para tomar notas y capturas de pantalla, y usar el puntero láser o la lupa.</translation>
+<translation id="2341729377289034582">Se bloqueó en posición vertical</translation>
 <translation id="2352467521400612932">Configuración de la pluma stylus</translation>
 <translation id="2354174487190027830">Activación de <ph name="NAME" /></translation>
 <translation id="2359808026110333948">Continuar</translation>
 <translation id="2365393535144473978">Si habilitas los datos móviles, se habilitará Bluetooth.</translation>
 <translation id="2391579633712104609">180°</translation>
+<translation id="239188844683466770">Activar o desactivar la función "No interrumpir"</translation>
 <translation id="2412593942846481727">Actualización disponible</translation>
+<translation id="2416346634399901812">Conexión establecida con <ph name="NETWORK_NAME" /></translation>
 <translation id="2429753432712299108">El dispositivo Bluetooth "<ph name="DEVICE_NAME" />" solicita permiso para sincronizarse. Antes de aceptar, debes confirmar que aparece la siguiente clave de contraseña en el dispositivo: <ph name="PASSKEY" />.</translation>
 <translation id="2482878487686419369">Notificaciones</translation>
 <translation id="2484513351006226581">Presiona <ph name="KEYBOARD_SHORTCUT" /> para cambiar de diseño de teclado.</translation>
@@ -114,6 +123,7 @@
 <translation id="2946119680249604491">Agregar conexión</translation>
 <translation id="2961963223658824723">Se produjo un error. Vuelve a intentarlo en unos segundos.</translation>
 <translation id="2963773877003373896">mod3</translation>
+<translation id="2995447421581609334">Mostrar dispositivos de transmisión</translation>
 <translation id="2996462380875591307">Se habilitó la lupa con vista acoplada. Presiona Ctrl+Buscar+D de nuevo para desactivarla.</translation>
 <translation id="2999742336789313416"><ph name="DISPLAY_NAME" /> es una sesión pública administrada por <ph name="DOMAIN" />.</translation>
 <translation id="3000461861112256445">Audio mono</translation>
@@ -128,6 +138,7 @@
 <translation id="315116470104423982">Datos móviles</translation>
 <translation id="3151786313568798007">Orientación</translation>
 <translation id="3153444934357957346">Puedes acceder a un máximo de <ph name="MULTI_PROFILE_USER_LIMIT" /> cuentas con acceso múltiple.</translation>
+<translation id="3202010236269062730">{NUM_DEVICES,plural, =1{Conectado a un dispositivo}other{Conectado a # dispositivos}}</translation>
 <translation id="3236488194889173876">No hay redes móviles disponibles</translation>
 <translation id="3238765806255363838"><ph name="USERNAME" /> <ph name="MAIL" /></translation>
 <translation id="3294437725009624529">Invitado</translation>
@@ -160,6 +171,7 @@
 <translation id="3784455785234192852">Bloquear</translation>
 <translation id="3798670284305777884">Altavoz (interno)</translation>
 <translation id="380165613292957338">Hola, ¿cómo puedo ayudarte?</translation>
+<translation id="383629559565718788">Mostrar la configuración del teclado</translation>
 <translation id="3846575436967432996">No hay información de red disponible.</translation>
 <translation id="385051799172605136">Atrás</translation>
 <translation id="3891340733213178823">Presiona Ctrl + Mayús + Q dos veces para salir.</translation>
@@ -175,8 +187,10 @@
 <translation id="4072264167173457037">Señal media</translation>
 <translation id="4200057768455216496">Presionaste la combinación de teclas para activar la lupa con vista acoplada. ¿Quieres activarla?</translation>
 <translation id="4217571870635786043">Dictado</translation>
+<translation id="4261870227682513959">Mostrar la configuración de las notificaciones: Están desactivadas</translation>
 <translation id="4274921305979314545">Conecta tu Chromebook con el teléfono</translation>
 <translation id="4279490309300973883">Duplicando</translation>
+<translation id="4292681942966152062">Activando la red <ph name="NETWORK_NAME" /></translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4331809312908958774">SO Chrome</translation>
 <translation id="4338109981321384717">Lupa</translation>
@@ -191,7 +205,7 @@
 <translation id="4508225577814909926"><ph name="NAME" />: Conectando...</translation>
 <translation id="4513946894732546136">Comentario</translation>
 <translation id="4527045527269911712">El dispositivo Bluetooth "<ph name="DEVICE_NAME" />" solicita permiso para sincronizarse.</translation>
-<translation id="453661520163887813">Tiempo restante hasta completarse la carga: <ph name="TIME" /></translation>
+<translation id="453661520163887813"><ph name="TIME" /> para completar carga</translation>
 <translation id="4544944664594876241">Se modificó el acceso directo para bloquear la pantalla. Utiliza <ph name="NEW_SHORTCUT" /> en vez de <ph name="OLD_SHORTCUT" />.</translation>
 <translation id="4564869809620998694">Servicio de fuentes</translation>
 <translation id="4570957409596482333">Botón de Seleccionar para pronunciar</translation>
@@ -240,6 +254,7 @@
 <translation id="5673434351075758678">De "<ph name="FROM_LOCALE" />" a "<ph name="TO_LOCALE" />" después de sincronizar tu configuración</translation>
 <translation id="574392208103952083">Mediano</translation>
 <translation id="5744083938413354016">Función tocar y arrastrar</translation>
+<translation id="5750765938512549687">Se activó la conexión Bluetooth</translation>
 <translation id="5777841717266010279">¿Dejar de compartir la pantalla?</translation>
 <translation id="57838592816432529">Silenciar</translation>
 <translation id="5805697420284793859">Administrador de ventanas</translation>
@@ -273,12 +288,14 @@
 <translation id="615957422585914272">Mostrar el teclado en pantalla</translation>
 <translation id="6164005077879661055">Todos los archivos y los datos locales asociados al usuario supervisado se eliminarán de forma permanente una vez que se elimine este usuario supervisado. Es posible que el administrador pueda seguir viendo la configuración y los sitios web visitados de este usuario supervisado en <ph name="MANAGEMENT_URL" />.</translation>
 <translation id="6165508094623778733">Más información</translation>
+<translation id="6254629735336163724">Se bloqueó en posición horizontal</translation>
 <translation id="6259254695169772643">Usa tu pluma stylus para realizar una selección</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: Activando...</translation>
 <translation id="6284232397434400372">Se cambió la resolución</translation>
 <translation id="6297287540776456956">Usa la pluma stylus para seleccionar una región</translation>
 <translation id="6310121235600822547"><ph name="DISPLAY_NAME" /> se giró a <ph name="ROTATION" />.</translation>
 <translation id="632744581670418035">Superposición de teclado</translation>
+<translation id="6376931439017688372">Se activó la conexión Bluetooth</translation>
 <translation id="639644700271529076">El bloqueo de mayúsculas está desactivado.</translation>
 <translation id="6406704438230478924">altgr</translation>
 <translation id="643147933154517414">Todo listo</translation>
@@ -314,6 +331,7 @@
 <translation id="6857811139397017780">Activar <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Esta actualización requiere que apliques la función Powerwash en tu dispositivo. Obtén más información sobre la actualización más reciente de <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Conectarte a otra red...</translation>
+<translation id="6972754398087986839">Comenzar</translation>
 <translation id="6981982820502123353">Accesibilidad</translation>
 <translation id="698231206551913481">Todos los archivos y datos locales asociados a este usuario se borrarán de forma permanente una vez que se quite este usuario.</translation>
 <translation id="7015766095477679451">Regresa a las <ph name="COME_BACK_TIME" />.</translation>
@@ -322,6 +340,7 @@
 <translation id="7066646422045619941">El administrador inhabilitó esta red.</translation>
 <translation id="7067196344162293536">Rotación automática</translation>
 <translation id="7076293881109082629">Accediendo</translation>
+<translation id="7092922358121866860">Mostrar la configuración de la función "Luz nocturna"</translation>
 <translation id="7098389117866926363">Dispositivo USB-C (puerto izquierdo en la parte posterior)</translation>
 <translation id="7131634465328662194">Tu sesión se cerrará automáticamente.</translation>
 <translation id="7143207342074048698">Conectando</translation>
@@ -357,6 +376,7 @@
 <translation id="7798302898096527229">Presiona mayúscula o la tecla de búsqueda para cancelarlo.</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> y <ph name="MINUTE" /></translation>
 <translation id="7829386189513694949">Señal fuerte</translation>
+<translation id="7842211907556571265">Conectando a <ph name="NETWORK_NAME" /></translation>
 <translation id="7842569679327885685">Advertencia: Función experimental</translation>
 <translation id="7846634333498149051">Teclado</translation>
 <translation id="790040513076446191">Manipular la configuración relacionada con la privacidad</translation>
@@ -397,18 +417,24 @@
 <translation id="8484916590211895857"><ph name="NAME" />: Restableciendo conexión…</translation>
 <translation id="8513108775083588393">Giro automático</translation>
 <translation id="8517041960877371778">Tu <ph name="DEVICE_TYPE" /> podría no cargarse si el dispositivo está encendido.</translation>
+<translation id="8627191004499078455">Conectado a <ph name="DEVICE_NAME" /></translation>
 <translation id="8639760480004882931"><ph name="PERCENTAGE" /> restante</translation>
 <translation id="8649101189709089199">Seleccionar para pronunciar</translation>
 <translation id="8652175077544655965">Cerrar configuración</translation>
+<translation id="8653151467777939995">Mostrar la configuración de las notificaciones: Están activadas</translation>
+<translation id="8664753092453405566">Mostrar la lista de redes: <ph name="STATE_TEXT" /></translation>
 <translation id="8673028979667498656">270°</translation>
 <translation id="8676770494376880701">Cargador de baja potencia conectado</translation>
 <translation id="8683506306463609433">Registro del rendimiento activado</translation>
 <translation id="8734991477317290293">Es posible que alguien esté intentando determinar qué teclas presionaste</translation>
+<translation id="8735953464173050365">Mostrar la configuración del teclado: Está seleccionado el teclado <ph name="KEYBOARD_NAME" /></translation>
+<translation id="875593634123171288">Mostrar la configuración de la VPN</translation>
 <translation id="8809737090443522491">Escribe el nombre de la app o el documento</translation>
 <translation id="8814190375133053267">Wi-Fi</translation>
 <translation id="8825534185036233643">La duplicación con más de dos pantallas no es compatible.</translation>
 <translation id="8828714802988429505">90°</translation>
 <translation id="8841375032071747811">Botón Atrás</translation>
+<translation id="8843682306134542540">Activar o desactivar el bloqueo de rotación: <ph name="STATE_TEXT" /></translation>
 <translation id="8850991929411075241">Tecla de búsqueda + Esc</translation>
 <translation id="8870509716567206129">La app no es compatible con la función de pantalla dividida.</translation>
 <translation id="8874184842967597500">No conectado</translation>
diff --git a/ash/strings/ash_strings_es.xtb b/ash/strings/ash_strings_es.xtb
index 9d04d5f9..7b8ab03 100644
--- a/ash/strings/ash_strings_es.xtb
+++ b/ash/strings/ash_strings_es.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Activar <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Esta actualización le hará un Powerwash a tu dispositivo. Consulta más información sobre la última actualización de <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Conectarse a otra red...</translation>
+<translation id="6972754398087986839">Empezar</translation>
 <translation id="6981982820502123353">Accesibilidad</translation>
 <translation id="698231206551913481">Una vez que se haya quitado este usuario, todos los archivos y datos asociados a él se eliminarán de forma permanente.</translation>
 <translation id="7015766095477679451">Hora a la que puedes volver: <ph name="COME_BACK_TIME" /></translation>
diff --git a/ash/strings/ash_strings_et.xtb b/ash/strings/ash_strings_et.xtb
index 84b3ff5f..3b9fd041 100644
--- a/ash/strings/ash_strings_et.xtb
+++ b/ash/strings/ash_strings_et.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Aktiveeri <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Värskenduse jaoks on vajalik seadme powerwash. Vaadake lisateavet operatsioonisüsteemi <ph name="SYSTEM_APP_NAME" /> uusima värskenduse kohta.</translation>
 <translation id="6911468394164995108">Liitu muu võrguga ...</translation>
+<translation id="6972754398087986839">Alustamine</translation>
 <translation id="6981982820502123353">Juurdepääsetavus</translation>
 <translation id="698231206551913481">Kõik selle kasutajaga seotud failid ja kohalikud andmed kustutatakse jäädavalt kohe, kui see kasutaja eemaldatakse.</translation>
 <translation id="7015766095477679451">Tulge tagasi kell <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_fa.xtb b/ash/strings/ash_strings_fa.xtb
index 63ba9251..1328a90 100644
--- a/ash/strings/ash_strings_fa.xtb
+++ b/ash/strings/ash_strings_fa.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">فعال سازی <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">‏این به‌روزرسانی نیاز به انجام powerwash دستگاهتان دارد. درباره جدیدترین به‌روزرسانی <ph name="SYSTEM_APP_NAME" /> بیشتر بدانید.</translation>
 <translation id="6911468394164995108">پیوستن به شبکه دیگر…</translation>
+<translation id="6972754398087986839">شروع به کار</translation>
 <translation id="6981982820502123353">قابلیت دسترسی</translation>
 <translation id="698231206551913481">اگر کاربر حذف شود، همه فایل‌ها و داده‌های محلی مربوط به او به‌طور دائم حذف خواهند شد.</translation>
 <translation id="7015766095477679451">ساعت <ph name="COME_BACK_TIME" /> دوباره برگردید.</translation>
diff --git a/ash/strings/ash_strings_fi.xtb b/ash/strings/ash_strings_fi.xtb
index c9d2e093..9e24448f 100644
--- a/ash/strings/ash_strings_fi.xtb
+++ b/ash/strings/ash_strings_fi.xtb
@@ -333,6 +333,7 @@
 <translation id="6857811139397017780">Aktivoi <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Tämän päivityksen asennus edellyttää laitteen powerwashia. Lue lisää uusimmasta <ph name="SYSTEM_APP_NAME" /> ‑päivityksestä.</translation>
 <translation id="6911468394164995108">Liity muuhun verkkoon...</translation>
+<translation id="6972754398087986839">Aloitusopas</translation>
 <translation id="6981982820502123353">Esteettömyys</translation>
 <translation id="698231206551913481">Kun käyttäjä poistetaan, kaikki kyseiseen käyttäjään yhdistetyt tiedostot ja paikalliset tiedot poistetaan pysyvästi.</translation>
 <translation id="7015766095477679451">Palaa kello <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_fil.xtb b/ash/strings/ash_strings_fil.xtb
index 7580f86..621469970 100644
--- a/ash/strings/ash_strings_fil.xtb
+++ b/ash/strings/ash_strings_fil.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">I-activate <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Kinakailangang i-powerwash ang iyong device para sa update na ito. Matuto pa tungkol sa pinakabagong update sa <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Sumali sa iba...</translation>
+<translation id="6972754398087986839">Magsimula</translation>
 <translation id="6981982820502123353">Pagiging Maa-access</translation>
 <translation id="698231206551913481">Permanenteng made-delete ang lahat ng file at lokal na data na nauugnay sa user na ito kapag inalis na ang user na ito.</translation>
 <translation id="7015766095477679451">Bumalik nang <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_fr.xtb b/ash/strings/ash_strings_fr.xtb
index 1631ad1..2588ecf9 100644
--- a/ash/strings/ash_strings_fr.xtb
+++ b/ash/strings/ash_strings_fr.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Activer <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Cette mise à jour nécessite que vous utilisiez la fonctionnalité Powerwash sur votre appareil. Obtenez de plus amples informations sur la dernière mise à jour <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Autre réseau…</translation>
+<translation id="6972754398087986839">Démarrer</translation>
 <translation id="6981982820502123353">Accessibilité</translation>
 <translation id="698231206551913481">L'ensemble des données locales et des fichiers associés à cet utilisateur seront définitivement supprimés en même temps que ce dernier.</translation>
 <translation id="7015766095477679451">Revenez à <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_gu.xtb b/ash/strings/ash_strings_gu.xtb
index 8aa8f0b..8646167 100644
--- a/ash/strings/ash_strings_gu.xtb
+++ b/ash/strings/ash_strings_gu.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">સક્રિય કરો <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">આ અપડેટ માટે તમારા ઉપકરણને પાવરવોશ કરવું જરૂરી છે. નવીનતમ <ph name="SYSTEM_APP_NAME" /> અપડેટ વિશે વધુ જાણો.</translation>
 <translation id="6911468394164995108">અન્યથી જોડાઓ...</translation>
+<translation id="6972754398087986839">પ્રારંભ કરો</translation>
 <translation id="6981982820502123353">ઍક્સેસિબિલિટી</translation>
 <translation id="698231206551913481">આ વપરાશકર્તા દૂર કરી દેવામાં આવે તે પછી આ વપરાશકર્તા સાથે સંકળાયેલ તમામ ફાઇલો અને સ્થાનિક ડેટા કાયમીરૂપે કાઢી નાખવામાં આવશે.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> વાગ્યે પાછા આવો.</translation>
diff --git a/ash/strings/ash_strings_hi.xtb b/ash/strings/ash_strings_hi.xtb
index c62f120d..a5d08a7f 100644
--- a/ash/strings/ash_strings_hi.xtb
+++ b/ash/strings/ash_strings_hi.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> को सक्रिय करें</translation>
 <translation id="6910714959251846841">इस अपडेट के लिए आपके डिवाइस को पावरवॉश करना ज़रूरी है. <ph name="SYSTEM_APP_NAME" /> के नए अपडेट के बारे में ज़्यादा जानें.</translation>
 <translation id="6911468394164995108">अन्य में शामिल हों...</translation>
+<translation id="6972754398087986839">आरंभ करें</translation>
 <translation id="6981982820502123353">पहुंच क्षमता</translation>
 <translation id="698231206551913481">इस उपयोगकर्ता को हटाए जाने पर, इससे जुड़ीं सभी फ़ाइलों और स्थानीय डेटा को हमेशा के लिए मिटा दिया जाएगा.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> बजे फिर से देखें.</translation>
diff --git a/ash/strings/ash_strings_hr.xtb b/ash/strings/ash_strings_hr.xtb
index 703f4dc..cb7cf14 100644
--- a/ash/strings/ash_strings_hr.xtb
+++ b/ash/strings/ash_strings_hr.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktiviraj <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Ovo ažuriranje zahtijeva powerwashing uređaja. Saznajte više o najnovijem ažuriranju za <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Pridruži se drugoj...</translation>
+<translation id="6972754398087986839">Početak upotrebe</translation>
 <translation id="6981982820502123353">Pristupačnost</translation>
 <translation id="698231206551913481">Sve datoteke i lokalni podaci povezani s ovim korisnikom trajno će se izbrisati nakon uklanjanja korisnika.</translation>
 <translation id="7015766095477679451">Vratite se u <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_hu.xtb b/ash/strings/ash_strings_hu.xtb
index 05182fb..4f7eb260 100644
--- a/ash/strings/ash_strings_hu.xtb
+++ b/ash/strings/ash_strings_hu.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> aktiválása</translation>
 <translation id="6910714959251846841">Eszköze frissítéséhez powerwash szükséges. További információ a legújabb <ph name="SYSTEM_APP_NAME" />-frissítésről.</translation>
 <translation id="6911468394164995108">Csatlakozás másik hálózathoz...</translation>
+<translation id="6972754398087986839">Első lépések</translation>
 <translation id="6981982820502123353">Kisegítő lehetőségek</translation>
 <translation id="698231206551913481">A felhasználó eltávolításakor az összes hozzá tartozó fájl és helyi adat is véglegesen törlődik.</translation>
 <translation id="7015766095477679451">Térjen vissza ekkor: <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_id.xtb b/ash/strings/ash_strings_id.xtb
index ea0e8999..37e583eb 100644
--- a/ash/strings/ash_strings_id.xtb
+++ b/ash/strings/ash_strings_id.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktifkan <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Update ini memerlukan powerwash perangkat. Pelajari lebih lanjut update <ph name="SYSTEM_APP_NAME" /> terbaru.</translation>
 <translation id="6911468394164995108">Bergabung dengan lainnya...</translation>
+<translation id="6972754398087986839">Mulai</translation>
 <translation id="6981982820502123353">Aksesibilitas</translation>
 <translation id="698231206551913481">Semua file dan data lokal yang dikaitkan ke pengguna ini akan dihapus secara permanen setelah pengguna ini dihapus.</translation>
 <translation id="7015766095477679451">Coba lagi pukul <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_it.xtb b/ash/strings/ash_strings_it.xtb
index 918288b..91a3755 100644
--- a/ash/strings/ash_strings_it.xtb
+++ b/ash/strings/ash_strings_it.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Attiva <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Questo aggiornamento richiede il powerwash del dispositivo. Leggi ulteriori informazioni sull'ultimo aggiornamento di <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Connetti a un'altra...</translation>
+<translation id="6972754398087986839">Inizia</translation>
 <translation id="6981982820502123353">Accessibilità</translation>
 <translation id="698231206551913481">Tutti i file e i dati locali associati a questo utente verranno eliminati definitivamente in seguito alla rimozione dell'utente.</translation>
 <translation id="7015766095477679451">Ritorna alle ore <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_iw.xtb b/ash/strings/ash_strings_iw.xtb
index dff8a4d..3a7b6e7 100644
--- a/ash/strings/ash_strings_iw.xtb
+++ b/ash/strings/ash_strings_iw.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">הפעל את <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">‏כדי להתקין את העדכון הזה צריך לבצע Powerwash של המכשיר. אפשר לקרוא מידע נוסף על העדכון האחרון של <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">הצטרף לרשת אחרת...</translation>
+<translation id="6972754398087986839">תחילת העבודה</translation>
 <translation id="6981982820502123353">נגישות</translation>
 <translation id="698231206551913481">כל הקבצים והנתונים המשויכים למשתמש זה יימחקו לצמיתות ברגע שהמשתמש יוסר.</translation>
 <translation id="7015766095477679451">אפשר לחזור בשעה <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_ja.xtb b/ash/strings/ash_strings_ja.xtb
index 694d393..adf8289 100644
--- a/ash/strings/ash_strings_ja.xtb
+++ b/ash/strings/ash_strings_ja.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> を有効にする</translation>
 <translation id="6910714959251846841">このアップデートを適用するには端末で Powerwash を実行する必要があります。<ph name="SYSTEM_APP_NAME" /> の最新アップデートの詳細をご確認ください。</translation>
 <translation id="6911468394164995108">他のネットワークに接続...</translation>
+<translation id="6972754398087986839">開始する</translation>
 <translation id="6981982820502123353">ユーザー補助機能</translation>
 <translation id="698231206551913481">このユーザーを削除すると、このユーザーに関連付けられているファイルとローカルデータもすべて完全に削除されます。</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> になったら利用を再開できます。</translation>
diff --git a/ash/strings/ash_strings_kn.xtb b/ash/strings/ash_strings_kn.xtb
index 8c29707..08a608d 100644
--- a/ash/strings/ash_strings_kn.xtb
+++ b/ash/strings/ash_strings_kn.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">ಸಕ್ರಿಯಗೊಳಿಸಿ<ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">ಈ ಅಪ್‌ಡೇಟ್‌ಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಪವರ್‌ವಾಷ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ. ಇತ್ತೀಚಿನ <ph name="SYSTEM_APP_NAME" /> ಅಪ್‌ಡೇಟ್ ಕುರಿತು ಇನ್ನಷ್ಟು ತಿಳಿದುಕೊಳ್ಳಿ.</translation>
 <translation id="6911468394164995108">ಇತರರನ್ನು ಸೇರಿ...</translation>
+<translation id="6972754398087986839">ಪ್ರಾರಂಭಗೊಂಡಿದೆ</translation>
 <translation id="6981982820502123353">ಪ್ರವೇಶ</translation>
 <translation id="698231206551913481">ಒಮ್ಮೆ ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಿದಾಗ ಈ ಬಳಕೆದಾರರೊಂದಿಗೆ ಸಂಯೋಜಿತವಾಗಿರುವ ಎಲ್ಲಾ ಫೈಲ್‌ಗಳು ಮತ್ತು ಸ್ಥಳೀಯ ಡೇಟಾವನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸಲಾಗುತ್ತದೆ.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> ಸಮಯಕ್ಕೆ ಹಿಂತಿರುಗಿ</translation>
diff --git a/ash/strings/ash_strings_ko.xtb b/ash/strings/ash_strings_ko.xtb
index 304333f..9d059229 100644
--- a/ash/strings/ash_strings_ko.xtb
+++ b/ash/strings/ash_strings_ko.xtb
@@ -204,7 +204,7 @@
 <translation id="4508225577814909926"><ph name="NAME" />: 연결하는 중...</translation>
 <translation id="4513946894732546136">문제 신고</translation>
 <translation id="4527045527269911712">블루투스 기기 '<ph name="DEVICE_NAME" />'에서 페어링 허가를 요청합니다.</translation>
-<translation id="453661520163887813">충전 완료까지 <ph name="TIME" /> 남음</translation>
+<translation id="453661520163887813"><ph name="TIME" /> 후 충전 완료</translation>
 <translation id="4544944664594876241">화면 잠금 단축키가 변경되었습니다. <ph name="OLD_SHORTCUT" /> 대신 <ph name="NEW_SHORTCUT" />을(를) 사용하세요.</translation>
 <translation id="4564869809620998694">글꼴 서비스</translation>
 <translation id="4570957409596482333">텍스트 읽어주기 버튼</translation>
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> 활성화</translation>
 <translation id="6910714959251846841">업데이트하려면 기기에서 파워워시를 실행해야 합니다. 최신 <ph name="SYSTEM_APP_NAME" /> 업데이트에 관해 자세히 알아보세요.</translation>
 <translation id="6911468394164995108">다른 네트워크에 연결</translation>
+<translation id="6972754398087986839">시작하기</translation>
 <translation id="6981982820502123353">접근성</translation>
 <translation id="698231206551913481">이 사용자를 제거하면 해당 사용자와 연결되어 있는 모든 파일 및 로컬 데이터가 영구적으로 삭제됩니다.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" />에 다시 사용해 주세요.</translation>
diff --git a/ash/strings/ash_strings_lt.xtb b/ash/strings/ash_strings_lt.xtb
index 6c0816b9..e6d547b 100644
--- a/ash/strings/ash_strings_lt.xtb
+++ b/ash/strings/ash_strings_lt.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Suaktyvinti „<ph name="NETWORKSERVICE" />“</translation>
 <translation id="6910714959251846841">Norint pritaikyti šį naujinį, reikia naudoti funkciją „Powerwash“ jūsų įrenginyje. Sužinokite daugiau apie naujausią „<ph name="SYSTEM_APP_NAME" />“ naujinį.</translation>
 <translation id="6911468394164995108">Prisijungti prie kito...</translation>
+<translation id="6972754398087986839">Darbo pradžia</translation>
 <translation id="6981982820502123353">Pritaikymas neįgaliesiems</translation>
 <translation id="698231206551913481">Visi failai ir su šiuo naudotoju susiję duomenys bus ištrinti visam laikui, kai šis naudotojas bus pašalintas.</translation>
 <translation id="7015766095477679451">Grįžkite <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_lv.xtb b/ash/strings/ash_strings_lv.xtb
index 073c631..70d6d6eb 100644
--- a/ash/strings/ash_strings_lv.xtb
+++ b/ash/strings/ash_strings_lv.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktivizēt <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Lai atjauninātu sistēmu, ierīcē jāizmanto funkcija Powerwash. Uzziniet vairāk par pēdējo <ph name="SYSTEM_APP_NAME" /> atjauninājumu.</translation>
 <translation id="6911468394164995108">Pievienoties citam...</translation>
+<translation id="6972754398087986839">Sākt darbu</translation>
 <translation id="6981982820502123353">Pieejamība</translation>
 <translation id="698231206551913481">Visi faili un lokālie dati, kas ir saistīti ar šo lietotāju, tiks neatgriezeniski dzēsti, tiklīdz šis lietotājs tiks noņemts.</translation>
 <translation id="7015766095477679451">Atgriezieties plkst. <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_ml.xtb b/ash/strings/ash_strings_ml.xtb
index 177b1ef4..71c34dd 100644
--- a/ash/strings/ash_strings_ml.xtb
+++ b/ash/strings/ash_strings_ml.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> സജീവമാക്കുക</translation>
 <translation id="6910714959251846841">ഈ അപ്ഡേറ്റിനായി നിങ്ങളുടെ ഉപകരണം powerwash ചെയ്യേണ്ടതുണ്ട്. ഏറ്റവും പുതിയ <ph name="SYSTEM_APP_NAME" /> അപ്‌ഡേറ്റിനെ കുറിച്ച് കൂടുതലറിയുക.</translation>
 <translation id="6911468394164995108">മറ്റുള്ളവ ചേർക്കുക...</translation>
+<translation id="6972754398087986839">ആരംഭിക്കാം</translation>
 <translation id="6981982820502123353">ഉപയോഗസഹായി</translation>
 <translation id="698231206551913481">ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുമ്പോൾ അതോടൊപ്പം അയാളുമായി ബന്ധപ്പെട്ട എല്ലാ ഫയലുകളും പ്രാദേശിക വിവരങ്ങളും ശാശ്വതമായി ഇല്ലാതാക്കപ്പെടും.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" />-ന് തിരികെ വരിക.</translation>
diff --git a/ash/strings/ash_strings_mr.xtb b/ash/strings/ash_strings_mr.xtb
index 680d4b9..f50d092 100644
--- a/ash/strings/ash_strings_mr.xtb
+++ b/ash/strings/ash_strings_mr.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">सक्रिय करा<ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">या अपडेटसाठी तुमचे डिव्हाइस Powerwash करणे आवश्यक आहे. <ph name="SYSTEM_APP_NAME" /> च्या नवीनतम अपडेटबाबत अधिक जाणून घ्या.</translation>
 <translation id="6911468394164995108">दुसरीकडे सामील व्हा...</translation>
+<translation id="6972754398087986839">प्रारंभ करा</translation>
 <translation id="6981982820502123353">प्रवेशयोग्यता</translation>
 <translation id="698231206551913481">एकदा हा वापरकर्ता काढल्यानंतर या वापरकर्त्याशी संबद्ध सर्व फायली आणि स्थानिक डेटा कायमचा हटवला जाईल.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> वाजता परत या.</translation>
diff --git a/ash/strings/ash_strings_ms.xtb b/ash/strings/ash_strings_ms.xtb
index 188f457..d417d46 100644
--- a/ash/strings/ash_strings_ms.xtb
+++ b/ash/strings/ash_strings_ms.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Aktifkan <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Kemas kini ini memerlukan powerwash dijalankan pada peranti anda. Ketahui lebih lanjut tentang kemas kini <ph name="SYSTEM_APP_NAME" /> yang terbaharu.</translation>
 <translation id="6911468394164995108">Sertai yang lain...</translation>
+<translation id="6972754398087986839">Bermula</translation>
 <translation id="6981982820502123353">Kebolehcapaian</translation>
 <translation id="698231206551913481">Semua fail dan data yang berkaitan dengan pengguna ini akan dipadamkan secara kekal selepas pengguna ini dialih keluar.</translation>
 <translation id="7015766095477679451">Datang semula pada <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_nl.xtb b/ash/strings/ash_strings_nl.xtb
index 6e77c201..ac444c4 100644
--- a/ash/strings/ash_strings_nl.xtb
+++ b/ash/strings/ash_strings_nl.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> activeren</translation>
 <translation id="6910714959251846841">Deze update vereist een powerwash van je apparaat. Meer informatie over de laatste update van <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Verbinding met ander netwerk maken...</translation>
+<translation id="6972754398087986839">Aan de slag</translation>
 <translation id="6981982820502123353">Toegankelijkheid</translation>
 <translation id="698231206551913481">Alle bestanden en lokale gegevens die zijn gekoppeld aan deze gebruiker, worden definitief verwijderd zodra deze gebruiker is verwijderd.</translation>
 <translation id="7015766095477679451">Kom terug om <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_no.xtb b/ash/strings/ash_strings_no.xtb
index 1257d6258..37f1bfe 100644
--- a/ash/strings/ash_strings_no.xtb
+++ b/ash/strings/ash_strings_no.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktiver <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Denne oppdateringen krever en powerwash av enheten din. Finn ut mer om den nyeste <ph name="SYSTEM_APP_NAME" />-oppdateringen.</translation>
 <translation id="6911468394164995108">Koble til annet</translation>
+<translation id="6972754398087986839">Kom i gang</translation>
 <translation id="6981982820502123353">Tilgjengelighet</translation>
 <translation id="698231206551913481">Alle filer og lokale data som er tilknyttet denne brukeren, slettes permanent når brukeren fjernes.</translation>
 <translation id="7015766095477679451">Kom tilbake <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_pl.xtb b/ash/strings/ash_strings_pl.xtb
index 1562df96..9bab1773 100644
--- a/ash/strings/ash_strings_pl.xtb
+++ b/ash/strings/ash_strings_pl.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Aktywuj sieć <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Ta aktualizacja wymaga usunięcia wszystkich danych z urządzenia za pomocą funkcji Powerwash. Dowiedz się więcej o najnowszej aktualizacji <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Połącz z inną...</translation>
+<translation id="6972754398087986839">Rozpocznij</translation>
 <translation id="6981982820502123353">Ułatwienia dostępu</translation>
 <translation id="698231206551913481">Usunięcie tego użytkownika spowoduje trwałe usunięcie wszystkich związanych z nim plików i danych lokalnych.</translation>
 <translation id="7015766095477679451">Możesz wrócić o <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_pt-BR.xtb b/ash/strings/ash_strings_pt-BR.xtb
index 5f6691a1..2eb4e96 100644
--- a/ash/strings/ash_strings_pt-BR.xtb
+++ b/ash/strings/ash_strings_pt-BR.xtb
@@ -332,6 +332,7 @@
 <translation id="6857811139397017780">Ativar <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Esta atualização requer o powerwash do seu dispositivo. Saiba mais sobre a última atualização do <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Conectar-se a outra...</translation>
+<translation id="6972754398087986839">Primeiros passos</translation>
 <translation id="6981982820502123353">Acessibilidade</translation>
 <translation id="698231206551913481">Todos os arquivos e dados locais associados a este usuário serão excluídos permanentemente quando o usuário for removido.</translation>
 <translation id="7015766095477679451">Volte às <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_pt-PT.xtb b/ash/strings/ash_strings_pt-PT.xtb
index f6758a6..35cf555 100644
--- a/ash/strings/ash_strings_pt-PT.xtb
+++ b/ash/strings/ash_strings_pt-PT.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Ativar <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Para efetuar esta atualização, é necessário efetuar o Powerwash do dispositivo. Saiba mais sobre a mais recente atualização do <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Ligar-se a outra...</translation>
+<translation id="6972754398087986839">Começar</translation>
 <translation id="6981982820502123353">Acessibilidade</translation>
 <translation id="698231206551913481">Todos os ficheiros e dados locais associados a este utilizador são permanentemente eliminados assim que este utilizador é removido.</translation>
 <translation id="7015766095477679451">Volte à(s) <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_ro.xtb b/ash/strings/ash_strings_ro.xtb
index a4b995d..a1cb93a 100644
--- a/ash/strings/ash_strings_ro.xtb
+++ b/ash/strings/ash_strings_ro.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Activează <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Această actualizare necesită rularea funcției Powerwash a dispozitivului. Află mai multe despre cea mai recentă actualizare <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Conectați-vă la altă rețea...</translation>
+<translation id="6972754398087986839">Începe</translation>
 <translation id="6981982820502123353">Accesibilitate</translation>
 <translation id="698231206551913481">Toate fișierele și datele locale asociate acestui utilizator vor fi șterse definitiv după eliminarea utilizatorului.</translation>
 <translation id="7015766095477679451">Revino la <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_ru.xtb b/ash/strings/ash_strings_ru.xtb
index 30b68d6..770c3e4 100644
--- a/ash/strings/ash_strings_ru.xtb
+++ b/ash/strings/ash_strings_ru.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Активировать <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Чтобы установить это обновление, необходимо сбросить настройки устройства до заводских. Подробнее о последнем обновлении <ph name="SYSTEM_APP_NAME" />…</translation>
 <translation id="6911468394164995108">Подключиться к другой сети...</translation>
+<translation id="6972754398087986839">Начать</translation>
 <translation id="6981982820502123353">Специальные возможности</translation>
 <translation id="698231206551913481">После удаления пользователя все связанные с ним файлы и локальные данные также будут удалены.</translation>
 <translation id="7015766095477679451">Увидимся снова в <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_sk.xtb b/ash/strings/ash_strings_sk.xtb
index 8eb5946..a30db36 100644
--- a/ash/strings/ash_strings_sk.xtb
+++ b/ash/strings/ash_strings_sk.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktivovať zariadenie <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Táto aktualizácia vyžaduje vykonať v zariadení obnovenie Powerwash. Prečítajte si ďalšie informácie o najnovšej aktualizácii aplikácie <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Pripojiť k ďalšej...</translation>
+<translation id="6972754398087986839">Začať</translation>
 <translation id="6981982820502123353">Dostupnosť</translation>
 <translation id="698231206551913481">Všetky súbory a miestne údaje priradené k tomuto používateľovi budú po jeho odstránení natrvalo vymazané.</translation>
 <translation id="7015766095477679451">Vráťte sa späť o <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_sl.xtb b/ash/strings/ash_strings_sl.xtb
index c7d147b..8da3536f 100644
--- a/ash/strings/ash_strings_sl.xtb
+++ b/ash/strings/ash_strings_sl.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktiviraj <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Pred namestitvijo te posodobitve morate uporabiti funkcijo Powerwash. Preberite več o najnovejši posodobitvi za <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Pridružitev drugemu omrežju ...</translation>
+<translation id="6972754398087986839">Začnite</translation>
 <translation id="6981982820502123353">Dostopnost</translation>
 <translation id="698231206551913481">Vse datoteke in lokalni podatki, povezani s tem uporabnikom, bodo trajno izbrisani, ko odstranite uporabnika.</translation>
 <translation id="7015766095477679451">Vrnite se ob <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_sr.xtb b/ash/strings/ash_strings_sr.xtb
index 9b03317f..9abbd5c 100644
--- a/ash/strings/ash_strings_sr.xtb
+++ b/ash/strings/ash_strings_sr.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Активирај <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Ово ажурирање захтева да обавите powerwash на уређају. Сазнајте више о најновијем ажурирању за: <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Придружи ме другој...</translation>
+<translation id="6972754398087986839">Започнимо</translation>
 <translation id="6981982820502123353">Приступачност</translation>
 <translation id="698231206551913481">Све датотеке и локални подаци повезани са овим корисником ће бити трајно избрисани када уклоните овог корисника.</translation>
 <translation id="7015766095477679451">Вратите се у <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_sv.xtb b/ash/strings/ash_strings_sv.xtb
index e9bfe9a..7c66b74 100644
--- a/ash/strings/ash_strings_sv.xtb
+++ b/ash/strings/ash_strings_sv.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Aktivera <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Den här uppdateringen kräver att en Powerwash görs av enheten. Läs mer om den senaste uppdateringen av <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Anslut till andra ...</translation>
+<translation id="6972754398087986839">Komma igång</translation>
 <translation id="6981982820502123353">Tillgänglighet</translation>
 <translation id="698231206551913481">Alla filer inklusive lokal data som tillhör den här användaren tas bort permanent när användaren tas bort.</translation>
 <translation id="7015766095477679451">Prova igen klockan <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_sw.xtb b/ash/strings/ash_strings_sw.xtb
index cded5c0..d9a709a4 100644
--- a/ash/strings/ash_strings_sw.xtb
+++ b/ash/strings/ash_strings_sw.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Amilisha <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Sasisho hili linahitaji powerwash kwenye kifaa chako. Pata maelezo zaidi kuhusu sasisho jipya la <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Jiunge na mwingine...</translation>
+<translation id="6972754398087986839">Anza</translation>
 <translation id="6981982820502123353">Upatikanaji</translation>
 <translation id="698231206551913481">Faili na data zote zilizo kwenye kifaa zinazohusishwa na mtumiaji zitafutwa kabisa pindi tu mtumiaji huyu atakapoondolewa.</translation>
 <translation id="7015766095477679451">Rejea saa <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_ta.xtb b/ash/strings/ash_strings_ta.xtb
index 54a4f8c..5704e182b 100644
--- a/ash/strings/ash_strings_ta.xtb
+++ b/ash/strings/ash_strings_ta.xtb
@@ -204,7 +204,7 @@
 <translation id="4508225577814909926"><ph name="NAME" />: இணைக்கிறது...</translation>
 <translation id="4513946894732546136">கருத்து</translation>
 <translation id="4527045527269911712">புளூடூத் சாதனம் "<ph name="DEVICE_NAME" />", இணைப்பதற்கான அனுமதியை விரும்புகிறது.</translation>
-<translation id="453661520163887813">முழு சார்ஜாக <ph name="TIME" /> ஆகும்</translation>
+<translation id="453661520163887813"><ph name="TIME" /> ஆகும் 100% சார்ஜாக</translation>
 <translation id="4544944664594876241">திரையைப் பூட்டுவதற்கான குறுக்குவழி மாற்றப்பட்டது.  <ph name="OLD_SHORTCUT" /> க்குப் பதிலாக <ph name="NEW_SHORTCUT" /> ஐப் பயன்படுத்தவும்.</translation>
 <translation id="4564869809620998694">எழுத்துரு சேவை</translation>
 <translation id="4570957409596482333">பேசும் திரைக்கான பொத்தான்</translation>
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" /> ஐ செயல்படுத்து</translation>
 <translation id="6910714959251846841">இந்தப் புதுப்பிப்பைப் பெற, உங்கள் சாதனத்தைப் பவர்வாஷ் செய்ய வேண்டும். சமீபத்திய <ph name="SYSTEM_APP_NAME" /> புதுப்பிப்பைப் பற்றி மேலும் அறிக.</translation>
 <translation id="6911468394164995108">மற்றொன்றில் சேர்...</translation>
+<translation id="6972754398087986839">தொடங்குக</translation>
 <translation id="6981982820502123353">அணுகல் தன்மை</translation>
 <translation id="698231206551913481">இந்தப் பயனர் அகற்றப்பட்டதும், பயனருடன் தொடர்புடைய எல்லா கோப்புகளும் அகத் தரவும் நிரந்தரமாக நீக்கப்படும்.</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" />க்கு மீண்டும் சாதனத்தைப் பயன்படுத்தலாம்.</translation>
diff --git a/ash/strings/ash_strings_te.xtb b/ash/strings/ash_strings_te.xtb
index 3f2a58e..6bc7414 100644
--- a/ash/strings/ash_strings_te.xtb
+++ b/ash/strings/ash_strings_te.xtb
@@ -7,6 +7,7 @@
 <translation id="1037492556044956303"><ph name="DEVICE_NAME" /> జోడించబడింది</translation>
 <translation id="1056775291175587022">నెట్‌వర్క్‌లు లేవు</translation>
 <translation id="1059194134494239015"><ph name="DISPLAY_NAME" />: <ph name="RESOLUTION" /></translation>
+<translation id="1104084341931202936">యాక్సెస్‌బిలిటి సెట్టింగ్‌లను చూపుతుంది</translation>
 <translation id="1104621072296271835">మీ పరికరాలు కలిసికట్టుగా మరింత బాగా పనిచేస్తాయి</translation>
 <translation id="112308213915226829">అరను స్వయంచాలకంగా దాచు</translation>
 <translation id="1153356358378277386">జత చేసిన పరికరాలు</translation>
@@ -20,17 +21,20 @@
 <translation id="1279938420744323401"><ph name="DISPLAY_NAME" /> (<ph name="ANNOTATION" />)</translation>
 <translation id="1290331692326790741">సిగ్నల్ బలహీనంగా ఉంది</translation>
 <translation id="1293264513303784526">USB-C పరికరం (ఎడమ పోర్ట్)</translation>
+<translation id="1302880136325416935">బ్లూటూత్ సెట్టింగ్‌లను చూపుతుంది. <ph name="STATE_TEXT" /></translation>
 <translation id="1346748346194534595">కుడి</translation>
 <translation id="1351937230027495976">మెనూను కుదించు</translation>
 <translation id="1383876407941801731">శోధించు</translation>
 <translation id="1467432559032391204">ఎడమ</translation>
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">లాంచర్</translation>
+<translation id="1520303207432623762">{NUM_APPS,plural, =1{ నోటిఫికేషన్ సెట్టింగ్‌లను చూపుతుంది. యాప్ కోసం నోటిఫికేషన్‌లు ఆఫ్ చేయబడి ఉన్నాయి}other{ నోటిఫికేషన్ సెట్టింగ్‌లను చూపుతుంది. # యాప్‌ల కోసం నోటిఫికేషన్‌లు ఆఫ్ చేయబడి ఉన్నాయి}}</translation>
 <translation id="1525508553941733066">తీసివేయి</translation>
 <translation id="1537254971476575106">పూర్తి స్క్రీన్‌ మాగ్నిఫైయర్</translation>
 <translation id="15373452373711364">పెద్ద మౌస్ కర్సర్</translation>
 <translation id="1550523713251050646">మరిన్ని ఎంపికల కోసం క్లిక్ చేయండి</translation>
 <translation id="1567387640189251553">మీరు మీ పాస్‌వర్డ్‌ని చివరిసారిగా నమోదు చేసిన తర్వాత ఒక విభిన్నమైన కీబోర్డ్ కనెక్ట్ చేయబడింది. మీ కీస్ట్రోక్‌లను దొంగిలించడం కోసం ఇది ప్రయత్నిస్తుండవచ్చు.</translation>
+<translation id="1570871743947603115">బ్లూటూత్‌ను టోగుల్ చేయండి. <ph name="STATE_TEXT" /></translation>
 <translation id="1608626060424371292">ఈ వినియోగదారుని తీసివేయండి</translation>
 <translation id="1621499497873603021">బ్యాటరీ ఖాళీ కావడానికి మిగిలి ఉన్న సమయం, <ph name="TIME_LEFT" /></translation>
 <translation id="1658406695958299976">క్షమించండి, మీ పాస్‌వర్డ్ ఇప్పటికీ ధృవీకరించబడలేదు. గమనిక: మీరు మీ పాస్‌వర్డ్‌ను ఇటీవల మార్చి ఉంటే, మీరు సైన్ అవుట్ చేసిన తర్వాత మీ కొత్త పాస్‌వర్డ్ వర్తించబడుతుంది, దయచేసి పాత పాస్‌వర్డ్‌ను ఇక్కడ ఉపయోగించండి.</translation>
@@ -40,6 +44,7 @@
 <translation id="1743570585616704562">గుర్తించలేదు</translation>
 <translation id="1746730358044914197">ఇన్‌పుట్ పద్ధతులు మీ నిర్వాహకుల ద్వారా కాన్ఫిగర్ చేయబడ్డాయి.</translation>
 <translation id="1747827819627189109">స్క్రీన్‌పై కనిపించే కీబోర్డ్ ప్రారంభించబడింది</translation>
+<translation id="1761222317188459878">నెట్‌వర్క్ కనెక్షన్‌ను టోగుల్ చేయండి. <ph name="STATE_TEXT" /></translation>
 <translation id="1823873187264960516">ఈథర్‌నెట్: <ph name="ADDRESS" /></translation>
 <translation id="1836215606488044471">సహాయకం (లోడ్ అవుతోంది...)</translation>
 <translation id="1841545962859478868">పరికర నిర్వాహకుడు క్రింది వాటిని పర్యవేక్షించవచ్చు:</translation>
@@ -63,6 +68,7 @@
 <translation id="2049639323467105390">ఈ పరికరం <ph name="DOMAIN" /> ద్వారా నిర్వహించబడుతుంది.</translation>
 <translation id="2050339315714019657">నిలువు</translation>
 <translation id="2067602449040652523">కీబోర్డ్ ప్రకాశం</translation>
+<translation id="2075212959500165896">చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
 <translation id="2081529251031312395">ఇప్పటికీ $1 తర్వాత సైన్ ఇన్ చేయవచ్చు.</translation>
 <translation id="2127372758936585790">తక్కువ-పవర్ గల ఛార్జర్</translation>
 <translation id="2135456203358955318">డాక్ చేయబడిన మాగ్నిఫైయర్</translation>
@@ -76,12 +82,15 @@
 <translation id="2303600792989757991">విండో స్థూలదృష్టిని టోగుల్ చేయి</translation>
 <translation id="2338501278241028356">సమీప పరికరాలను కనుగొనడానికి బ్లూటూత్‌ను ఆన్ చేయండి</translation>
 <translation id="2339073806695260576">గమనికను వ్రాయడానికి, స్క్రీన్‌షాట్‌ను తీయడానికి, లేజర్ పాయింటర్ లేదా భూతద్దాన్ని ఉపయోగించడానికి అరలో స్టైలస్ బటన్‌ను నొక్కండి.</translation>
+<translation id="2341729377289034582">నిలువు ప్రదర్శనకు లాక్ చేయబడింది</translation>
 <translation id="2352467521400612932">స్టైలస్ సెట్టింగ్‌లు</translation>
 <translation id="2354174487190027830"><ph name="NAME" />ని సక్రియం చేస్తోంది</translation>
 <translation id="2359808026110333948">కొనసాగు</translation>
 <translation id="2365393535144473978">మొబైల్ డేటాను ప్రారంభించడం బ్లూటూత్‌ని ప్రారంభిస్తుంది.</translation>
 <translation id="2391579633712104609">180°</translation>
+<translation id="239188844683466770">అంతరాయం కలిగించవద్దు ఎంపికను టోగుల్ చేయండి</translation>
 <translation id="2412593942846481727">అప్‌డేట్ అందుబాటులో ఉంది</translation>
+<translation id="2416346634399901812"><ph name="NETWORK_NAME" />కి కనెక్ట్ చేయబడింది</translation>
 <translation id="2429753432712299108">బ్లూటూత్ పరికరం "<ph name="DEVICE_NAME" />" జత కావడానికి అనుమతి కోరుతోంది. ఆమోదించడానికి ముందు, దయచేసి ఆ పరికరంలో ఈ పాస్‌కీ చూపబడుతోందని నిర్ధారించుకోండి: <ph name="PASSKEY" /></translation>
 <translation id="2482878487686419369">ప్రకటనలు</translation>
 <translation id="2484513351006226581">కీబోర్డ్ లేఅవుట్‌ను మార్చడానికి <ph name="KEYBOARD_SHORTCUT" />ని నొక్కండి.</translation>
@@ -114,6 +123,7 @@
 <translation id="2946119680249604491">కనెక్షన్‌ని జోడించండి</translation>
 <translation id="2961963223658824723">ఏదో తప్పు జరిగింది. కొన్ని క్షణాల తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
 <translation id="2963773877003373896">mod3</translation>
+<translation id="2995447421581609334">ప్రదర్శన పరికరాలను చూపుతుంది.</translation>
 <translation id="2996462380875591307">డాక్ చేయబడిన మాగ్నిఫైయర్ ప్రారంభించబడింది. దాన్ని టోగుల్ ఆఫ్ చేయడానికి మళ్లీ Ctrl+Search+Dని నొక్కండి.</translation>
 <translation id="2999742336789313416"><ph name="DISPLAY_NAME" /> అనేది <ph name="DOMAIN" /> ద్వారా నిర్వహించబడుతున్న పబ్లిక్ సెషన్</translation>
 <translation id="3000461861112256445">మోనో ఆడియో</translation>
@@ -128,6 +138,7 @@
 <translation id="315116470104423982">మొబైల్ డేటా</translation>
 <translation id="3151786313568798007">దృగ్విన్యాసం</translation>
 <translation id="3153444934357957346">మీరు బహుళ సైన్-ఇన్‌లో గరిష్టంగా <ph name="MULTI_PROFILE_USER_LIMIT" /> ఖాతాలను మాత్రమే కలిగి ఉండవచ్చు.</translation>
+<translation id="3202010236269062730">{NUM_DEVICES,plural, =1{పరికరానికి కనెక్ట్ చేయబడింది}other{# పరికరాలకు కనెక్ట్ చేయబడింది}}</translation>
 <translation id="3236488194889173876">మొబైల్ నెట్‌వర్క్ ఏదీ అందుబాటులో లేదు</translation>
 <translation id="3238765806255363838"><ph name="USERNAME" /> <ph name="MAIL" /></translation>
 <translation id="3294437725009624529">అతిథి</translation>
@@ -160,6 +171,7 @@
 <translation id="3784455785234192852">లాక్ చేయి</translation>
 <translation id="3798670284305777884">స్పీకర్ (అంతర్గతం)</translation>
 <translation id="380165613292957338">హాయ్, నేను ఎలా సహాయపడగలను?</translation>
+<translation id="383629559565718788">కీబోర్డ్ సెట్టింగ్‌లను చూపుతుంది</translation>
 <translation id="3846575436967432996">నెట్‌వర్క్ సమాచారం అందుబాటులో లేదు</translation>
 <translation id="385051799172605136">వెనుకకు</translation>
 <translation id="3891340733213178823">సైన్ అవుట్ చేయడానికి Ctrl+Shift+Qని రెండుసార్లు నొక్కండి.</translation>
@@ -175,8 +187,10 @@
 <translation id="4072264167173457037">సిగ్నల్ ఓ మోస్తరుగా ఉంది</translation>
 <translation id="4200057768455216496">డాక్ చేసిన మాగ్నిఫైయర్‌కు సంబంధించిన షార్ట్‌కట్‌ను మీరు నొక్కారు. మీరు దీనిని ఆన్ చేయాలనుకుంటున్నారా?</translation>
 <translation id="4217571870635786043">డిక్టేషన్</translation>
+<translation id="4261870227682513959">నోటిఫికేషన్ సెట్టింగ్‌లను చూపుతుంది. నోటిఫికేషన్‌లు ఆఫ్ చేయబడి ఉన్నాయి</translation>
 <translation id="4274921305979314545">మీ Chromebookను మీ ఫోన్‌కు కనెక్ట్ చేయండి</translation>
 <translation id="4279490309300973883">ప్రతిబింబిస్తుంది</translation>
+<translation id="4292681942966152062"><ph name="NETWORK_NAME" /> యాక్టివేట్ చేయబడుతోంది</translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4331809312908958774">Chrome OS</translation>
 <translation id="4338109981321384717">భూతద్దం</translation>
@@ -226,7 +240,7 @@
 <translation id="544691375626129091">అందుబాటులో ఉన్న వినియోగదారులందరూ ఇప్పటికే ఈ సెషన్‌కు జోడించబడ్డారు.</translation>
 <translation id="5457599981699367932">అతిథి వలె బ్రౌజ్ చెయ్యండి</translation>
 <translation id="54609108002486618">నిర్వహించబడింది</translation>
-<translation id="5496819745535887422">మీ నిర్వాహకుడు మీ పరికరాన్ని మళ్లీ ప్రారంభిస్తున్నారు. పరికరం మళ్లీ ప్రారంభించినప్పుడు మొత్తం డేటా తొలగించబడుతుంది.</translation>
+<translation id="5496819745535887422">మీ నిర్వాహకుడు మీ పరికరాన్ని ఉపసంహరిస్తున్నారు. పరికరం మళ్లీ ప్రారంభించినప్పుడు మొత్తం డేటా తొలగించబడుతుంది.</translation>
 <translation id="553675580533261935">సెషన్ నుండి నిష్క్రమిస్తోంది</translation>
 <translation id="5537725057119320332">Cast</translation>
 <translation id="5548285847212963613">"<ph name="EXTENSION_NAME" />" పొడిగింపు ఈ నెట్‌వర్క్‌కు కనెక్ట్ చేయడంలో సహాయపడగలదు.</translation>
@@ -240,6 +254,7 @@
 <translation id="5673434351075758678">మీ సెట్టింగులను సమకాలీకరించిన తర్వాత "<ph name="FROM_LOCALE" />" నుండి "<ph name="TO_LOCALE" />"కి.</translation>
 <translation id="574392208103952083">మధ్యస్థం</translation>
 <translation id="5744083938413354016">నొక్కి లాగండి</translation>
+<translation id="5750765938512549687">బ్లూటూత్ ఆఫ్ చేయబడింది</translation>
 <translation id="5777841717266010279">స్క్రీన్ భాగస్వామ్యాన్ని ఆపివేయాలా?</translation>
 <translation id="57838592816432529">మ్యూట్ చేయి</translation>
 <translation id="5805697420284793859">విండో మేనేజర్</translation>
@@ -273,12 +288,14 @@
 <translation id="615957422585914272">స్క్రీన్‌పై కీబోర్డ్‌ను చూపు</translation>
 <translation id="6164005077879661055">ఈ పర్యవేక్షించబడే వినియోగదారు తీసివేయబడినప్పుడు పర్యవేక్షించబడే వినియోగదారుతో అనుబంధించబడిన అన్ని ఫైల్‌లు మరియు స్థానిక డేటా శాశ్వతంగా తొలగించబడతాయి. ఈ పర్యవేక్షించబడే వినియోగదారు సందర్శించిన వెబ్‌సైట్‌లు మరియు వీరి సెట్టింగ్‌లు ఇప్పటికీ <ph name="MANAGEMENT_URL" />లో నిర్వాహకునికి కనిపించవచ్చు.</translation>
 <translation id="6165508094623778733">మరింత తెలుసుకోండి</translation>
+<translation id="6254629735336163724">సమాంతర ప్రదర్శనకు లాక్ చేయబడింది</translation>
 <translation id="6259254695169772643">ఎంచుకోవడానికి మీ స్టైలస్‌ను ఉపయోగించండి</translation>
 <translation id="6267036997247669271"><ph name="NAME" />: సక్రియం చేస్తోంది...</translation>
 <translation id="6284232397434400372">రిజల్యూషన్ మార్చబడింది</translation>
 <translation id="6297287540776456956">ప్రాంతాన్ని ఎంచుకోవడానికి స్టైలస్‌ను ఉపయోగించండి</translation>
 <translation id="6310121235600822547"><ph name="DISPLAY_NAME" /> <ph name="ROTATION" />కి తిప్పబడింది</translation>
 <translation id="632744581670418035">కీబోర్డ్ అతివ్యాప్తి</translation>
+<translation id="6376931439017688372">బ్లూటూత్ ఆన్ చేయబడింది</translation>
 <translation id="639644700271529076">CAPS LOCK ఆపివేయబడింది</translation>
 <translation id="6406704438230478924">altgr</translation>
 <translation id="643147933154517414">పూర్తయింది</translation>
@@ -314,6 +331,7 @@
 <translation id="6857811139397017780"><ph name="NETWORKSERVICE" />ని సక్రియం చెయ్యి</translation>
 <translation id="6910714959251846841">ఈ అప్‌డేట్ కోసం మీ పరికరాన్ని పవర్‌వాష్ చేయాలి. తాజా <ph name="SYSTEM_APP_NAME" /> అప్‌డేట్ గురించి మరింత తెలుసుకోండి.</translation>
 <translation id="6911468394164995108">మరొక దానిలో చేరండి...</translation>
+<translation id="6972754398087986839">ప్రారంభించండి</translation>
 <translation id="6981982820502123353">ప్రాప్యత</translation>
 <translation id="698231206551913481">ఈ వినియోగదారును తీసివేసిన తర్వాత ఈ వినియోగదారుతో అనుబంధించిన అన్ని ఫైల్‌లు మరియు స్థానిక డేటా శాశ్వతంగా తొలగించబడతాయి.</translation>
 <translation id="7015766095477679451">తిరిగి <ph name="COME_BACK_TIME" />కి రండి.</translation>
@@ -322,6 +340,7 @@
 <translation id="7066646422045619941">ఈ నెట్‌వర్క్‌ను మీ నిర్వాహకులు నిలిపివేసారు.</translation>
 <translation id="7067196344162293536">స్వయంచాలకంగా తిప్పు</translation>
 <translation id="7076293881109082629">సైన్ ఇన్ చేస్తోంది</translation>
+<translation id="7092922358121866860">రాత్రి కాంతి సెట్టింగ్‌లను చూపుతుంది</translation>
 <translation id="7098389117866926363">USB-C పరికరం (వెనుక భాగంలో ఎడమ పోర్ట్)</translation>
 <translation id="7131634465328662194">మీరు ఆటోమేటిక్‌గా సైన్ అవుట్ చేయబడతారు.</translation>
 <translation id="7143207342074048698">కనెక్ట్ అవుతోంది</translation>
@@ -357,6 +376,7 @@
 <translation id="7798302898096527229">రద్దు చేయడానికి Search లేదా Shiftని నొక్కండి.</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> మరియు <ph name="MINUTE" /></translation>
 <translation id="7829386189513694949">సిగ్నల్ దృఢంగా ఉంది</translation>
+<translation id="7842211907556571265"><ph name="NETWORK_NAME" />కి కనెక్ట్ చేయబడుతోంది</translation>
 <translation id="7842569679327885685">హెచ్చరిక: ప్రయోగాత్మక ఫీచర్</translation>
 <translation id="7846634333498149051">కీబోర్డ్</translation>
 <translation id="790040513076446191">గోప్యత సంబంధ సెట్టింగ్‌లను మ్యానిపులేట్ చేయండి</translation>
@@ -397,18 +417,24 @@
 <translation id="8484916590211895857"><ph name="NAME" />: మళ్లీ కనెక్ట్ చేస్తోంది...</translation>
 <translation id="8513108775083588393">ఆటో-రొటేట్‌లో ఉంది</translation>
 <translation id="8517041960877371778">మీ <ph name="DEVICE_TYPE" /> ఆన్‌లో ఉన్నప్పుడు ఛార్జ్ కాకపోవచ్చు.</translation>
+<translation id="8627191004499078455"><ph name="DEVICE_NAME" />కి కనెక్ట్ చేయబడింది</translation>
 <translation id="8639760480004882931"><ph name="PERCENTAGE" /> మిగిలి ఉంది</translation>
 <translation id="8649101189709089199">వినడానికి ఎంచుకోండి</translation>
 <translation id="8652175077544655965">సెట్టింగ్‌లను మూసివేయండి</translation>
+<translation id="8653151467777939995">నోటిఫికేషన్ సెట్టింగ్‌లను చూపుతుంది. నోటిఫికేషన్‌లు ఆన్ చేయబడి ఉన్నాయి</translation>
+<translation id="8664753092453405566">నెట్‌వర్క్ జాబితాను చూపుతుంది. <ph name="STATE_TEXT" /></translation>
 <translation id="8673028979667498656">270°</translation>
 <translation id="8676770494376880701">తక్కువ-పవర్ గల ఛార్జర్ కనెక్ట్ చేయబడింది</translation>
 <translation id="8683506306463609433">పనితీరు స్థితిగతి కనుగొనడం యాక్టివ్‌గా ఉంది</translation>
 <translation id="8734991477317290293">మీ కీస్ట్రోక్‌లను దొంగిలించడానికి ఇది ప్రయత్నిస్తుండవచ్చు</translation>
+<translation id="8735953464173050365">కీబోర్డ్ సెట్టింగ్‌లను చూపుతుంది. <ph name="KEYBOARD_NAME" /> ఎంపిక చేయబడింది</translation>
+<translation id="875593634123171288">VPN సెట్టింగ్‌లను చూపుతుంది</translation>
 <translation id="8809737090443522491">యాప్ లేదా పత్రం యొక్క పేరుని టైప్ చేయండి</translation>
 <translation id="8814190375133053267">Wi-Fi</translation>
 <translation id="8825534185036233643">రెండింటి కంటే ఎక్కువ డిస్‌ప్లేలతో మిర్రరింగ్ చేయడానికి మద్దతు లేదు.</translation>
 <translation id="8828714802988429505">90°</translation>
 <translation id="8841375032071747811">వెనుకకు బటన్</translation>
+<translation id="8843682306134542540">భ్రమణం లాక్‌ను టోగుల్ చేయండి. <ph name="STATE_TEXT" /></translation>
 <translation id="8850991929411075241">Search+Esc</translation>
 <translation id="8870509716567206129">యాప్‌లో విభజన స్క్రీన్‌కి మద్దతు లేదు.</translation>
 <translation id="8874184842967597500">కనెక్ట్ చేయబడలేదు</translation>
@@ -419,7 +445,7 @@
 <translation id="8984179138335769204">శీఘ్ర ప్రారంభం</translation>
 <translation id="8995603266996330174"><ph name="DOMAIN" /> ద్వారా నిర్వహించబడుతోంది</translation>
 <translation id="9029474291399787231">Adobe Flash Player అప్‌డేట్ అందుబాటులో ఉంది</translation>
-<translation id="9056839673611986238">పరికరం తిరిగి ప్రారంభించబడుతుంది</translation>
+<translation id="9056839673611986238">పరికరం ఉపసంహరించబడుతుంది</translation>
 <translation id="9074739597929991885">Bluetooth</translation>
 <translation id="9079731690316798640">Wi-Fi: <ph name="ADDRESS" /></translation>
 <translation id="9080206825613744995">మైక్రోఫోన్ ఉపయోగంలో ఉంది.</translation>
diff --git a/ash/strings/ash_strings_th.xtb b/ash/strings/ash_strings_th.xtb
index 1d1d7d3..6997f3e0 100644
--- a/ash/strings/ash_strings_th.xtb
+++ b/ash/strings/ash_strings_th.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">เปิดใช้งาน <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">อัปเดตนี้จะมีการ Powerwash อุปกรณ์ ดูข้อมูลเพิ่มเติมเกี่ยวกับอัปเดตล่าสุดของ <ph name="SYSTEM_APP_NAME" /></translation>
 <translation id="6911468394164995108">เชื่อมต่อเครือข่ายอื่น...</translation>
+<translation id="6972754398087986839">เริ่มต้นใช้งาน</translation>
 <translation id="6981982820502123353">การเข้าถึง</translation>
 <translation id="698231206551913481">ระบบจะลบไฟล์ทั้งหมดและข้อมูลในเครื่องที่เชื่อมโยงกับผู้ใช้รายนี้ออกอย่างถาวรหลังจากนำผู้ใช้รายนี้ออกแล้ว</translation>
 <translation id="7015766095477679451">กลับมาเมื่อถึงเวลา <ph name="COME_BACK_TIME" /></translation>
diff --git a/ash/strings/ash_strings_tr.xtb b/ash/strings/ash_strings_tr.xtb
index e100045..a896b42 100644
--- a/ash/strings/ash_strings_tr.xtb
+++ b/ash/strings/ash_strings_tr.xtb
@@ -204,7 +204,7 @@
 <translation id="4508225577814909926"><ph name="NAME" />: Bağlanıyor...</translation>
 <translation id="4513946894732546136">Geri Bildirim</translation>
 <translation id="4527045527269911712">"<ph name="DEVICE_NAME" />" adlı Bluetooth cihaz eşleme izni istiyor.</translation>
-<translation id="453661520163887813">Dolması için gereken süre: <ph name="TIME" /></translation>
+<translation id="453661520163887813">Dolmasına <ph name="TIME" /> var</translation>
 <translation id="4544944664594876241">Ekranı kilitleme kısayolu değişti. Lütfen <ph name="OLD_SHORTCUT" /> yerine <ph name="NEW_SHORTCUT" /> kısayolunu kullanın.</translation>
 <translation id="4564869809620998694">Yazı tipi hizmeti</translation>
 <translation id="4570957409596482333">Seç ve Dinle düğmesi</translation>
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Şunu etkinleştir: <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Bu güncelleme, cihazınızda powerwash işlemi yapılmasını gerektiriyor. En yeni <ph name="SYSTEM_APP_NAME" /> güncellemesi ile ilgili daha fazla bilgi edinin.</translation>
 <translation id="6911468394164995108">Başka ağa katıl...</translation>
+<translation id="6972754398087986839">Başlarken</translation>
 <translation id="6981982820502123353">Erişilebilirlik</translation>
 <translation id="698231206551913481">Bu kullanıcıyla ilişkilendirilen tüm dosyalar ve yerel veriler, bu kullanıcı kaldırıldıktan sonra kalıcı olarak silinir.</translation>
 <translation id="7015766095477679451">Saat <ph name="COME_BACK_TIME" /> olduğunda geri gelin.</translation>
diff --git a/ash/strings/ash_strings_uk.xtb b/ash/strings/ash_strings_uk.xtb
index a0c0fc2..44850e5 100644
--- a/ash/strings/ash_strings_uk.xtb
+++ b/ash/strings/ash_strings_uk.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">Активувати <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Для цього оновлення потрібно виконати Powerwash на пристрої. Докладніше про останнє оновлення додатка <ph name="SYSTEM_APP_NAME" />.</translation>
 <translation id="6911468394164995108">Під’єднатися до іншої...</translation>
+<translation id="6972754398087986839">Почати</translation>
 <translation id="6981982820502123353">Доступність</translation>
 <translation id="698231206551913481">Якщо видалити цього користувача, усі файли та локальні дані, зв’язані з ним, буде видалено назавжди.</translation>
 <translation id="7015766095477679451">Поверніться о <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_vi.xtb b/ash/strings/ash_strings_vi.xtb
index 7399d561..d16d960 100644
--- a/ash/strings/ash_strings_vi.xtb
+++ b/ash/strings/ash_strings_vi.xtb
@@ -331,6 +331,7 @@
 <translation id="6857811139397017780">Kích hoạt <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">Bản cập nhật này yêu cầu phải powerwash (đặt lại toàn bộ) thiết bị của bạn. Hãy tìm hiểu thêm về bản cập nhật <ph name="SYSTEM_APP_NAME" /> mới nhất.</translation>
 <translation id="6911468394164995108">Tham gia mạng khác...</translation>
+<translation id="6972754398087986839">Bắt đầu</translation>
 <translation id="6981982820502123353">Truy cập</translation>
 <translation id="698231206551913481">Tất cả các tệp và dữ liệu cục bộ liên quan tới người dùng này sẽ bị xóa vĩnh viễn sau khi người dùng này bị xóa.</translation>
 <translation id="7015766095477679451">Quay lại lúc <ph name="COME_BACK_TIME" />.</translation>
diff --git a/ash/strings/ash_strings_zh-CN.xtb b/ash/strings/ash_strings_zh-CN.xtb
index 5a98646..3d768c3 100644
--- a/ash/strings/ash_strings_zh-CN.xtb
+++ b/ash/strings/ash_strings_zh-CN.xtb
@@ -7,6 +7,7 @@
 <translation id="1037492556044956303">已添加<ph name="DEVICE_NAME" /></translation>
 <translation id="1056775291175587022">找不到任何网络</translation>
 <translation id="1059194134494239015"><ph name="DISPLAY_NAME" />:<ph name="RESOLUTION" /></translation>
+<translation id="1104084341931202936">显示无障碍设置</translation>
 <translation id="1104621072296271835">协同运作可使您的各部设备更好地发挥作用</translation>
 <translation id="112308213915226829">自动隐藏任务栏</translation>
 <translation id="1153356358378277386">已配对的设备</translation>
@@ -20,17 +21,20 @@
 <translation id="1279938420744323401"><ph name="DISPLAY_NAME" />(<ph name="ANNOTATION" />)</translation>
 <translation id="1290331692326790741">信号较弱</translation>
 <translation id="1293264513303784526">USB-C 设备(左侧端口)</translation>
+<translation id="1302880136325416935">显示蓝牙设置。<ph name="STATE_TEXT" /></translation>
 <translation id="1346748346194534595">向右</translation>
 <translation id="1351937230027495976">收起菜单</translation>
 <translation id="1383876407941801731">搜索</translation>
 <translation id="1467432559032391204">向左</translation>
 <translation id="1484102317210609525"><ph name="DEVICE_NAME" /> (HDMI/DP)</translation>
 <translation id="1510238584712386396">启动器</translation>
+<translation id="1520303207432623762">{NUM_APPS,plural, =1{显示通知设置。针对 1 个应用关闭通知}other{显示通知设置。针对 # 个应用关闭通知}}</translation>
 <translation id="1525508553941733066">关闭</translation>
 <translation id="1537254971476575106">全屏放大镜</translation>
 <translation id="15373452373711364">大号鼠标光标</translation>
 <translation id="1550523713251050646">点击即可查看更多选项</translation>
 <translation id="1567387640189251553">自从您上次输入密码后,所连接的键盘已被更换。当前连接的键盘可能会试图窃取您的击键操作。</translation>
+<translation id="1570871743947603115">切换蓝牙设置。<ph name="STATE_TEXT" /></translation>
 <translation id="1608626060424371292">移除此用户</translation>
 <translation id="1621499497873603021">电池电量将在 <ph name="TIME_LEFT" />后耗尽</translation>
 <translation id="1658406695958299976">抱歉,系统仍然无法验证您的密码。注意:如果您最近更改了密码,新密码将在您退出后生效。目前请在此处输入旧密码。</translation>
@@ -40,6 +44,7 @@
 <translation id="1743570585616704562">无法识别</translation>
 <translation id="1746730358044914197">输入法是由您的管理员配置的。</translation>
 <translation id="1747827819627189109">屏幕键盘已启用</translation>
+<translation id="1761222317188459878">切换网络连接设置。<ph name="STATE_TEXT" /></translation>
 <translation id="1823873187264960516">以太网:<ph name="ADDRESS" /></translation>
 <translation id="1836215606488044471">智能助理(正在加载中…)</translation>
 <translation id="1841545962859478868">此设备的管理员可能会监控以下各项:</translation>
@@ -63,6 +68,7 @@
 <translation id="2049639323467105390">此设备由 <ph name="DOMAIN" /> 管理。</translation>
 <translation id="2050339315714019657">纵向</translation>
 <translation id="2067602449040652523">键盘亮度</translation>
+<translation id="2075212959500165896">尝试次数过多,请稍后重试。</translation>
 <translation id="2081529251031312395">日后“$1”仍能登录。</translation>
 <translation id="2127372758936585790">低功率充电器</translation>
 <translation id="2135456203358955318">停靠的放大镜</translation>
@@ -76,12 +82,15 @@
 <translation id="2303600792989757991">“切换窗口”概述</translation>
 <translation id="2338501278241028356">开启蓝牙以发现附近的设备</translation>
 <translation id="2339073806695260576">点按任务栏中的触控笔按钮即可开始记事、截取屏幕截图以及使用激光笔/放大镜。</translation>
+<translation id="2341729377289034582">已锁定为纵向</translation>
 <translation id="2352467521400612932">触控笔设置</translation>
 <translation id="2354174487190027830">正在激活“<ph name="NAME" />”</translation>
 <translation id="2359808026110333948">继续</translation>
 <translation id="2365393535144473978">如果您启用移动数据网络,蓝牙亦会随之开启。</translation>
 <translation id="2391579633712104609">180°</translation>
+<translation id="239188844683466770">切换“请勿打扰”模式</translation>
 <translation id="2412593942846481727">有可用的更新</translation>
+<translation id="2416346634399901812">已连接到<ph name="NETWORK_NAME" /></translation>
 <translation id="2429753432712299108">蓝牙设备“<ph name="DEVICE_NAME" />”需要配对许可。在接受之前,请确保该设备上显示以下配对密钥:<ph name="PASSKEY" /></translation>
 <translation id="2482878487686419369">通知</translation>
 <translation id="2484513351006226581">按 <ph name="KEYBOARD_SHORTCUT" />键可切换键盘布局。</translation>
@@ -114,6 +123,7 @@
 <translation id="2946119680249604491">添加连接</translation>
 <translation id="2961963223658824723">出了点问题。请过几秒钟后重试。</translation>
 <translation id="2963773877003373896">mod3</translation>
+<translation id="2995447421581609334">显示投射设备。</translation>
 <translation id="2996462380875591307">已启用停靠的放大镜。再按一次 Ctrl+搜索键+D 组合键即可将其停用。</translation>
 <translation id="2999742336789313416">“<ph name="DISPLAY_NAME" />”是由 <ph name="DOMAIN" /> 管理的公用自助终端</translation>
 <translation id="3000461861112256445">单声道音频</translation>
@@ -128,6 +138,7 @@
 <translation id="315116470104423982">移动数据</translation>
 <translation id="3151786313568798007">方向</translation>
 <translation id="3153444934357957346">使用多帐号登录时,一次最多只能登入 <ph name="MULTI_PROFILE_USER_LIMIT" /> 个帐号。</translation>
+<translation id="3202010236269062730">{NUM_DEVICES,plural, =1{已连接到 1 台设备}other{已连接到 # 台设备}}</translation>
 <translation id="3236488194889173876">没有可用的移动网络</translation>
 <translation id="3238765806255363838"><ph name="USERNAME" /> <ph name="MAIL" /></translation>
 <translation id="3294437725009624529">访客</translation>
@@ -159,6 +170,7 @@
 <translation id="3784455785234192852">锁定</translation>
 <translation id="3798670284305777884">扬声器(内部)</translation>
 <translation id="380165613292957338">嗨,有什么我可以帮您的吗?</translation>
+<translation id="383629559565718788">显示键盘设置</translation>
 <translation id="3846575436967432996">没有可用的网络信息</translation>
 <translation id="385051799172605136">后退</translation>
 <translation id="3891340733213178823">连按两次Ctrl+Shift+Q即可退出。</translation>
@@ -174,8 +186,10 @@
 <translation id="4072264167173457037">信号中等</translation>
 <translation id="4200057768455216496">您按下了停靠放大镜的快捷键。要开启这项功能吗?</translation>
 <translation id="4217571870635786043">语音输入</translation>
+<translation id="4261870227682513959">显示通知设置。通知已关闭</translation>
 <translation id="4274921305979314545">将您的 Chromebook 连接到手机</translation>
 <translation id="4279490309300973883">正在镜像</translation>
+<translation id="4292681942966152062">正在启用<ph name="NETWORK_NAME" /></translation>
 <translation id="4321179778687042513">ctrl</translation>
 <translation id="4331809312908958774">Chrome OS
 </translation>
@@ -240,6 +254,7 @@
 <translation id="5673434351075758678">当系统同步完您的设置后,“<ph name="FROM_LOCALE" />”即会改为“<ph name="TO_LOCALE" />”。</translation>
 <translation id="574392208103952083">中</translation>
 <translation id="5744083938413354016">点按拖动</translation>
+<translation id="5750765938512549687">蓝牙已关闭</translation>
 <translation id="5777841717266010279">要停止屏幕共享吗?</translation>
 <translation id="57838592816432529">静音</translation>
 <translation id="5805697420284793859">窗口管理器</translation>
@@ -273,12 +288,14 @@
 <translation id="615957422585914272">显示屏幕键盘</translation>
 <translation id="6164005077879661055">删除该受监管用户后,与其相关联的所有文件和本地数据都会被永久删除,但管理员仍可以在 <ph name="MANAGEMENT_URL" /> 上查看该用户的设置和访问过的网站。</translation>
 <translation id="6165508094623778733">了解详情</translation>
+<translation id="6254629735336163724">已锁定为横向</translation>
 <translation id="6259254695169772643">请使用您的触控笔进行选择</translation>
 <translation id="6267036997247669271"><ph name="NAME" />:正在激活…</translation>
 <translation id="6284232397434400372">分辨率已更改</translation>
 <translation id="6297287540776456956">使用触控笔选择一个区域</translation>
 <translation id="6310121235600822547"><ph name="DISPLAY_NAME" />已旋转为<ph name="ROTATION" /></translation>
 <translation id="632744581670418035">键盘功能标注</translation>
+<translation id="6376931439017688372">蓝牙已开启</translation>
 <translation id="639644700271529076">CAPS LOCK 已关闭</translation>
 <translation id="6406704438230478924">altgr</translation>
 <translation id="643147933154517414">大功告成</translation>
@@ -314,6 +331,7 @@
 <translation id="6857811139397017780">激活 <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">必须对您的设备执行 Powerwash 才能安装这项更新。详细了解最新的 <ph name="SYSTEM_APP_NAME" />更新。</translation>
 <translation id="6911468394164995108">连接其他网络...</translation>
+<translation id="6972754398087986839">开始使用</translation>
 <translation id="6981982820502123353">无障碍</translation>
 <translation id="698231206551913481">移除该用户后,与其关联的所有文件和本地数据都会被永久删除。</translation>
 <translation id="7015766095477679451">您需要等到<ph name="COME_BACK_TIME" /> 才能再次使用此设备。</translation>
@@ -322,6 +340,7 @@
 <translation id="7066646422045619941">您的管理员已禁用此网络。</translation>
 <translation id="7067196344162293536">自动旋转</translation>
 <translation id="7076293881109082629">正在登录</translation>
+<translation id="7092922358121866860">显示“夜间模式”设置</translation>
 <translation id="7098389117866926363">USB-C 设备(背面左侧端口)</translation>
 <translation id="7131634465328662194">您将会自动退出会话。</translation>
 <translation id="7143207342074048698">正在连接</translation>
@@ -357,6 +376,7 @@
 <translation id="7798302898096527229">按搜索键或按 Shift 键可取消。</translation>
 <translation id="7814236020522506259"><ph name="HOUR" /> <ph name="MINUTE" /></translation>
 <translation id="7829386189513694949">信号较强</translation>
+<translation id="7842211907556571265">正在连接到<ph name="NETWORK_NAME" /></translation>
 <translation id="7842569679327885685">警告:实验性功能</translation>
 <translation id="7846634333498149051">键盘</translation>
 <translation id="790040513076446191">管理隐私相关设置</translation>
@@ -397,18 +417,24 @@
 <translation id="8484916590211895857"><ph name="NAME" />:正在重新连接…</translation>
 <translation id="8513108775083588393">自动旋转屏幕</translation>
 <translation id="8517041960877371778">您的 <ph name="DEVICE_TYPE" /> 在开启时可能无法充电。</translation>
+<translation id="8627191004499078455">已连接到<ph name="DEVICE_NAME" /></translation>
 <translation id="8639760480004882931">剩余电量:<ph name="PERCENTAGE" /></translation>
 <translation id="8649101189709089199">随选朗读</translation>
 <translation id="8652175077544655965">关闭设置</translation>
+<translation id="8653151467777939995">显示通知设置。通知已开启</translation>
+<translation id="8664753092453405566">显示网络列表。<ph name="STATE_TEXT" /></translation>
 <translation id="8673028979667498656">270°</translation>
 <translation id="8676770494376880701">已连接低功率充电器</translation>
 <translation id="8683506306463609433">正在跟踪性能</translation>
 <translation id="8734991477317290293">当前连接的键盘可能会试图窃取您的击键操作</translation>
+<translation id="8735953464173050365">显示键盘设置。已选择<ph name="KEYBOARD_NAME" /></translation>
+<translation id="875593634123171288">显示 VPN 设置</translation>
 <translation id="8809737090443522491">输入应用或文档的名称</translation>
 <translation id="8814190375133053267">Wi-Fi</translation>
 <translation id="8825534185036233643">系统不支持镜像两个以上的显示屏。</translation>
 <translation id="8828714802988429505">90°</translation>
 <translation id="8841375032071747811">“返回”按钮</translation>
+<translation id="8843682306134542540">切换旋转锁定设置。<ph name="STATE_TEXT" /></translation>
 <translation id="8850991929411075241">Search+Esc</translation>
 <translation id="8870509716567206129">应用不支持分屏。</translation>
 <translation id="8874184842967597500">未连接</translation>
diff --git a/ash/strings/ash_strings_zh-TW.xtb b/ash/strings/ash_strings_zh-TW.xtb
index b26d507..95e2572bc 100644
--- a/ash/strings/ash_strings_zh-TW.xtb
+++ b/ash/strings/ash_strings_zh-TW.xtb
@@ -330,6 +330,7 @@
 <translation id="6857811139397017780">啟用 <ph name="NETWORKSERVICE" /></translation>
 <translation id="6910714959251846841">必須對你的裝置執行 Powerwash 才能安裝這項更新。進一步瞭解最新的 <ph name="SYSTEM_APP_NAME" />更新內容。</translation>
 <translation id="6911468394164995108">加入其他網路...</translation>
+<translation id="6972754398087986839">開始使用</translation>
 <translation id="6981982820502123353">協助工具</translation>
 <translation id="698231206551913481">將這位使用者移除後,與這位使用者相關聯的所有檔案和本機資料都會遭到永久刪除。</translation>
 <translation id="7015766095477679451"><ph name="COME_BACK_TIME" /> 裝置就會解除鎖定。</translation>
diff --git a/ash/system/date/date_view.cc b/ash/system/date/date_view.cc
index ca71faed..9db4638 100644
--- a/ash/system/date/date_view.cc
+++ b/ash/system/date/date_view.cc
@@ -4,6 +4,8 @@
 
 #include "ash/system/date/date_view.h"
 
+#include "ash/session/session_controller.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/model/clock_model.h"
 #include "ash/system/model/system_tray_model.h"
@@ -294,6 +296,17 @@
   Layout();
 }
 
+void TimeView::SetTextColorBasedOnSession(
+    session_manager::SessionState session_state) {
+  auto set_color = [&](std::unique_ptr<views::Label>& label) {
+    label->SetEnabledColor(TrayIconColor(session_state));
+  };
+
+  set_color(horizontal_label_);
+  set_color(vertical_label_hours_);
+  set_color(vertical_label_minutes_);
+}
+
 void TimeView::Refresh() {
   UpdateText();
 }
diff --git a/ash/system/date/date_view.h b/ash/system/date/date_view.h
index b133753a..d68d672 100644
--- a/ash/system/date/date_view.h
+++ b/ash/system/date/date_view.h
@@ -13,6 +13,7 @@
 #include "base/i18n/time_formatting.h"
 #include "base/macros.h"
 #include "base/timer/timer.h"
+#include "components/session_manager/session_manager_types.h"
 #include "ui/views/view.h"
 
 namespace base {
@@ -126,6 +127,9 @@
   // Updates clock layout.
   void UpdateClockLayout(ClockLayout clock_layout);
 
+  // Updates the time color based on the current session state.
+  void SetTextColorBasedOnSession(session_manager::SessionState session_state);
+
   // ClockObserver:
   void Refresh() override;
 
diff --git a/ash/system/date/tray_system_info.cc b/ash/system/date/tray_system_info.cc
index b022443..fc6d1e0 100644
--- a/ash/system/date/tray_system_info.cc
+++ b/ash/system/date/tray_system_info.cc
@@ -12,32 +12,52 @@
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
-#include "ash/system/tray/tray_item_view.h"
 
 namespace ash {
 
+namespace tray {
+
+TimeTrayItemView::TimeTrayItemView(SystemTrayItem* owner, Shelf* shelf)
+    : TrayItemView(owner), session_observer_(this) {
+  tray::TimeView::ClockLayout clock_layout =
+      shelf->IsHorizontalAlignment()
+          ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK
+          : tray::TimeView::ClockLayout::VERTICAL_CLOCK;
+  time_view_ = new tray::TimeView(clock_layout,
+                                  Shell::Get()->system_tray_model()->clock());
+  AddChildView(time_view_);
+}
+
+TimeTrayItemView::~TimeTrayItemView() = default;
+
+void TimeTrayItemView::UpdateAlignmentForShelf(Shelf* shelf) {
+  tray::TimeView::ClockLayout clock_layout =
+      shelf->IsHorizontalAlignment()
+          ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK
+          : tray::TimeView::ClockLayout::VERTICAL_CLOCK;
+  time_view_->UpdateClockLayout(clock_layout);
+}
+
+void TimeTrayItemView::OnSessionStateChanged(
+    session_manager::SessionState state) {
+  time_view_->SetTextColorBasedOnSession(state);
+}
+
+}  // namespace tray
+
 TraySystemInfo::TraySystemInfo(SystemTray* system_tray)
-    : SystemTrayItem(system_tray, SystemTrayItemUmaType::UMA_DATE),
-      tray_view_(nullptr),
-      default_view_(nullptr) {}
+    : SystemTrayItem(system_tray, SystemTrayItemUmaType::UMA_DATE) {}
 
 TraySystemInfo::~TraySystemInfo() = default;
 
 const tray::TimeView* TraySystemInfo::GetTimeTrayForTesting() const {
-  return tray_view_;
+  return tray_view_->time_view();
 }
 
 views::View* TraySystemInfo::CreateTrayView(LoginStatus status) {
   CHECK(tray_view_ == nullptr);
-  tray::TimeView::ClockLayout clock_layout =
-      system_tray()->shelf()->IsHorizontalAlignment()
-          ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK
-          : tray::TimeView::ClockLayout::VERTICAL_CLOCK;
-  tray_view_ = new tray::TimeView(clock_layout,
-                                  Shell::Get()->system_tray_model()->clock());
-  views::View* view = new TrayItemView(this);
-  view->AddChildView(tray_view_);
-  return view;
+  tray_view_ = new tray::TimeTrayItemView(this, system_tray()->shelf());
+  return tray_view_;
 }
 
 views::View* TraySystemInfo::CreateDefaultView(LoginStatus status) {
@@ -54,13 +74,8 @@
 }
 
 void TraySystemInfo::UpdateAfterShelfAlignmentChange() {
-  if (tray_view_) {
-    tray::TimeView::ClockLayout clock_layout =
-        system_tray()->shelf()->IsHorizontalAlignment()
-            ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK
-            : tray::TimeView::ClockLayout::VERTICAL_CLOCK;
-    tray_view_->UpdateClockLayout(clock_layout);
-  }
+  if (tray_view_)
+    tray_view_->UpdateAlignmentForShelf(system_tray()->shelf());
 }
 
 }  // namespace ash
diff --git a/ash/system/date/tray_system_info.h b/ash/system/date/tray_system_info.h
index 7676936..2c6011eb 100644
--- a/ash/system/date/tray_system_info.h
+++ b/ash/system/date/tray_system_info.h
@@ -9,20 +9,39 @@
 
 #include "ash/ash_export.h"
 #include "ash/login_status.h"
+#include "ash/session/session_controller.h"
+#include "ash/session/session_observer.h"
 #include "ash/system/date/clock_observer.h"
 #include "ash/system/tray/system_tray_item.h"
+#include "ash/system/tray/tray_item_view.h"
 #include "base/macros.h"
 
-namespace views {
-class Label;
-}
-
 namespace ash {
+class Shelf;
 class SystemInfoDefaultView;
 
 namespace tray {
+
 class TimeView;
-}
+
+class TimeTrayItemView : public TrayItemView, public SessionObserver {
+ public:
+  TimeTrayItemView(SystemTrayItem* owner, Shelf* shelf);
+  ~TimeTrayItemView() override;
+
+  void UpdateAlignmentForShelf(Shelf* shelf);
+  tray::TimeView* time_view() { return time_view_; }
+
+  // SessionObserver:
+  void OnSessionStateChanged(session_manager::SessionState state) override;
+
+ private:
+  TimeView* time_view_ = nullptr;
+  ScopedSessionObserver session_observer_;
+  DISALLOW_COPY_AND_ASSIGN(TimeTrayItemView);
+};
+
+}  // namespace tray
 
 // The bottom row of the system menu. The default view shows the current date
 // and power status. The tray view shows the current time.
@@ -41,10 +60,8 @@
   void OnDefaultViewDestroyed() override;
   void UpdateAfterShelfAlignmentChange() override;
 
-  void SetupLabelForTimeTray(views::Label* label);
-
-  tray::TimeView* tray_view_;
-  SystemInfoDefaultView* default_view_;
+  tray::TimeTrayItemView* tray_view_ = nullptr;
+  SystemInfoDefaultView* default_view_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TraySystemInfo);
 };
diff --git a/ash/system/ime/ime_feature_pod_controller.cc b/ash/system/ime/ime_feature_pod_controller.cc
index f4853523..4b601ab 100644
--- a/ash/system/ime/ime_feature_pod_controller.cc
+++ b/ash/system/ime/ime_feature_pod_controller.cc
@@ -8,6 +8,7 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/unified/feature_pod_button.h"
 #include "ash/system/unified/unified_system_tray_controller.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -53,9 +54,13 @@
 
 IMEFeaturePodController::IMEFeaturePodController(
     UnifiedSystemTrayController* tray_controller)
-    : tray_controller_(tray_controller) {}
+    : tray_controller_(tray_controller) {
+  Shell::Get()->system_tray_notifier()->AddIMEObserver(this);
+}
 
-IMEFeaturePodController::~IMEFeaturePodController() = default;
+IMEFeaturePodController::~IMEFeaturePodController() {
+  Shell::Get()->system_tray_notifier()->RemoveIMEObserver(this);
+}
 
 FeaturePodButton* IMEFeaturePodController::CreateButton() {
   button_ = new FeaturePodButton(this);
@@ -76,6 +81,14 @@
   return SystemTrayItemUmaType::UMA_IME;
 }
 
+void IMEFeaturePodController::OnIMERefresh() {
+  Update();
+}
+
+void IMEFeaturePodController::OnIMEMenuActivationChanged(bool is_activated) {
+  Update();
+}
+
 void IMEFeaturePodController::Update() {
   button_->SetSubLabel(GetLabelString());
   button_->SetVisible(IsButtonVisible());
diff --git a/ash/system/ime/ime_feature_pod_controller.h b/ash/system/ime/ime_feature_pod_controller.h
index 535e5f2..4d2a6430 100644
--- a/ash/system/ime/ime_feature_pod_controller.h
+++ b/ash/system/ime/ime_feature_pod_controller.h
@@ -6,6 +6,7 @@
 #define ASH_SYSTEM_IME_IME_FEATURE_POD_CONTROLLER_H_
 
 #include "ash/ash_export.h"
+#include "ash/system/ime/ime_observer.h"
 #include "ash/system/unified/feature_pod_controller_base.h"
 #include "base/macros.h"
 
@@ -14,7 +15,8 @@
 class UnifiedSystemTrayController;
 
 // Controller of IME feature pod button.
-class ASH_EXPORT IMEFeaturePodController : public FeaturePodControllerBase {
+class ASH_EXPORT IMEFeaturePodController : public FeaturePodControllerBase,
+                                           public IMEObserver {
  public:
   IMEFeaturePodController(UnifiedSystemTrayController* tray_controller);
   ~IMEFeaturePodController() override;
@@ -27,6 +29,10 @@
  private:
   void Update();
 
+  // IMEObserver:
+  void OnIMERefresh() override;
+  void OnIMEMenuActivationChanged(bool is_activated) override;
+
   // Unowned.
   UnifiedSystemTrayController* const tray_controller_;
   FeaturePodButton* button_ = nullptr;
diff --git a/ash/system/ime/ime_feature_pod_controller_unittest.cc b/ash/system/ime/ime_feature_pod_controller_unittest.cc
new file mode 100644
index 0000000..a8049ff
--- /dev/null
+++ b/ash/system/ime/ime_feature_pod_controller_unittest.cc
@@ -0,0 +1,104 @@
+// 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 "ash/system/ime/ime_feature_pod_controller.h"
+
+#include <vector>
+
+#include "ash/shell.h"
+#include "ash/ime/ime_controller.h"
+#include "ash/system/unified/feature_pod_button.h"
+#include "ash/system/unified/unified_system_tray_controller.h"
+#include "ash/system/unified/unified_system_tray_model.h"
+#include "ash/test/ash_test_base.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+
+
+namespace ash {
+
+// Tests manually control their session state.
+class IMEFeaturePodControllerTest : public NoSessionAshTestBase {
+ public:
+  IMEFeaturePodControllerTest() = default;
+  ~IMEFeaturePodControllerTest() override = default;
+
+  void SetUp() override {
+    NoSessionAshTestBase::SetUp();
+
+    tray_model_ = std::make_unique<UnifiedSystemTrayModel>();
+    tray_controller_ =
+        std::make_unique<UnifiedSystemTrayController>(tray_model_.get());
+  }
+
+  void TearDown() override {
+    button_.reset();
+    controller_.reset();
+    tray_controller_.reset();
+    tray_model_.reset();
+    NoSessionAshTestBase::TearDown();
+  }
+
+ protected:
+  void SetUpButton() {
+    controller_ =
+        std::make_unique<IMEFeaturePodController>(tray_controller());
+    button_.reset(controller_->CreateButton());
+  }
+
+  UnifiedSystemTrayController* tray_controller() {
+    return tray_controller_.get();
+  }
+
+  FeaturePodButton* button() { return button_.get(); }
+
+  // Creates |count| simulated active IMEs.
+  void SetActiveIMECount(int count) {
+    available_imes_.resize(count);
+    for (int i = 0; i < count; ++i)
+      available_imes_[i].id = base::IntToString(i);
+    RefreshImeController();
+  }
+
+  void RefreshImeController() {
+    std::vector<mojom::ImeInfoPtr> available_ime_ptrs;
+    for (const auto& ime : available_imes_)
+      available_ime_ptrs.push_back(ime.Clone());
+
+    std::vector<mojom::ImeMenuItemPtr> menu_item_ptrs;
+    for (const auto& item : menu_items_)
+      menu_item_ptrs.push_back(item.Clone());
+
+    Shell::Get()->ime_controller()->RefreshIme(current_ime_.id,
+                                              std::move(available_ime_ptrs),
+                                              std::move(menu_item_ptrs));
+  }
+
+ private:
+  std::unique_ptr<UnifiedSystemTrayModel> tray_model_;
+  std::unique_ptr<UnifiedSystemTrayController> tray_controller_;
+  std::unique_ptr<IMEFeaturePodController> controller_;
+  std::unique_ptr<FeaturePodButton> button_;
+
+  // IMEs
+  mojom::ImeInfo current_ime_;
+  std::vector<mojom::ImeInfo> available_imes_;
+  std::vector<mojom::ImeMenuItem> menu_items_;
+
+  DISALLOW_COPY_AND_ASSIGN(IMEFeaturePodControllerTest);
+};
+
+// Tests that if the pod button is hidden if less than 2 IMEs are present.
+TEST_F(IMEFeaturePodControllerTest, ButtonVisibilityIMECount) {
+  SetUpButton();
+
+  SetActiveIMECount(0);
+  EXPECT_FALSE(button()->visible());
+  SetActiveIMECount(1);
+  EXPECT_FALSE(button()->visible());
+  SetActiveIMECount(2);
+  EXPECT_TRUE(button()->visible());
+}
+
+}  // namespace ash
diff --git a/ash/system/ime/tray_ime_chromeos.cc b/ash/system/ime/tray_ime_chromeos.cc
index dcbbbd2c..836a071a 100644
--- a/ash/system/ime/tray_ime_chromeos.cc
+++ b/ash/system/ime/tray_ime_chromeos.cc
@@ -10,6 +10,7 @@
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/ime/ime_controller.h"
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_observer.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/model/system_tray_model.h"
@@ -41,6 +42,28 @@
 #include "ui/views/widget/widget.h"
 
 namespace ash {
+
+namespace {
+class IMETrayItemView : public TrayItemView, public SessionObserver {
+ public:
+  explicit IMETrayItemView(SystemTrayItem* owner) : TrayItemView(owner) {
+    CreateLabel();
+    SetupLabelForTray(label());
+  }
+  ~IMETrayItemView() override = default;
+
+  // SessionObserver:
+  void OnSessionStateChanged(session_manager::SessionState state) override {
+    label()->SetEnabledColor(TrayIconColor(state));
+  }
+
+ private:
+  ScopedSessionObserver session_observer_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(IMETrayItemView);
+};
+}  // namespace
+
 namespace tray {
 
 class IMEDefaultView : public TrayItemMore {
@@ -210,9 +233,7 @@
 
 views::View* TrayIME::CreateTrayView(LoginStatus status) {
   CHECK(tray_label_ == nullptr);
-  tray_label_ = new TrayItemView(this);
-  tray_label_->CreateLabel();
-  SetupLabelForTray(tray_label_->label());
+  tray_label_ = new IMETrayItemView(this);
   // Hide IME tray when it is created, it will be updated when it is notified
   // of the IME refresh event.
   tray_label_->SetVisible(false);
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc
index 2af83d7..f52166d 100644
--- a/ash/system/ime_menu/ime_list_view.cc
+++ b/ash/system/ime_menu/ime_list_view.cc
@@ -6,11 +6,11 @@
 
 #include "ash/ime/ime_controller.h"
 #include "ash/ime/ime_switch_type.h"
+#include "ash/keyboard/virtual_keyboard_controller.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/interfaces/ime_info.mojom.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
-#include "ash/shell_port.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/actionable_view.h"
 #include "ash/system/tray/system_menu_button.h"
@@ -330,7 +330,7 @@
                                       const ui::Event& event) {
   DCHECK_EQ(sender, keyboard_status_row_->toggle());
 
-  ShellPort::Get()->ToggleIgnoreExternalKeyboard();
+  Shell::Get()->virtual_keyboard_controller()->ToggleIgnoreExternalKeyboard();
   last_selected_item_id_.clear();
   last_item_selected_with_keyboard_ = false;
 }
diff --git a/ash/system/message_center/notification_tray.cc b/ash/system/message_center/notification_tray.cc
index c0059d0..779dde9 100644
--- a/ash/system/message_center/notification_tray.cc
+++ b/ash/system/message_center/notification_tray.cc
@@ -352,38 +352,30 @@
   if (IsMessageCenterVisible())
     return true;
 
-  if (switches::IsSidebarEnabled()) {
-    SidebarInitMode mode =
-        (!show_settings ? SidebarInitMode::NORMAL
-                        : SidebarInitMode::MESSAGE_CENTER_SETTINGS);
-    // TODO(yoshiki): Support non-primary desktop on multi-display environment.
-    Shell::Get()->GetPrimaryRootWindowController()->sidebar()->Show(mode);
-  } else {
-    MessageCenterBubble* message_center_bubble =
-        new MessageCenterBubble(message_center());
+  MessageCenterBubble* message_center_bubble =
+      new MessageCenterBubble(message_center());
 
-    // In the horizontal case, message center starts from the top of the shelf.
-    // In the vertical case, it starts from the bottom of NotificationTray.
-    const int max_height = (shelf()->IsHorizontalAlignment()
-                                ? shelf()->GetUserWorkAreaBounds().height()
-                                : GetBoundsInScreen().bottom() -
-                                      shelf()->GetUserWorkAreaBounds().y());
-    // Sets the maximum height, considering the padding from the top edge of
-    // screen. This padding should be applied in all types of shelf alignment.
-    message_center_bubble->SetMaxHeight(max_height - kPaddingFromScreenTop);
+  // In the horizontal case, message center starts from the top of the shelf.
+  // In the vertical case, it starts from the bottom of NotificationTray.
+  const int max_height = (shelf()->IsHorizontalAlignment()
+                              ? shelf()->GetUserWorkAreaBounds().height()
+                              : GetBoundsInScreen().bottom() -
+                                    shelf()->GetUserWorkAreaBounds().y());
+  // Sets the maximum height, considering the padding from the top edge of
+  // screen. This padding should be applied in all types of shelf alignment.
+  message_center_bubble->SetMaxHeight(max_height - kPaddingFromScreenTop);
 
-    if (show_settings)
-      message_center_bubble->SetSettingsVisible();
+  if (show_settings)
+    message_center_bubble->SetSettingsVisible();
 
-    // For vertical shelf alignments, anchor to the NotificationTray, but for
-    // horizontal (i.e. bottom) shelves, anchor to the system tray.
-    TrayBackgroundView* anchor_tray = this;
-    if (shelf()->IsHorizontalAlignment())
-      anchor_tray = shelf()->GetSystemTrayAnchor();
+  // For vertical shelf alignments, anchor to the NotificationTray, but for
+  // horizontal (i.e. bottom) shelves, anchor to the system tray.
+  TrayBackgroundView* anchor_tray = this;
+  if (shelf()->IsHorizontalAlignment())
+    anchor_tray = shelf()->GetSystemTrayAnchor();
 
-    message_center_bubble_ = std::make_unique<NotificationBubbleWrapper>(
-        this, anchor_tray, message_center_bubble, show_by_click);
-  }
+  message_center_bubble_ = std::make_unique<NotificationBubbleWrapper>(
+      this, anchor_tray, message_center_bubble, show_by_click);
 
   shelf()->UpdateAutoHideState();
   SetIsActive(true);
@@ -395,20 +387,11 @@
 }
 
 void NotificationTray::HideMessageCenter() {
-  if ((switches::IsSidebarEnabled() && !IsMessageCenterVisible()) ||
-      (!switches::IsSidebarEnabled() && !message_center_bubble()))
+  if (!message_center_bubble())
     return;
 
   SetIsActive(false);
-  if (switches::IsSidebarEnabled()) {
-    Sidebar* sidebar =
-        RootWindowController::ForWindow(GetWidget()->GetNativeView())
-            ->sidebar();
-    if (sidebar)
-      sidebar->Hide();
-  } else {
-    message_center_bubble_.reset();
-  }
+  message_center_bubble_.reset();
   show_message_center_on_unlock_ = false;
   shelf()->UpdateAutoHideState();
 }
@@ -442,15 +425,8 @@
 }
 
 bool NotificationTray::IsMessageCenterVisible() const {
-  if (switches::IsSidebarEnabled()) {
-    Sidebar* sidebar =
-        RootWindowController::ForWindow(GetWidget()->GetNativeView())
-            ->sidebar();
-    return sidebar && sidebar->IsVisible();
-  } else {
-    return message_center_bubble() &&
-           message_center_bubble()->bubble()->IsVisible();
-  }
+  return message_center_bubble() &&
+         message_center_bubble()->bubble()->IsVisible();
 }
 
 void NotificationTray::UpdateAfterShelfAlignmentChange() {
@@ -528,16 +504,8 @@
 
 bool NotificationTray::ShowNotifierSettings() {
   if (IsMessageCenterVisible()) {
-    if (switches::IsSidebarEnabled()) {
-      Sidebar* sidebar =
-          RootWindowController::ForWindow(GetWidget()->GetNativeView())
-              ->sidebar();
-      if (sidebar)
-        sidebar->Show(SidebarInitMode::MESSAGE_CENTER_SETTINGS);
-    } else {
-      static_cast<MessageCenterBubble*>(message_center_bubble()->bubble())
-          ->SetSettingsVisible();
-    }
+    static_cast<MessageCenterBubble*>(message_center_bubble()->bubble())
+        ->SetSettingsVisible();
     return true;
   }
   return ShowMessageCenterInternal(true /* show_settings */,
diff --git a/ash/system/message_center/session_state_notification_blocker.cc b/ash/system/message_center/session_state_notification_blocker.cc
index 4f3bd1a..82e4375 100644
--- a/ash/system/message_center/session_state_notification_blocker.cc
+++ b/ash/system/message_center/session_state_notification_blocker.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/message_center/session_state_notification_blocker.h"
 
-#include "ash/public/cpp/ash_features.h"
+#include "ash/message_center/ash_message_center_lock_screen_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ui/message_center/message_center.h"
@@ -21,7 +21,7 @@
 
   return !session_controller->IsRunningInAppMode() &&
          (!session_controller->IsScreenLocked() ||
-          features::IsLockScreenNotificationsEnabled());
+          AshMessageCenterLockScreenController::IsEnabled());
 }
 
 bool CalculateShouldShowPopup() {
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc
index a36daf9..3d3befb 100644
--- a/ash/system/network/network_icon.cc
+++ b/ash/system/network/network_icon.cc
@@ -165,9 +165,16 @@
 // Number of discrete images to use for alpha fade animation
 const int kNumFadeImages = 10;
 
+bool IsTrayIcon(IconType icon_type) {
+  return icon_type == ICON_TYPE_TRAY_REGULAR ||
+         icon_type == ICON_TYPE_TRAY_OOBE;
+}
+
 SkColor GetDefaultColorForIconType(IconType icon_type) {
-  if (icon_type == ICON_TYPE_TRAY)
+  if (icon_type == ICON_TYPE_TRAY_REGULAR)
     return kTrayIconColor;
+  if (icon_type == ICON_TYPE_TRAY_OOBE)
+    return kOobeTrayIconColor;
   if (features::IsSystemTrayUnifiedEnabled())
     return kUnifiedMenuIconColor;
   else
@@ -175,7 +182,7 @@
 }
 
 bool IconTypeIsDark(IconType icon_type) {
-  return (icon_type != ICON_TYPE_TRAY);
+  return icon_type != ICON_TYPE_TRAY_REGULAR;
 }
 
 bool IconTypeHasVPNBadge(IconType icon_type) {
@@ -214,7 +221,7 @@
 // have an associated Tether network. Used to display the correct icon.
 std::string GetEffectiveNetworkType(const NetworkState* network,
                                     IconType icon_type) {
-  if (icon_type == ICON_TYPE_TRAY && network->type() == shill::kTypeWifi &&
+  if (IsTrayIcon(icon_type) && network->type() == shill::kTypeWifi &&
       !network->tether_guid().empty()) {
     return chromeos::kTypeTether;
   }
@@ -228,7 +235,7 @@
 
 gfx::Size GetSizeForIconType(IconType icon_type) {
   int size = kMenuIconSize;
-  if (icon_type == ICON_TYPE_TRAY) {
+  if (IsTrayIcon(icon_type)) {
     size = kTrayIconSize;
   } else if (features::IsSystemTrayUnifiedEnabled() &&
              icon_type == ICON_TYPE_DEFAULT_VIEW) {
@@ -352,7 +359,7 @@
                             strength_index);
   }
   if (network->Matches(NetworkTypePattern::VPN())) {
-    DCHECK_NE(ICON_TYPE_TRAY, icon_type);
+    DCHECK(!IsTrayIcon(icon_type));
     return gfx::CreateVectorIcon(kNetworkVpnIcon,
                                  GetDefaultColorForIconType(ICON_TYPE_LIST));
   }
@@ -367,7 +374,7 @@
 gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) {
   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
   const NetworkState* connected_network = nullptr;
-  if (icon_type == ICON_TYPE_TRAY) {
+  if (IsTrayIcon(icon_type)) {
     connected_network =
         handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
   }
@@ -710,7 +717,7 @@
       state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual());
   const NetworkState* connecting_network =
       state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless());
-  if (!connecting_network && icon_type == ICON_TYPE_TRAY) {
+  if (!connecting_network && IsTrayIcon(icon_type)) {
     connecting_network =
         state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN());
   }
@@ -728,7 +735,7 @@
   }
 
   // Don't show ethernet in the tray
-  if (icon_type == ICON_TYPE_TRAY && network &&
+  if (IsTrayIcon(icon_type) && network &&
       network->Matches(NetworkTypePattern::Ethernet())) {
     *image = gfx::ImageSkia();
     *animating = false;
@@ -788,7 +795,8 @@
        iter != networks.end(); ++iter) {
     network_paths.insert((*iter)->path());
   }
-  PurgeIconMap(ICON_TYPE_TRAY, network_paths);
+  PurgeIconMap(ICON_TYPE_TRAY_OOBE, network_paths);
+  PurgeIconMap(ICON_TYPE_TRAY_REGULAR, network_paths);
   PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths);
   PurgeIconMap(ICON_TYPE_LIST, network_paths);
   PurgeIconMap(ICON_TYPE_MENU_LIST, network_paths);
diff --git a/ash/system/network/network_icon.h b/ash/system/network/network_icon.h
index c978e89..e4b8728ec 100644
--- a/ash/system/network/network_icon.h
+++ b/ash/system/network/network_icon.h
@@ -22,7 +22,8 @@
 
 // Type of icon which dictates color theme and VPN badging
 enum IconType {
-  ICON_TYPE_TRAY,          // light icons with VPN badges
+  ICON_TYPE_TRAY_OOBE,     // dark icons with VPN badges, used during OOBE
+  ICON_TYPE_TRAY_REGULAR,  // light icons with VPN badges, used outside of OOBE
   ICON_TYPE_DEFAULT_VIEW,  // dark icons with VPN badges
   ICON_TYPE_LIST,          // dark icons without VPN badges; in-line status
   ICON_TYPE_MENU_LIST,     // dark icons without VPN badges; separate status
diff --git a/ash/system/network/network_icon_unittest.cc b/ash/system/network/network_icon_unittest.cc
index 340ff75..060200f 100644
--- a/ash/system/network/network_icon_unittest.cc
+++ b/ash/system/network/network_icon_unittest.cc
@@ -118,7 +118,7 @@
 
   const base::MessageLoop message_loop_;
 
-  IconType icon_type_ = ICON_TYPE_TRAY;
+  IconType icon_type_ = ICON_TYPE_TRAY_REGULAR;
 
   chromeos::NetworkStateHandler* handler_;
 
diff --git a/ash/system/network/network_tray_view.cc b/ash/system/network/network_tray_view.cc
index adc2cd72..7b04afd 100644
--- a/ash/system/network/network_tray_view.cc
+++ b/ash/system/network/network_tray_view.cc
@@ -4,6 +4,8 @@
 
 #include "ash/system/network/network_tray_view.h"
 
+#include "ash/session/session_controller.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/network/network_icon.h"
 #include "ash/system/network/network_icon_animation.h"
@@ -47,8 +49,14 @@
   gfx::ImageSkia image;
   base::string16 name;
   bool animating = false;
-  network_icon::GetDefaultNetworkImageAndLabel(network_icon::ICON_TYPE_TRAY,
-                                               &image, &name, &animating);
+  auto icon_type = network_icon::ICON_TYPE_TRAY_REGULAR;
+  if (Shell::Get()->session_controller()->GetSessionState() ==
+      session_manager::SessionState::OOBE) {
+    icon_type = network_icon::ICON_TYPE_TRAY_OOBE;
+  }
+
+  network_icon::GetDefaultNetworkImageAndLabel(icon_type, &image, &name,
+                                               &animating);
   bool show_in_tray = !image.isNull();
   UpdateIcon(show_in_tray, image);
   if (animating)
@@ -67,6 +75,11 @@
   UpdateConnectionStatus(GetConnectedNetwork(), false /* notify_a11y */);
 }
 
+void NetworkTrayView::OnSessionStateChanged(
+    session_manager::SessionState state) {
+  UpdateNetworkStateHandlerIcon();
+}
+
 void NetworkTrayView::UpdateConnectionStatus(
     const NetworkState* connected_network,
     bool notify_a11y) {
diff --git a/ash/system/network/network_tray_view.h b/ash/system/network/network_tray_view.h
index ef4616b..bc5b69c7 100644
--- a/ash/system/network/network_tray_view.h
+++ b/ash/system/network/network_tray_view.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_NETWORK_NETWORK_TRAY_VIEW_H_
 #define ASH_SYSTEM_NETWORK_NETWORK_TRAY_VIEW_H_
 
+#include "ash/session/session_observer.h"
 #include "ash/system/network/network_icon_animation_observer.h"
 #include "ash/system/tray/tray_item_view.h"
 #include "base/macros.h"
@@ -22,7 +23,8 @@
 const chromeos::NetworkState* GetConnectedNetwork();
 
 class NetworkTrayView : public TrayItemView,
-                        public network_icon::AnimationObserver {
+                        public network_icon::AnimationObserver,
+                        public SessionObserver {
  public:
   explicit NetworkTrayView(TrayNetwork* network_tray);
 
@@ -38,6 +40,9 @@
   // network_icon::AnimationObserver:
   void NetworkIconChanged() override;
 
+  // SessionObserver:
+  void OnSessionStateChanged(session_manager::SessionState state) override;
+
   // Updates connection status and notifies accessibility event when necessary.
   void UpdateConnectionStatus(const chromeos::NetworkState* connected_network,
                               bool notify_a11y);
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc
index c2f3edea..99a3c37 100644
--- a/ash/system/power/power_prefs.cc
+++ b/ash/system/power/power_prefs.cc
@@ -98,6 +98,8 @@
   registry->RegisterBooleanPref(
       prefs::kPowerForceNonzeroBrightnessForUserActivity, true,
       PrefRegistry::PUBLIC);
+  registry->RegisterBooleanPref(prefs::kPowerSmartDimEnabled, true,
+                                PrefRegistry::PUBLIC);
 
   if (for_test) {
     registry->RegisterBooleanPref(prefs::kAllowScreenLock, true,
@@ -296,6 +298,7 @@
   pref_change_registrar_->Add(
       prefs::kPowerForceNonzeroBrightnessForUserActivity, update_callback);
   pref_change_registrar_->Add(prefs::kAllowScreenLock, update_callback);
+  pref_change_registrar_->Add(prefs::kPowerSmartDimEnabled, update_callback);
 
   UpdatePowerPolicyFromPrefs();
 }
diff --git a/ash/system/power/power_prefs_unittest.cc b/ash/system/power/power_prefs_unittest.cc
index 2dd4657..340f92d 100644
--- a/ash/system/power/power_prefs_unittest.cc
+++ b/ash/system/power/power_prefs_unittest.cc
@@ -264,4 +264,10 @@
             GetCurrentPowerPolicyActions());
 }
 
+TEST_F(PowerPrefsTest, SmartDimEnabled) {
+  PrefService* prefs =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  EXPECT_TRUE(prefs->GetBoolean(prefs::kPowerSmartDimEnabled));
+}
+
 }  // namespace ash
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc
index 39375f8..b5537ea 100644
--- a/ash/system/power/tray_power.cc
+++ b/ash/system/power/tray_power.cc
@@ -10,6 +10,8 @@
 #include "ash/public/cpp/ash_switches.h"
 
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/date/date_view.h"
 #include "ash/system/power/battery_notification.h"
@@ -59,6 +61,10 @@
   UpdateStatus();
 }
 
+void PowerTrayView::OnSessionStateChanged(session_manager::SessionState state) {
+  UpdateImage();
+}
+
 void PowerTrayView::UpdateStatus() {
   UpdateImage();
   SetVisible(PowerStatus::Get()->IsBatteryPresent());
@@ -68,12 +74,20 @@
 void PowerTrayView::UpdateImage() {
   const PowerStatus::BatteryImageInfo& info =
       PowerStatus::Get()->GetBatteryImageInfo();
-  // Only change the image when the info changes. http://crbug.com/589348
-  if (info_ && info_->ApproximatelyEqual(info))
+  session_manager::SessionState session_state =
+      Shell::Get()->session_controller()->GetSessionState();
+
+  // Only change the image when the info changes and the icon color has not
+  // changed. http://crbug.com/589348
+  if (info_ && info_->ApproximatelyEqual(info) &&
+      icon_session_state_color_ == session_state)
     return;
   info_ = info;
+  icon_session_state_color_ = session_state;
+
+  SkColor color = TrayIconColor(session_state);
   image_view()->SetImage(PowerStatus::GetBatteryImage(
-      info, kTrayIconSize, SkColorSetA(kTrayIconColor, 0x4C), kTrayIconColor));
+      info, kTrayIconSize, SkColorSetA(color, 0x4C), color));
 }
 
 }  // namespace tray
diff --git a/ash/system/power/tray_power.h b/ash/system/power/tray_power.h
index 5bf8c100e..b47b0084 100644
--- a/ash/system/power/tray_power.h
+++ b/ash/system/power/tray_power.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ash/session/session_observer.h"
 #include "ash/system/power/power_status.h"
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/system/tray/tray_item_view.h"
@@ -16,24 +17,32 @@
 
 namespace tray {
 
-class PowerTrayView : public TrayItemView, public PowerStatus::Observer {
+class PowerTrayView : public TrayItemView,
+                      public PowerStatus::Observer,
+                      public SessionObserver {
  public:
   explicit PowerTrayView(SystemTrayItem* owner);
 
   ~PowerTrayView() override;
 
-  // Overridden from views::View.
+  // views::View:
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
-  // Overridden from PowerStatus::Observer.
+  // PowerStatus::Observer:
   void OnPowerStatusChanged() override;
 
+  // SessionObserver:
+  void OnSessionStateChanged(session_manager::SessionState state) override;
+
  private:
   void UpdateStatus();
   void UpdateImage();
 
   base::string16 accessible_name_;
   base::Optional<PowerStatus::BatteryImageInfo> info_;
+  session_manager::SessionState icon_session_state_color_ =
+      session_manager::SessionState::UNKNOWN;
+  ScopedSessionObserver session_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(PowerTrayView);
 };
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc
index 0acee76f..0cc0f5e 100644
--- a/ash/system/tray/tray_constants.cc
+++ b/ash/system/tray/tray_constants.cc
@@ -55,6 +55,8 @@
 
 const int kTrayIconSize = 16;
 const SkColor kTrayIconColor = SK_ColorWHITE;
+const SkColor kOobeTrayIconColor = gfx::kGoogleGrey600;
+
 const int kMenuIconSize = 20;
 const SkColor kMenuIconColor = gfx::kChromeIconGrey;
 const SkColor kMenuIconColorDisabled = SkColorSetA(gfx::kChromeIconGrey, 0x61);
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index dc68df91..3d869cf 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -93,6 +93,7 @@
 // system tray.
 extern const int kTrayIconSize;
 extern const SkColor kTrayIconColor;
+extern const SkColor kOobeTrayIconColor;
 
 // The total visual padding at the start and end of the icon/label section
 // of the tray.
diff --git a/ash/system/tray/tray_utils.cc b/ash/system/tray/tray_utils.cc
index 6b60b125..8bd323173 100644
--- a/ash/system/tray/tray_utils.cc
+++ b/ash/system/tray/tray_utils.cc
@@ -18,4 +18,10 @@
       kTrayTextFontSizeIncrease, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
 }
 
+SkColor TrayIconColor(session_manager::SessionState session_state) {
+  if (session_state == session_manager::SessionState::OOBE)
+    return kOobeTrayIconColor;
+  return kTrayIconColor;
+}
+
 }  // namespace ash
diff --git a/ash/system/tray/tray_utils.h b/ash/system/tray/tray_utils.h
index fbc7b31..fb89ed0 100644
--- a/ash/system/tray/tray_utils.h
+++ b/ash/system/tray/tray_utils.h
@@ -5,6 +5,9 @@
 #ifndef ASH_SYSTEM_TRAY_TRAY_UTILS_H_
 #define ASH_SYSTEM_TRAY_TRAY_UTILS_H_
 
+#include "components/session_manager/session_manager_types.h"
+#include "third_party/skia/include/core/SkColor.h"
+
 namespace views {
 class Label;
 }
@@ -14,6 +17,9 @@
 // Sets up a Label properly for the tray (sets color, font etc.).
 void SetupLabelForTray(views::Label* label);
 
+// Get the current tray icon color for the given session state.
+SkColor TrayIconColor(session_manager::SessionState session_state);
+
 }  // namespace ash
 
 #endif  // ASH_SYSTEM_TRAY_TRAY_UTILS_H_
diff --git a/ash/system/unified/ime_mode_view.cc b/ash/system/unified/ime_mode_view.cc
index 3a53a0d..873f874e 100644
--- a/ash/system/unified/ime_mode_view.cc
+++ b/ash/system/unified/ime_mode_view.cc
@@ -5,8 +5,10 @@
 #include "ash/system/unified/ime_mode_view.h"
 
 #include "ash/ime/ime_controller.h"
+#include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
+#include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_utils.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ui/views/controls/label.h"
@@ -46,6 +48,10 @@
   Update();
 }
 
+void ImeModeView::OnSessionStateChanged(session_manager::SessionState state) {
+  Update();
+}
+
 void ImeModeView::Update() {
   // Do not show IME mode icon in tablet mode as it's less useful and screen
   // space is limited.
@@ -63,6 +69,8 @@
              (ime_count > 1 || ime_controller->managed_by_policy()));
 
   label()->SetText(ime_controller->current_ime().short_name);
+  label()->SetEnabledColor(
+      TrayIconColor(Shell::Get()->session_controller()->GetSessionState()));
   Layout();
 }
 
diff --git a/ash/system/unified/ime_mode_view.h b/ash/system/unified/ime_mode_view.h
index b0b596b9..246b20e 100644
--- a/ash/system/unified/ime_mode_view.h
+++ b/ash/system/unified/ime_mode_view.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_UNIFIED_IME_MODE_VIEW_H_
 #define ASH_SYSTEM_UNIFIED_IME_MODE_VIEW_H_
 
+#include "ash/session/session_observer.h"
 #include "ash/system/ime/ime_observer.h"
 #include "ash/system/tray/tray_item_view.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
@@ -15,7 +16,8 @@
 // An IME mode icon view in UnifiedSystemTray button.
 class ImeModeView : public TrayItemView,
                     public IMEObserver,
-                    public TabletModeObserver {
+                    public TabletModeObserver,
+                    public SessionObserver {
  public:
   ImeModeView();
   ~ImeModeView() override;
@@ -28,11 +30,16 @@
   void OnTabletModeStarted() override;
   void OnTabletModeEnded() override;
 
+  // SessionObserver:
+  void OnSessionStateChanged(session_manager::SessionState state) override;
+
  private:
   void Update();
 
   bool ime_menu_on_shelf_activated_ = false;
 
+  ScopedSessionObserver session_observer_{this};
+
   DISALLOW_COPY_AND_ASSIGN(ImeModeView);
 };
 
diff --git a/ash/system/unified/top_shortcuts_view.cc b/ash/system/unified/top_shortcuts_view.cc
index 84e640f..8cbfdb5 100644
--- a/ash/system/unified/top_shortcuts_view.cc
+++ b/ash/system/unified/top_shortcuts_view.cc
@@ -146,6 +146,7 @@
   if (Shell::Get()->session_controller()->login_status() !=
       LoginStatus::NOT_LOGGED_IN) {
     user_avatar_button_ = new UserAvatarButton(this);
+    user_avatar_button_->SetEnabled(controller->IsUserChooserEnabled());
     container_->AddChildView(user_avatar_button_);
   }
 
@@ -198,7 +199,7 @@
 void TopShortcutsView::ButtonPressed(views::Button* sender,
                                      const ui::Event& event) {
   if (sender == user_avatar_button_)
-    controller_->ShowUserChooserWidget();
+    controller_->ShowUserChooserView();
   else if (sender == sign_out_button_)
     controller_->HandleSignOutAction();
   else if (sender == lock_button_)
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index af91cf14..46ebcbd4 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -10,6 +10,7 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/date/date_view.h"
+#include "ash/system/date/tray_system_info.h"
 #include "ash/system/message_center/ash_popup_alignment_delegate.h"
 #include "ash/system/model/clock_model.h"
 #include "ash/system/model/system_tray_model.h"
@@ -151,9 +152,7 @@
       ime_mode_view_(new ImeModeView()),
       notification_counter_item_(new NotificationCounterView()),
       quiet_mode_view_(new QuietModeView()),
-      time_view_(
-          new tray::TimeView(tray::TimeView::ClockLayout::HORIZONTAL_CLOCK,
-                             Shell::Get()->system_tray_model()->clock())) {
+      time_view_(new tray::TimeTrayItemView(nullptr, shelf)) {
   tray_container()->AddChildView(ime_mode_view_);
   tray_container()->AddChildView(notification_counter_item_);
   tray_container()->AddChildView(quiet_mode_view_);
@@ -167,10 +166,7 @@
   }
 
   tray_container()->AddChildView(new tray::PowerTrayView(nullptr));
-
-  TrayItemView* time_item = new TrayItemView(nullptr);
-  time_item->AddChildView(time_view_);
-  tray_container()->AddChildView(time_item);
+  tray_container()->AddChildView(time_view_);
 
   SetInkDropMode(InkDropMode::ON);
   set_separator_visibility(false);
@@ -281,10 +277,7 @@
 
 void UnifiedSystemTray::UpdateAfterShelfAlignmentChange() {
   TrayBackgroundView::UpdateAfterShelfAlignmentChange();
-  time_view_->UpdateClockLayout(
-      shelf()->IsHorizontalAlignment()
-          ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK
-          : tray::TimeView::ClockLayout::VERTICAL_CLOCK);
+  time_view_->UpdateAlignmentForShelf(shelf());
 }
 
 void UnifiedSystemTray::ShowBubbleInternal(bool show_by_click) {
diff --git a/ash/system/unified/unified_system_tray.h b/ash/system/unified/unified_system_tray.h
index 532a215..e08c0c1 100644
--- a/ash/system/unified/unified_system_tray.h
+++ b/ash/system/unified/unified_system_tray.h
@@ -13,7 +13,7 @@
 namespace ash {
 
 namespace tray {
-class TimeView;
+class TimeTrayItemView;
 }  // namespace tray
 
 class ImeModeView;
@@ -118,7 +118,7 @@
   ImeModeView* const ime_mode_view_;
   NotificationCounterView* const notification_counter_item_;
   QuietModeView* const quiet_mode_view_;
-  tray::TimeView* const time_view_;
+  tray::TimeTrayItemView* const time_view_;
 
   DISALLOW_COPY_AND_ASSIGN(UnifiedSystemTray);
 };
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index faefec5..cdb4b3d 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -217,9 +217,12 @@
   // TODO(yamaguchi): Reconsider this formula. The y-position of the top edge
   // still differes by few pixels between the horizontal and vertical shelf
   // modes.
+  gfx::Rect anchor_bounds =
+      tray_->shelf()->GetSystemTrayAnchor()->GetBoundsInScreen();
+  int bottom = tray_->shelf()->IsHorizontalAlignment() ? anchor_bounds.y()
+                                                       : anchor_bounds.bottom();
   int free_space_height_above_anchor =
-      tray_->shelf()->GetSystemTrayAnchor()->GetBoundsInScreen().y() -
-      tray_->shelf()->GetUserWorkAreaBounds().y();
+      bottom - tray_->shelf()->GetUserWorkAreaBounds().y();
   return free_space_height_above_anchor - kPaddingFromScreenTop -
          bubble_view_->GetBorderInsets().height();
 }
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index 0b798df..f95455e2 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -213,22 +213,9 @@
   StartAnimation(velocity < 0);
 }
 
-void UnifiedSystemTrayController::ShowUserChooserWidget() {
-  // Don't allow user add or switch when CancelCastingDialog is open.
-  // See http://crrev.com/291276 and http://crbug.com/353170.
-  if (Shell::IsSystemModalWindowOpen())
+void UnifiedSystemTrayController::ShowUserChooserView() {
+  if (!IsUserChooserEnabled())
     return;
-
-  // Don't allow at login, lock or when adding a multi-profile user.
-  SessionController* session = Shell::Get()->session_controller();
-  if (session->IsUserSessionBlocked())
-    return;
-
-  // Don't show if we cannot add or switch users.
-  if (session->GetAddUserPolicy() != AddUserSessionPolicy::ALLOWED &&
-      session->NumberOfLoggedInUsers() <= 1)
-    return;
-
   unified_view_->SetDetailedView(new UserChooserView(this));
 }
 
@@ -305,6 +292,24 @@
   animation_->Show();
 }
 
+bool UnifiedSystemTrayController::IsUserChooserEnabled() const {
+  // Don't allow user add or switch when CancelCastingDialog is open.
+  // See http://crrev.com/291276 and http://crbug.com/353170.
+  if (Shell::IsSystemModalWindowOpen())
+    return false;
+
+  // Don't allow at login, lock or when adding a multi-profile user.
+  SessionController* session = Shell::Get()->session_controller();
+  if (session->IsUserSessionBlocked())
+    return false;
+
+  // Don't show if we cannot add or switch users.
+  if (session->GetAddUserPolicy() != AddUserSessionPolicy::ALLOWED &&
+      session->NumberOfLoggedInUsers() <= 1)
+    return false;
+  return true;
+}
+
 void UnifiedSystemTrayController::AnimationEnded(
     const gfx::Animation* animation) {
   UpdateExpandedAmount();
diff --git a/ash/system/unified/unified_system_tray_controller.h b/ash/system/unified/unified_system_tray_controller.h
index 7133b32..69929aec 100644
--- a/ash/system/unified/unified_system_tray_controller.h
+++ b/ash/system/unified/unified_system_tray_controller.h
@@ -69,8 +69,8 @@
   void EndDrag(const gfx::Point& location);
   void Fling(int velocity);
 
-  // Show user selector popup widget. Called from the view.
-  void ShowUserChooserWidget();
+  // Show user selector view. Called from the view.
+  void ShowUserChooserView();
   // Show the detailed view of network. If |force| is true, it shows the
   // detailed view even if it's collapsed. Called from the view.
   void ShowNetworkDetailedView(bool force);
@@ -103,6 +103,9 @@
   // Ensure the main view is expanded. Called from the slider bubble controller.
   void EnsureExpanded();
 
+  // Return true if user chooser is enabled. Called from the view.
+  bool IsUserChooserEnabled() const;
+
   // gfx::AnimationDelegate:
   void AnimationEnded(const gfx::Animation* animation) override;
   void AnimationProgressed(const gfx::Animation* animation) override;
diff --git a/ash/system/unified/unified_system_tray_test_api.cc b/ash/system/unified/unified_system_tray_test_api.cc
index ce4e69c..2bb88fb7 100644
--- a/ash/system/unified/unified_system_tray_test_api.cc
+++ b/ash/system/unified/unified_system_tray_test_api.cc
@@ -7,6 +7,7 @@
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/date/date_view.h"
+#include "ash/system/date/tray_system_info.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/unified/unified_system_tray_bubble.h"
@@ -105,7 +106,8 @@
 }
 
 void UnifiedSystemTrayTestApi::Is24HourClock(Is24HourClockCallback cb) {
-  base::HourClockType type = tray_->time_view_->GetHourTypeForTesting();
+  base::HourClockType type =
+      tray_->time_view_->time_view()->GetHourTypeForTesting();
   std::move(cb).Run(type == base::k24HourClock);
 }
 
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index cbb2a1b..544e3fd 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/unified_system_tray_view.h"
 
+#include "ash/message_center/ash_message_center_lock_screen_controller.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/session/session_controller.h"
@@ -281,7 +282,7 @@
   notification_hidden_view_->SetVisible(
       session_controller->GetUserSession(0) &&
       session_controller->IsScreenLocked() &&
-      !features::IsLockScreenNotificationsEnabled());
+      !AshMessageCenterLockScreenController::IsEnabled());
   AddChildView(notification_hidden_view_);
 
   AddChildView(system_tray_container_);
@@ -376,7 +377,10 @@
 }
 
 int UnifiedSystemTrayView::GetExpandedHeight() const {
-  return top_shortcuts_view_->GetPreferredSize().height() +
+  return (notification_hidden_view_->visible()
+              ? notification_hidden_view_->GetPreferredSize().height()
+              : 0) +
+         top_shortcuts_view_->GetPreferredSize().height() +
          feature_pods_container_->GetExpandedHeight() +
          sliders_container_->GetExpandedHeight() +
          system_info_view_->GetPreferredSize().height();
diff --git a/ash/system/update/tray_update.cc b/ash/system/update/tray_update.cc
index 436f060..e8607a8 100644
--- a/ash/system/update/tray_update.cc
+++ b/ash/system/update/tray_update.cc
@@ -36,6 +36,7 @@
   const SkColor default_color = for_menu ? kMenuIconColor : kTrayIconColor;
   switch (severity) {
     case mojom::UpdateSeverity::NONE:
+    case mojom::UpdateSeverity::VERY_LOW:  // Not used on Chrome OS.
       return default_color;
     case mojom::UpdateSeverity::LOW:
       return for_menu ? gfx::kGoogleGreen700 : kTrayIconColor;
@@ -44,10 +45,8 @@
     case mojom::UpdateSeverity::HIGH:
     case mojom::UpdateSeverity::CRITICAL:
       return for_menu ? gfx::kGoogleRed700 : gfx::kGoogleRed300;
-    default:
-      NOTREACHED();
-      break;
   }
+  NOTREACHED() << severity;
   return default_color;
 }
 
diff --git a/ash/test/ash_test_suite.cc b/ash/test/ash_test_suite.cc
index 1a308048..a80f65fb 100644
--- a/ash/test/ash_test_suite.cc
+++ b/ash/test/ash_test_suite.cc
@@ -16,6 +16,7 @@
 #include "ui/base/ui_base_switches.h"
 #include "ui/compositor/test/context_factories_for_test.h"
 #include "ui/gfx/gfx_paths.h"
+#include "ui/gl/gl_switches.h"
 #include "ui/gl/test/gl_surface_test_support.h"
 
 namespace ash {
@@ -26,6 +27,12 @@
 
 void AshTestSuite::Initialize() {
   base::TestSuite::Initialize();
+
+  // Force software-gl. This is necessary for tests that trigger launching ash
+  // in its own process
+  base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  cmd_line->AppendSwitch(switches::kOverrideUseSoftwareGLForTests);
+
   gl::GLSurfaceTestSupport::InitializeOneOff();
 
   gfx::RegisterPathProvider();
diff --git a/ash/wm/overlay_layout_manager.cc b/ash/wm/overlay_layout_manager.cc
new file mode 100644
index 0000000..6ea24c73
--- /dev/null
+++ b/ash/wm/overlay_layout_manager.cc
@@ -0,0 +1,46 @@
+// 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 "ash/wm/overlay_layout_manager.h"
+
+#include "ash/wm/window_state.h"
+#include "ash/wm/wm_event.h"
+#include "base/logging.h"
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+
+using display::Screen;
+
+namespace ash {
+
+OverlayLayoutManager::OverlayLayoutManager(aura::Window* overlay_container)
+    : overlay_container_(overlay_container) {
+  DCHECK(overlay_container_);
+  Screen::GetScreen()->AddObserver(this);
+}
+
+OverlayLayoutManager::~OverlayLayoutManager() {
+  Screen::GetScreen()->RemoveObserver(this);
+}
+
+void OverlayLayoutManager::OnDisplayMetricsChanged(
+    const display::Display& display,
+    uint32_t changed_metrics) {
+  if (display.id() !=
+      Screen::GetScreen()->GetDisplayNearestWindow(overlay_container_).id()) {
+    // The update wasn't for this container's display.
+    return;
+  }
+
+  for (aura::Window* child : overlay_container_->children()) {
+    wm::WindowState* window_state = wm::GetWindowState(child);
+    if (window_state->IsFullscreen()) {
+      const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED);
+      window_state->OnWMEvent(&event);
+    }
+  }
+}
+
+}  // namespace ash
diff --git a/ash/wm/overlay_layout_manager.h b/ash/wm/overlay_layout_manager.h
new file mode 100644
index 0000000..7108cc94
--- /dev/null
+++ b/ash/wm/overlay_layout_manager.h
@@ -0,0 +1,39 @@
+// 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 ASH_WM_OVERLAY_LAYOUT_MANAGER_H_
+#define ASH_WM_OVERLAY_LAYOUT_MANAGER_H_
+
+#include "ash/ash_export.h"
+#include "ash/wm/wm_snap_to_pixel_layout_manager.h"
+#include "base/macros.h"
+#include "ui/display/display_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ash {
+
+// Updates the bounds of widgets in the overlay container whenever the display
+// bounds change. Keeps children snapped to pixel bounds.
+class ASH_EXPORT OverlayLayoutManager : public wm::WmSnapToPixelLayoutManager,
+                                        public display::DisplayObserver {
+ public:
+  explicit OverlayLayoutManager(aura::Window* overlay_container);
+  ~OverlayLayoutManager() override;
+
+  // display::DisplayObserver:
+  void OnDisplayMetricsChanged(const display::Display& display,
+                               uint32_t changed_metrics) override;
+
+ private:
+  aura::Window* overlay_container_;
+
+  DISALLOW_COPY_AND_ASSIGN(OverlayLayoutManager);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_OVERLAY_LAYOUT_MANAGER_H_
diff --git a/ash/wm/overlay_layout_manager_unittest.cc b/ash/wm/overlay_layout_manager_unittest.cc
new file mode 100644
index 0000000..b89fa91
--- /dev/null
+++ b/ash/wm/overlay_layout_manager_unittest.cc
@@ -0,0 +1,36 @@
+// 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 "ash/wm/overlay_layout_manager.h"
+
+#include <memory>
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/test/ash_test_base.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace {
+
+using OverlayLayoutManagerTest = AshTestBase;
+
+// Verifies that a fullscreen widget in the overlay container has its bounds
+// updated when the display rotates. https://crbug.com/869130
+TEST_F(OverlayLayoutManagerTest, FullscreenWidgetWithDisplayRotation) {
+  UpdateDisplay("800x600");
+
+  // Create a fullscreen widget in the overlay container.
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(nullptr, kShellWindowId_OverlayContainer);
+  widget->SetFullscreen(true);
+  EXPECT_EQ(gfx::Rect(0, 0, 800, 600), widget->GetWindowBoundsInScreen());
+
+  // Widget bounds update after display rotation.
+  UpdateDisplay("800x600/r");
+  EXPECT_EQ(gfx::Rect(0, 0, 600, 800), widget->GetWindowBoundsInScreen());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index d3f81e5..c37c7503b 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -101,15 +101,19 @@
         ->UpdateNudge(item_, val);
     val = base::ClampToRange(val, 0.f, 1.f);
     float opacity = original_opacity_;
-    if (opacity > kItemMinOpacity) {
+    if (opacity > kItemMinOpacity)
       opacity = original_opacity_ - val * (original_opacity_ - kItemMinOpacity);
-    }
     item_->SetOpacity(opacity);
   } else if (current_drag_behavior_ == DragBehavior::kDragToSnap) {
     UpdateDragIndicatorsAndWindowGrid(location_in_screen);
     x_offset = location_in_screen.x() - previous_event_location_.x();
   }
 
+  // Update the split view divider bar status if necessary. If splitview is
+  // active when dragging the overview window, the split divider bar should be
+  // placed below the dragged window during dragging.
+  split_view_controller_->OnWindowDragStarted(item_->GetWindow());
+
   // Update the dragged |item_|'s bounds accordingly.
   gfx::Rect bounds(item_->target_bounds());
   bounds.Offset(x_offset,
@@ -120,6 +124,13 @@
 
 void OverviewWindowDragController::CompleteDrag(
     const gfx::Point& location_in_screen) {
+  // Update the split view divider bar stuatus if necessary. The divider bar
+  // should be placed above the dragged window after drag ends. Note here the
+  // passed paramters |snap_position_| and |location_in_screen| won't be used in
+  // this function for this case, but they are passed in as placeholders.
+  split_view_controller_->OnWindowDragEnded(item_->GetWindow(), snap_position_,
+                                            location_in_screen);
+
   // Update window grid bounds and |snap_position_| in case the screen
   // orientation was changed.
   if (current_drag_behavior_ == DragBehavior::kDragToSnap) {
@@ -248,22 +259,9 @@
   SplitViewController::SnapPosition last_snap_position = snap_position_;
   snap_position_ = GetSnapPosition(location_in_screen);
 
-  // If there is already a snapped window in |snap_position_|, do not allow
-  // another window snap in the same position.
-  SplitViewController::State snapped_state = split_view_controller_->state();
-  if ((snap_position_ == SplitViewController::LEFT &&
-       snapped_state == SplitViewController::LEFT_SNAPPED) ||
-      (snap_position_ == SplitViewController::RIGHT &&
-       snapped_state == SplitViewController::RIGHT_SNAPPED)) {
-    snap_position_ = SplitViewController::NONE;
-    window_selector_->SetSplitViewDragIndicatorsIndicatorState(
-        IndicatorState::kNone, gfx::Point());
-    return;
-  }
-
   // If there is no current snapped window, update the window grid size if the
   // dragged window can be snapped if dropped.
-  if (snapped_state == SplitViewController::NO_SNAP &&
+  if (split_view_controller_->state() == SplitViewController::NO_SNAP &&
       snap_position_ != last_snap_position) {
     // Do not reposition the item that is currently being dragged.
     window_selector_->SetBoundsForWindowGridsInScreenIgnoringWindow(
@@ -356,49 +354,59 @@
       screen_util::GetDisplayWorkAreaBoundsInParent(item_->GetWindow()));
   ::wm::ConvertRectToScreen(item_->GetWindow()->GetRootWindow(), &area);
 
-  switch (split_view_controller_->GetCurrentScreenOrientation()) {
-    case OrientationLockType::kLandscapePrimary:
-    case OrientationLockType::kLandscapeSecondary: {
-      // The window can be snapped if it reaches close enough to the screen
-      // edge of the screen (on primary axis). The edge insets are a fixed ratio
-      // of the screen plus some padding. This matches the drag indicators ui.
-      const int screen_edge_inset_for_drag =
-          area.width() * kHighlightScreenPrimaryAxisRatio +
-          kHighlightScreenEdgePaddingDp;
-      area.Inset(screen_edge_inset_for_drag, 0);
-      if (location_in_screen.x() <= area.x()) {
-        return split_view_controller_->IsCurrentScreenOrientationPrimary()
-                   ? SplitViewController::LEFT
-                   : SplitViewController::RIGHT;
-      }
-      if (location_in_screen.x() >= area.right() - 1) {
-        return split_view_controller_->IsCurrentScreenOrientationPrimary()
-                   ? SplitViewController::RIGHT
-                   : SplitViewController::LEFT;
-      }
-      return SplitViewController::NONE;
+  const bool is_landscape =
+      split_view_controller_->IsCurrentScreenOrientationLandscape();
+  const bool is_primary =
+      split_view_controller_->IsCurrentScreenOrientationPrimary();
+
+  // If split view mode is active at the moment, and dragging an overview window
+  // to snap it to a position that already has a snapped window in place, we
+  // should show the preview window as soon as the window past the split divider
+  // bar.
+  if (split_view_controller_->IsSplitViewModeActive()) {
+    const int position =
+        is_landscape ? location_in_screen.x() : location_in_screen.y();
+    SplitViewController::SnapPosition default_snap_position =
+        split_view_controller_->default_snap_position();
+    // If we're trying to snap to a position that already has a snapped window:
+    const bool re_snap =
+        is_primary == (position < split_view_controller_->divider_position() ==
+                       (default_snap_position == SplitViewController::LEFT));
+    if (re_snap)
+      return default_snap_position;
+  }
+
+  if (is_landscape) {
+    // The window can be snapped if it reaches close enough to the screen
+    // edge of the screen (on primary axis). The edge insets are a fixed ratio
+    // of the screen plus some padding. This matches the drag indicators ui.
+    const int screen_edge_inset_for_drag =
+        area.width() * kHighlightScreenPrimaryAxisRatio +
+        kHighlightScreenEdgePaddingDp;
+    area.Inset(screen_edge_inset_for_drag, 0);
+    if (location_in_screen.x() <= area.x()) {
+      return is_primary ? SplitViewController::LEFT
+                        : SplitViewController::RIGHT;
     }
-    case OrientationLockType::kPortraitPrimary:
-    case OrientationLockType::kPortraitSecondary: {
-      const int screen_edge_inset_for_drag =
-          area.height() * kHighlightScreenPrimaryAxisRatio +
-          kHighlightScreenEdgePaddingDp;
-      area.Inset(0, screen_edge_inset_for_drag);
-      if (location_in_screen.y() <= area.y()) {
-        return split_view_controller_->IsCurrentScreenOrientationPrimary()
-                   ? SplitViewController::LEFT
-                   : SplitViewController::RIGHT;
-      }
-      if (location_in_screen.y() >= area.bottom() - 1) {
-        return split_view_controller_->IsCurrentScreenOrientationPrimary()
-                   ? SplitViewController::RIGHT
-                   : SplitViewController::LEFT;
-      }
-      return SplitViewController::NONE;
+    if (location_in_screen.x() >= area.right() - 1) {
+      return is_primary ? SplitViewController::RIGHT
+                        : SplitViewController::LEFT;
     }
-    default:
-      NOTREACHED();
-      return SplitViewController::NONE;
+    return SplitViewController::NONE;
+  } else {
+    const int screen_edge_inset_for_drag =
+        area.height() * kHighlightScreenPrimaryAxisRatio +
+        kHighlightScreenEdgePaddingDp;
+    area.Inset(0, screen_edge_inset_for_drag);
+    if (location_in_screen.y() <= area.y()) {
+      return is_primary ? SplitViewController::LEFT
+                        : SplitViewController::RIGHT;
+    }
+    if (location_in_screen.y() >= area.bottom() - 1) {
+      return is_primary ? SplitViewController::RIGHT
+                        : SplitViewController::LEFT;
+    }
+    return SplitViewController::NONE;
   }
 }
 
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 04902e3..d20a971 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -595,7 +595,7 @@
   // Add the mask which gives the window selector items rounded corners, and add
   // the shadow around the window.
   ui::Layer* layer = minimized_widget_
-                         ? minimized_widget_->GetContentsView()->layer()
+                         ? minimized_widget_->GetNativeWindow()->layer()
                          : window_->layer();
 
   if (!minimized_widget_)
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc
index f5ac63f..7c81aa2 100644
--- a/ash/wm/overview/window_grid.cc
+++ b/ash/wm/overview/window_grid.cc
@@ -198,10 +198,6 @@
   widget->SetContentsView(new NewSelectorItemView());
   widget->Show();
 
-  // Stack the newly created widget below the dragged window.
-  dragged_window->parent()->StackChildBelow(widget->GetNativeWindow(),
-                                            dragged_window);
-
   if (animate) {
     widget->SetOpacity(0.f);
     ui::ScopedLayerAnimationSettings animation_settings(
@@ -577,6 +573,9 @@
   window_selector_->AddItem(new_selector_item_widget_->GetNativeWindow(),
                             /*reposition=*/true, animate);
 
+  // Stack the |dragged_window| at top during drag.
+  dragged_window->parent()->StackChildAtTop(dragged_window);
+
   // Called to set caption and title visibility during dragging.
   OnSelectorItemDragStarted(/*item=*/nullptr);
 }
diff --git a/ash/wm/overview/window_grid.h b/ash/wm/overview/window_grid.h
index 2532db1..b5de4bb 100644
--- a/ash/wm/overview/window_grid.h
+++ b/ash/wm/overview/window_grid.h
@@ -124,8 +124,8 @@
   void OnSelectorItemDragStarted(WindowSelectorItem* item);
   void OnSelectorItemDragEnded();
 
-  // Called when a window's tab(s) start/continue/end being dragged around in
-  // WindowGrid.
+  // Called when a window (either it's browser window or an app window)
+  // start/continue/end being dragged in tablet mode.
   void OnWindowDragStarted(aura::Window* dragged_window, bool animate);
   void OnWindowDragContinued(aura::Window* dragged_window,
                              const gfx::Point& location_in_screen,
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 770e3ab..40b95d4 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -139,8 +139,8 @@
   void ActivateDraggedWindow();
   void ResetDraggedWindowGesture();
 
-  // Called when a window's tab(s) start/continue/end being dragged around if
-  // overview mode is active.
+  // Called when a window (either it's browser window or an app window)
+  // start/continue/end being dragged in tablet mode.
   // TODO(xdai): Currently it doesn't work for multi-display scenario.
   void OnWindowDragStarted(aura::Window* dragged_window, bool animate);
   void OnWindowDragContinued(aura::Window* dragged_window,
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 5d9a4e9..aff8229 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -1143,19 +1143,6 @@
     widget_window->parent()->StackChildAtTop(widget_window);
     widget_window->parent()->StackChildBelow(window, widget_window);
   }
-
-  // If split view mode is actvie and there is already a snapped window, stack
-  // this item's window below the snapped window. Note: this should be temporary
-  // for M66, see https://crbug.com/809298 for details.
-  if (Shell::Get()->IsSplitViewModeActive()) {
-    aura::Window* snapped_window =
-        Shell::Get()->split_view_controller()->GetDefaultSnappedWindow();
-    if (widget_window && widget_window->parent() == window->parent() &&
-        widget_window->parent() == snapped_window->parent()) {
-      widget_window->parent()->StackChildBelow(widget_window, snapped_window);
-      widget_window->parent()->StackChildBelow(window, widget_window);
-    }
-  }
 }
 
 }  // namespace ash
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 95003dcf..f0865a51 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -3207,14 +3207,18 @@
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
 
   // Drag |window2| selector item to attempt to snap to left. Since there is
-  // already one left snapped window, we do not allow |window2| snap to left.
+  // already one left snapped window |window1|, |window1| will be put in
+  // overview mode.
   WindowSelectorItem* selector_item2 =
       GetWindowItemForWindow(grid_index, window2.get());
   DragWindowTo(selector_item2, gfx::Point(0, 0));
 
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::LEFT_SNAPPED);
-  EXPECT_EQ(split_view_controller()->left_window(), window1.get());
+  EXPECT_EQ(split_view_controller()->left_window(), window2.get());
+  EXPECT_TRUE(
+      window_selector_controller()->window_selector()->IsWindowInOverview(
+          window1.get()));
 
   // Drag |window3| selector item to snap to right.
   WindowSelectorItem* selector_item3 =
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index c49863a1..4624a93 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -289,8 +289,10 @@
     splitview_start_time_ = base::Time::Now();
   }
 
+  aura::Window* previous_snapped_window = nullptr;
   if (snap_position == LEFT) {
     if (left_window_ != window) {
+      previous_snapped_window = left_window_;
       StopObserving(LEFT);
       left_window_ = window;
     }
@@ -300,6 +302,7 @@
     }
   } else if (snap_position == RIGHT) {
     if (right_window_ != window) {
+      previous_snapped_window = right_window_;
       StopObserving(RIGHT);
       right_window_ = window;
     }
@@ -310,6 +313,10 @@
   }
   StartObserving(window);
 
+  // Insert the previous snapped window to overview if overview is active.
+  if (previous_snapped_window)
+    InsertWindowToOverview(previous_snapped_window);
+
   // Update the divider position and window bounds before snapping a new window.
   // Since the minimum size of |window| maybe larger than currently bounds in
   // |snap_position|.
@@ -1400,18 +1407,6 @@
   window_selector->RemoveWindowSelectorItem(item, /*reposition=*/false);
 }
 
-aura::Window* SplitViewController::GetSnappedWindowAt(
-    SnapPosition snap_position) {
-  switch (snap_position) {
-    case LEFT:
-      return left_window_;
-    case RIGHT:
-      return right_window_;
-    default:
-      return nullptr;
-  }
-}
-
 void SplitViewController::InsertWindowToOverview(aura::Window* window) {
   if (!window || !Shell::Get()->window_selector_controller()->IsSelecting())
     return;
@@ -1442,8 +1437,8 @@
     aura::Window* window,
     SnapPosition desired_snap_position,
     const gfx::Point& last_location_in_screen) {
-  // If the newly created window has been added to overview window, do
-  // nothing.
+  // If dragged window was in overview before or it has been added to overview
+  // window by dropping on the new selector item, do nothing.
   WindowSelectorController* window_selector_controller =
       Shell::Get()->window_selector_controller();
   if (window_selector_controller->IsSelecting() &&
@@ -1458,15 +1453,9 @@
       // Even though |snap_position| equals |NONE|, the dragged window still
       // needs to be snapped if splitview mode is active at the momemnt.
       // Calculate the expected snap position based on the last event
-      // location.
-      SplitViewController::SnapPosition snap_position =
-          GetSnapPosition(window, last_location_in_screen);
-      aura::Window* previous_snapped_window = GetSnappedWindowAt(snap_position);
-      SnapWindow(window, snap_position);
-      if (state() != SplitViewController::BOTH_SNAPPED) {
-        DCHECK(window_selector_controller->IsSelecting());
-        InsertWindowToOverview(previous_snapped_window);
-      }
+      // location. Note if there is already a window at |desired_snap_postion|,
+      // SnapWindow() will put the previous snapped window in overview.
+      SnapWindow(window, GetSnapPosition(window, last_location_in_screen));
     } else {
       if (window_selector_controller->IsSelecting()) {
         window_selector_controller->window_selector()
@@ -1477,8 +1466,8 @@
       }
     }
   } else {
-    aura::Window* previous_snapped_window =
-        GetSnappedWindowAt(desired_snap_position);
+    // Note SnapWindow() might put the previous window that was snapped at the
+    // |desired_snap_position| in overview.
     SnapWindow(window, desired_snap_position);
     if (!was_splitview_active) {
       // If splitview mode was not active before snapping the dragged
@@ -1492,17 +1481,9 @@
                        ? SplitViewController::RIGHT
                        : SplitViewController::LEFT);
       } else {
+        // If overview is not active, open overview.
         StartOverview();
       }
-    } else {
-      // If splitview mode was active before snapping the dragged window,
-      // but the dragged window was then snapped to the same side (i.e.,
-      // overview mode is still active), put the previous snapped window to
-      // overview window grid.
-      if (state() != SplitViewController::BOTH_SNAPPED) {
-        DCHECK(window_selector_controller->IsSelecting());
-        InsertWindowToOverview(previous_snapped_window);
-      }
     }
   }
 }
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 9907f4dc..e5945979 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -317,9 +317,6 @@
   // called before trying to snap the window.
   void RemoveWindowFromOverviewIfApplicable(aura::Window* window);
 
-  // Returns the window that is currently snapped at |snap_position|.
-  aura::Window* GetSnappedWindowAt(SnapPosition snap_position);
-
   // Inserts |window| into overview window grid if overview mode is active. Do
   // nothing if overview mode is inactive at the moment.
   void InsertWindowToOverview(aura::Window* window);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 2ef131b..9a0e580 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -29,7 +29,6 @@
 import("//build/config/sysroot.gni")
 import("//build/config/ui.gni")
 import("//build/nocompile.gni")
-import("//build/timestamp.gni")
 import("//build/util/lastchange.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
 import("//testing/test.gni")
@@ -2739,10 +2738,14 @@
     "$target_gen_dir/generated_build_date.h",
   ]
 
-  args = [
-    rebase_path("$target_gen_dir/generated_build_date.h", root_build_dir),
-    build_timestamp,
-  ]
+  args =
+      [ rebase_path("$target_gen_dir/generated_build_date.h", root_build_dir) ]
+
+  if (is_official_build) {
+    args += [ "official" ]
+  } else {
+    args += [ "default" ]
+  }
 }
 
 if (enable_nocompile_tests) {
diff --git a/base/sampling_heap_profiler/module_cache.cc b/base/sampling_heap_profiler/module_cache.cc
index 2b5efc9..9384f4c 100644
--- a/base/sampling_heap_profiler/module_cache.cc
+++ b/base/sampling_heap_profiler/module_cache.cc
@@ -30,4 +30,12 @@
       .first->second;
 }
 
+std::vector<const ModuleCache::Module*> ModuleCache::GetModules() const {
+  std::vector<const Module*> result;
+  result.reserve(modules_cache_map_.size());
+  for (const auto& it : modules_cache_map_)
+    result.push_back(&it.second);
+  return result;
+}
+
 }  // namespace base
diff --git a/base/sampling_heap_profiler/module_cache.h b/base/sampling_heap_profiler/module_cache.h
index 2fccb78a..ec039c3 100644
--- a/base/sampling_heap_profiler/module_cache.h
+++ b/base/sampling_heap_profiler/module_cache.h
@@ -6,6 +6,7 @@
 #define BASE_SAMPLING_HEAP_PROFILER_MODULE_CACHE_H_
 
 #include <map>
+#include <vector>
 
 #include "base/profiler/stack_sampling_profiler.h"
 
@@ -19,6 +20,7 @@
   ~ModuleCache();
 
   const Module& GetModuleForAddress(uintptr_t address);
+  std::vector<const Module*> GetModules() const;
 
  private:
   std::map<uintptr_t, Module> modules_cache_map_;
diff --git a/base/sampling_heap_profiler/module_cache_unittest.cc b/base/sampling_heap_profiler/module_cache_unittest.cc
index a353f0a..92a8270 100644
--- a/base/sampling_heap_profiler/module_cache_unittest.cc
+++ b/base/sampling_heap_profiler/module_cache_unittest.cc
@@ -19,8 +19,10 @@
 // addresses within the module.
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 #define MAYBE_ModuleCache ModuleCache
+#define MAYBE_ModulesList ModulesList
 #else
 #define MAYBE_ModuleCache DISABLED_ModuleCache
+#define MAYBE_ModulesList DISABLED_ModulesList
 #endif
 TEST_F(ModuleCacheTest, MAYBE_ModuleCache) {
   uintptr_t ptr1 = reinterpret_cast<uintptr_t>(&AFunctionForTest);
@@ -34,6 +36,15 @@
   EXPECT_GT(module1.base_address + module1.size, ptr2);
 }
 
+TEST_F(ModuleCacheTest, MAYBE_ModulesList) {
+  ModuleCache cache;
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(&AFunctionForTest);
+  const ModuleCache::Module& module = cache.GetModuleForAddress(ptr);
+  EXPECT_TRUE(module.is_valid);
+  EXPECT_EQ(1u, cache.GetModules().size());
+  EXPECT_EQ(&module, cache.GetModules().front());
+}
+
 TEST_F(ModuleCacheTest, InvalidModule) {
   ModuleCache cache;
   const ModuleCache::Module& invalid_module = cache.GetModuleForAddress(1);
diff --git a/base/task/sequence_manager/thread_controller_impl.cc b/base/task/sequence_manager/thread_controller_impl.cc
index 5f6f933..228b34c 100644
--- a/base/task/sequence_manager/thread_controller_impl.cc
+++ b/base/task/sequence_manager/thread_controller_impl.cc
@@ -146,6 +146,8 @@
 }
 
 void ThreadControllerImpl::DoWork(WorkType work_type) {
+  TRACE_EVENT0("sequence_manager", "ThreadControllerImpl::DoWork");
+
   DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
   DCHECK(sequence_);
 
@@ -165,8 +167,10 @@
     if (!task)
       break;
 
-    TRACE_TASK_EXECUTION("ThreadControllerImpl::DoWork", *task);
-    task_annotator_.RunTask("ThreadControllerImpl::DoWork", &*task);
+    {
+      TRACE_TASK_EXECUTION("ThreadControllerImpl::RunTask", *task);
+      task_annotator_.RunTask("ThreadControllerImpl::RunTask", &*task);
+    }
 
     if (!weak_ptr)
       return;
diff --git a/base/task/task_scheduler/task_scheduler.h b/base/task/task_scheduler/task_scheduler.h
index 5d030883..895e36b 100644
--- a/base/task/task_scheduler/task_scheduler.h
+++ b/base/task/task_scheduler/task_scheduler.h
@@ -46,8 +46,8 @@
 //
 // The instance methods of this class are thread-safe.
 //
-// Note: All base/task_scheduler users should go through post_task.h instead of
-// TaskScheduler except for the one callsite per process which manages the
+// Note: All TaskScheduler users should go through base/task/post_task.h instead
+// of this interface except for the one callsite per process which manages the
 // process's instance.
 class BASE_EXPORT TaskScheduler {
  public:
diff --git a/base/task/task_traits.h b/base/task/task_traits.h
index 161901d..7727365 100644
--- a/base/task/task_traits.h
+++ b/base/task/task_traits.h
@@ -113,7 +113,7 @@
 // removing usage of methods listed above in the labeled tasks would still
 // result in tasks that may block (per MayBlock()'s definition).
 //
-// In doubt, consult with //base/task_scheduler/OWNERS.
+// In doubt, consult with //base/task/OWNERS.
 struct WithBaseSyncPrimitives {};
 
 // Describes immutable metadata for a single task or a group of tasks.
diff --git a/base/task_scheduler/OWNERS b/base/task_scheduler/OWNERS
deleted file mode 100644
index 6e259974..0000000
--- a/base/task_scheduler/OWNERS
+++ /dev/null
@@ -1,10 +0,0 @@
-# TODO(gab): Remove this file from this now empty directory after
-# base/test/OWNERS is updated on the server to no longer refer to it...
-# https://crbug.com/870426
-
-fdoray@chromium.org
-gab@chromium.org
-robliao@chromium.org
-
-# TEAM: scheduler-dev@chromium.org
-# COMPONENT: Internals>TaskScheduler
diff --git a/base/values.cc b/base/values.cc
index 68d5ef2f..cab1fed 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -76,6 +76,8 @@
 
 }  // namespace
 
+constexpr uint32_t Value::kMagicIsAlive;
+
 // static
 std::unique_ptr<Value> Value::CreateWithCopiedBuffer(const char* buffer,
                                                      size_t size) {
@@ -215,6 +217,7 @@
 
 Value::~Value() {
   InternalCleanup();
+  is_alive_ = 0;
 }
 
 // static
@@ -701,6 +704,8 @@
 }
 
 void Value::InternalCleanup() {
+  CHECK_EQ(is_alive_, kMagicIsAlive);
+
   switch (type_) {
     case Type::NONE:
     case Type::BOOLEAN:
diff --git a/base/values.h b/base/values.h
index 0a6e052..0728c01 100644
--- a/base/values.h
+++ b/base/values.h
@@ -96,6 +96,10 @@
     // Note: Do not add more types. See the file-level comment above for why.
   };
 
+  // Magic IsAlive signature to debug double frees.
+  // TODO(crbug.com/859477): Remove once root cause is found.
+  static constexpr uint32_t kMagicIsAlive = 0x15272f19;
+
   // For situations where you want to keep ownership of your buffer, this
   // factory method creates a new BinaryValue by copying the contents of the
   // buffer that's passed in.
@@ -383,6 +387,10 @@
   void InternalMoveConstructFrom(Value&& that);
   void InternalCleanup();
 
+  // IsAlive member to debug double frees.
+  // TODO(crbug.com/859477): Remove once root cause is found.
+  uint32_t is_alive_ = kMagicIsAlive;
+
   DISALLOW_COPY_AND_ASSIGN(Value);
 };
 
diff --git a/build/compute_build_timestamp.py b/build/compute_build_timestamp.py
deleted file mode 100755
index 2adc2f8..0000000
--- a/build/compute_build_timestamp.py
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env python
-# 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.
-"""Returns a timestamp that approximates the build date.
-
-build_type impacts the timestamp generated:
-- default: the build date is set to the most recent first Sunday of a month at
-  5:00am. The reason is that it is a time where invalidating the build cache
-  shouldn't have major reprecussions (due to lower load).
-- official: the build date is set to the current date at 5:00am, or the day
-  before if the current time is before 5:00am.
-Either way, it is guaranteed to be in the past and always in UTC.
-"""
-
-# The requirements for the timestamp:
-# (1) for the purposes of continuous integration, longer duration
-#     between cache invalidation is better, but >=1mo is preferable.
-# (2) for security purposes, timebombs would ideally be as close to
-#     the actual time of the build as possible. It must be in the past.
-# (3) HSTS certificate pinning is valid for 70 days. To make CI builds enforce
-#     HTST pinning, <=1mo is preferable.
-#
-# On Windows, the timestamp is also written in the PE/COFF file header of
-# executables of dlls.  That timestamp and the executable's file size are
-# the only two pieces of information that identify a given executable on
-# the symbol server, so rarely changing timestamps can cause conflicts there
-# as well. We only upload symbols for official builds to the symbol server.
-
-import argparse
-import calendar
-import datetime
-import doctest
-import sys
-
-
-def GetFirstSundayOfMonth(year, month):
-  """Returns the first sunday of the given month of the given year.
-
-  >>> GetFirstSundayOfMonth(2016, 2)
-  7
-  >>> GetFirstSundayOfMonth(2016, 3)
-  6
-  >>> GetFirstSundayOfMonth(2000, 1)
-  2
-  """
-  weeks = calendar.Calendar().monthdays2calendar(year, month)
-  # Return the first day in the first week that is a Sunday.
-  return [date_day[0] for date_day in weeks[0] if date_day[1] == 6][0]
-
-
-def GetBuildDate(build_type, utc_now):
-  """Gets the approximate build date given the specific build type.
-
-  >>> GetBuildDate('default', datetime.datetime(2016, 2, 6, 1, 2, 3))
-  datetime.datetime(2016, 1, 3, 1, 2, 3)
-  >>> GetBuildDate('default', datetime.datetime(2016, 2, 7, 5))
-  datetime.datetime(2016, 2, 7, 5, 0)
-  >>> GetBuildDate('default', datetime.datetime(2016, 2, 8, 5))
-  datetime.datetime(2016, 2, 7, 5, 0)
-  >>> GetBuildDate('official', datetime.datetime(2016, 2, 8, 5))
-  datetime.datetime(2016, 2, 8, 5, 0)
-  """
-  day = utc_now.day
-  month = utc_now.month
-  year = utc_now.year
-  if build_type != 'official':
-    first_sunday = GetFirstSundayOfMonth(year, month)
-    # If our build is after the first Sunday, we've already refreshed our build
-    # cache on a quiet day, so just use that day.
-    # Otherwise, take the first Sunday of the previous month.
-    if day >= first_sunday:
-      day = first_sunday
-    else:
-      month -= 1
-      if month == 0:
-        month = 12
-        year -= 1
-      day = GetFirstSundayOfMonth(year, month)
-  return datetime.datetime(
-      year, month, day, utc_now.hour, utc_now.minute, utc_now.second)
-
-
-def main():
-  if doctest.testmod()[0]:
-    return 1
-  argument_parser = argparse.ArgumentParser()
-  argument_parser.add_argument(
-      'build_type', help='The type of build', choices=('official', 'default'))
-  args = argument_parser.parse_args()
-
-  now = datetime.datetime.utcnow()
-  if now.hour < 5:
-    # The time is locked at 5:00 am in UTC to cause the build cache
-    # invalidation to not happen exactly at midnight. Use the same calculation
-    # as the day before.
-    # See //base/build_time.cc.
-    now = now - datetime.timedelta(days=1)
-  now = datetime.datetime(now.year, now.month, now.day, 5, 0, 0)
-  build_date = GetBuildDate(args.build_type, now)
-  print int(calendar.timegm(build_date.utctimetuple()))
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 98389b6..5dcc9ef5 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -8,7 +8,6 @@
 import("//build/config/compiler/compiler.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/win/visual_studio_version.gni")
-import("//build/timestamp.gni")
 import("//build/toolchain/goma.gni")
 import("//build/toolchain/toolchain.gni")
 
@@ -107,23 +106,12 @@
     cflags += [ "/Brepro" ]
   }
 
-  ldflags = []
-
-  if (use_lld) {
-    # lld defaults to writing the current time in the pe/coff header.
-    # For build reproducibility, pass an explicit timestamp. See
-    # build/compute_build_timestamp.py for how the timestamp is chosen.
-    # (link.exe also writes the current time, but it doesn't have a flag to
-    # override that behavior.)
-    ldflags += [ "/TIMESTAMP:" + build_timestamp ]
-  }
-
   if (!is_debug && !is_component_build) {
     # Enable standard linker optimizations like GC (/OPT:REF) and ICF in static
     # release builds. These are implied by /PROFILE below, but /PROFILE is
     # incompatible with /debug:fastlink and LLD ignores it as of this writing.
     # Release builds always want these optimizations, so enable them explicitly.
-    ldflags += [
+    ldflags = [
       "/OPT:REF",
       "/OPT:ICF",
       "/INCREMENTAL:NO",
diff --git a/build/dotfile_settings.gni b/build/dotfile_settings.gni
index 4242ec6..8382c75 100644
--- a/build/dotfile_settings.gni
+++ b/build/dotfile_settings.gni
@@ -24,7 +24,6 @@
     "//build/config/sysroot.gni",
     "//build/config/win/BUILD.gn",
     "//build/config/win/visual_studio_version.gni",
-    "//build/timestamp.gni",
     "//build/toolchain/BUILD.gn",
     "//build/toolchain/concurrent_links.gni",
     "//build/toolchain/mac/BUILD.gn",
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index 73991da7..c07c9387 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-7b819cc87306ccc5c75a7c0dabfa05bc0b2862a6
\ No newline at end of file
+43e0834be00a65cd7f811ad3cb5c2528e456ec52
\ No newline at end of file
diff --git a/build/timestamp.gni b/build/timestamp.gni
deleted file mode 100644
index 90b6231..0000000
--- a/build/timestamp.gni
+++ /dev/null
@@ -1,19 +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.
-#
-# Defines the build_timestamp variable.
-
-if (is_official_build) {
-  official_name = "official"
-} else {
-  official_name = "default"
-}
-
-# This will return a timestamp that's different each day (official builds)
-# of each month (regular builds).  Just rely on gn rerunning due to other
-# changes to keep this up to date.  (Bots run gn on each build, and for devs
-# the timestamp being 100% accurate doesn't matter.)
-# See compute_build_timestamp.py for tradeoffs for picking the timestamp.
-build_timestamp =
-    exec_script("compute_build_timestamp.py", [ official_name ], "trim string")
diff --git a/build/write_build_date_header.py b/build/write_build_date_header.py
index 7738828..01c9e276 100755
--- a/build/write_build_date_header.py
+++ b/build/write_build_date_header.py
@@ -2,25 +2,98 @@
 # Copyright (c) 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.
-"""Takes a timestamp and writes it in as readable text to a .h file."""
+"""Writes a file that contains a define that approximates the build date.
+
+build_type impacts the timestamp generated:
+- default: the build date is set to the most recent first Sunday of a month at
+  5:00am. The reason is that it is a time where invalidating the build cache
+  shouldn't have major reprecussions (due to lower load).
+- official: the build date is set to the current date at 5:00am, or the day
+  before if the current time is before 5:00am.
+Either way, it is guaranteed to be in the past and always in UTC.
+
+It is also possible to explicitly set a build date to be used.
+"""
 
 import argparse
+import calendar
 import datetime
+import doctest
 import os
 import sys
 
 
+def GetFirstSundayOfMonth(year, month):
+  """Returns the first sunday of the given month of the given year.
+
+  >>> GetFirstSundayOfMonth(2016, 2)
+  7
+  >>> GetFirstSundayOfMonth(2016, 3)
+  6
+  >>> GetFirstSundayOfMonth(2000, 1)
+  2
+  """
+  weeks = calendar.Calendar().monthdays2calendar(year, month)
+  # Return the first day in the first week that is a Sunday.
+  return [date_day[0] for date_day in weeks[0] if date_day[1] == 6][0]
+
+
+def GetBuildDate(build_type, utc_now):
+  """Gets the approximate build date given the specific build type.
+
+  >>> GetBuildDate('default', datetime.datetime(2016, 2, 6, 1, 2, 3))
+  'Jan 03 2016 01:02:03'
+  >>> GetBuildDate('default', datetime.datetime(2016, 2, 7, 5))
+  'Feb 07 2016 05:00:00'
+  >>> GetBuildDate('default', datetime.datetime(2016, 2, 8, 5))
+  'Feb 07 2016 05:00:00'
+  """
+  day = utc_now.day
+  month = utc_now.month
+  year = utc_now.year
+  if build_type != 'official':
+    first_sunday = GetFirstSundayOfMonth(year, month)
+    # If our build is after the first Sunday, we've already refreshed our build
+    # cache on a quiet day, so just use that day.
+    # Otherwise, take the first Sunday of the previous month.
+    if day >= first_sunday:
+      day = first_sunday
+    else:
+      month -= 1
+      if month == 0:
+        month = 12
+        year -= 1
+      day = GetFirstSundayOfMonth(year, month)
+  now = datetime.datetime(
+      year, month, day, utc_now.hour, utc_now.minute, utc_now.second)
+  return '{:%b %d %Y %H:%M:%S}'.format(now)
+
+
 def main():
-  argument_parser = argparse.ArgumentParser()
+  if doctest.testmod()[0]:
+    return 1
+  argument_parser = argparse.ArgumentParser(
+      description=sys.modules[__name__].__doc__,
+      formatter_class=argparse.RawDescriptionHelpFormatter)
   argument_parser.add_argument('output_file', help='The file to write to')
-  argument_parser.add_argument('timestamp')
+  argument_parser.add_argument(
+      'build_type', help='The type of build', choices=('official', 'default'))
   args = argument_parser.parse_args()
 
-  date = datetime.datetime.utcfromtimestamp(int(args.timestamp))
+  now = datetime.datetime.utcnow()
+  if now.hour < 5:
+    # The time is locked at 5:00 am in UTC to cause the build cache
+    # invalidation to not happen exactly at midnight. Use the same calculation
+    # as the day before.
+    # See //base/build_time.cc.
+    now = now - datetime.timedelta(days=1)
+  now = datetime.datetime(now.year, now.month, now.day, 5, 0, 0)
+  build_date = GetBuildDate(args.build_type, now)
+
   output = ('// Generated by //build/write_build_date_header.py\n'
            '#ifndef BUILD_DATE\n'
-           '#define BUILD_DATE "{:%b %d %Y %H:%M:%S}"\n'
-           '#endif // BUILD_DATE\n'.format(date))
+           '#define BUILD_DATE "{}"\n'
+           '#endif // BUILD_DATE\n'.format(build_date))
 
   current_contents = ''
   if os.path.isfile(args.output_file):
diff --git a/build_overrides/spirv_tools.gni b/build_overrides/spirv_tools.gni
new file mode 100644
index 0000000..cc7e7d1
--- /dev/null
+++ b/build_overrides/spirv_tools.gni
@@ -0,0 +1,10 @@
+# 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.
+
+# We are building inside Chromium
+spirv_tools_standalone = false
+
+# Paths to SPIRV-Tools dependencies in Chromium
+spirv_tools_googletest_dir = "//third_party/googletest/src"
+spirv_tools_spirv_headers_dir = "//third_party/spirv-headers/src"
diff --git a/cc/paint/paint_op_buffer_eq_fuzzer.cc b/cc/paint/paint_op_buffer_eq_fuzzer.cc
index 553136d..081744b 100644
--- a/cc/paint/paint_op_buffer_eq_fuzzer.cc
+++ b/cc/paint/paint_op_buffer_eq_fuzzer.cc
@@ -21,18 +21,19 @@
 //
 // serialized1 -> deserialized1 -> serialized2 -> deserialized2 -> serialized3
 //
-// It does a binary comparison that serialized2 == serialized3
 // Ideally this test would compare serialized1 to serialized2, however:
 // (1) Deserializing is a destructive process on bad input, e.g. SkMatrix
 //     that says it is identity will be clobbered to have identity values.
 // (2) Padding for alignment is skipped and so serialized1 may have garbage.
 //     serialized2 and serialized3 are cleared to zero first.
+// (3) Any internal allocated memory (e.g. DrawRecord ops) also will not
+//     be initialized to zero, and some ops memcpy when serializing or
+//     deserializing, and may copy some of this garbage.
 //
-// Binary comparing serialized2 to serialized3 is not identical to comparing
-// serialized1 to serialized2, as this could overlook some bugs that clobbered
-// object state to something that serialized cleanly at that point.
-// To mitigate those errors, this test also compares the logical equality
-// deserialized1 and deserialized2 using PaintOp::operator==.
+// It'd be nice to be able to binary compare, but because of all the above
+// reasons, this is impossible to do for all ops, so this test only does
+// a logical comparison of deserialized1 and deserialized2, and verifies
+// that serialized2 and serialized3 wrote the exact same number of bytes.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   const size_t kMaxSerializedSize = 1000000;
 
@@ -115,7 +116,6 @@
   CHECK(*deserialized_op1 == *deserialized_op2)
       << "\n1: " << cc::PaintOpHelper::ToString(deserialized_op1)
       << "\n2: " << cc::PaintOpHelper::ToString(deserialized_op2);
-  CHECK_EQ(0, memcmp(serialized2.get(), serialized3.get(), written_bytes2));
 
   deserialized_op1->DestroyThis();
   deserialized_op2->DestroyThis();
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index a47af42a..9a0d4e5a3 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -232,6 +232,7 @@
           "/DELAYLOAD:uxtheme.dll",
           "/DELAYLOAD:ole32.dll",
           "/DELAYLOAD:oleaut32.dll",
+          "/DELAYLOAD:winhttp.dll",
         ]
 
         if (current_cpu == "x64") {
diff --git a/chrome/VERSION b/chrome/VERSION
index 04c5e8f..327b3b4 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=70
 MINOR=0
-BUILD=3516
+BUILD=3517
 PATCH=0
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
index 8afcc4c..2272e0b9 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
@@ -22,6 +22,7 @@
 import com.google.android.libraries.feed.host.stream.StreamConfiguration;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.NativePageHost;
@@ -256,4 +257,20 @@
     public void setTouchEnabled(boolean enabled) {
         // TODO(twellington): implement this method.
     }
+
+    /**
+     * Configures the {@link FeedNewTabPage} for testing.
+     * @param inTestMode Whether test mode is enabled. If true, test implementations of Feed
+     *                   interfaces will be used to create the {@link FeedProcessScope}. If false,
+     *                   the FeedProcessScope will be reset.
+     */
+    @VisibleForTesting
+    public static void setInTestMode(boolean inTestMode) {
+        if (inTestMode) {
+            FeedProcessScopeFactory.createFeedProcessScopeForTesting(
+                    new TestFeedScheduler(), new TestNetworkClient());
+        } else {
+            FeedProcessScopeFactory.clearFeedProcessScopeForTesting();
+        }
+    }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
index 3312351..e430686 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java
@@ -10,8 +10,10 @@
 import com.google.android.libraries.feed.host.config.Configuration;
 import com.google.android.libraries.feed.host.config.Configuration.ConfigKey;
 import com.google.android.libraries.feed.host.config.DebugBehavior;
+import com.google.android.libraries.feed.host.network.NetworkClient;
 import com.google.android.libraries.feed.hostimpl.logging.LoggingApiImpl;
 
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.profiles.Profile;
 
 import java.util.concurrent.Executors;
@@ -21,7 +23,7 @@
  */
 public class FeedProcessScopeFactory {
     private static FeedProcessScope sFeedProcessScope;
-    private static FeedSchedulerBridge sFeedSchedulerBridge;
+    private static FeedScheduler sFeedScheduler;
 
     /**
      * @return The shared {@link FeedProcessScope} instance.
@@ -36,33 +38,71 @@
     /**
      * @return The {@link FeedSchedulerBridge} that was given to the {@link FeedProcessScope}.
      */
-    public static FeedSchedulerBridge getFeedSchedulerBridge() {
-        if (sFeedSchedulerBridge == null) {
+    public static FeedScheduler getFeedSchedulerBridge() {
+        if (sFeedScheduler == null) {
             initialize();
         }
-        return sFeedSchedulerBridge;
+        return sFeedScheduler;
     }
 
     private static void initialize() {
-        assert sFeedSchedulerBridge == null && sFeedProcessScope == null;
+        assert sFeedScheduler == null && sFeedProcessScope == null;
         Profile profile = Profile.getLastUsedProfile().getOriginalProfile();
-        Configuration configHostApi =
-                new Configuration.Builder()
-                        .put(ConfigKey.FEED_SERVER_HOST, "https://www.google.com")
-                        .put(ConfigKey.FEED_SERVER_PATH_AND_PARAMS,
-                                "/httpservice/noretry/NowStreamService/FeedQuery")
-                        .put(ConfigKey.SESSION_LIFETIME_MS, 300000L)
-                        .build();
-        sFeedSchedulerBridge = new FeedSchedulerBridge(profile);
+        Configuration configHostApi = createConfiguration();
+
+        FeedSchedulerBridge schedulerBridge = new FeedSchedulerBridge(profile);
+        sFeedScheduler = schedulerBridge;
         FeedAppLifecycleListener lifecycleListener =
                 new FeedAppLifecycleListener(new ThreadUtils());
         sFeedProcessScope =
                 new FeedProcessScope
                         .Builder(configHostApi, Executors.newSingleThreadExecutor(),
                                 new LoggingApiImpl(), new FeedNetworkBridge(profile),
-                                sFeedSchedulerBridge, lifecycleListener, DebugBehavior.SILENT)
+                                schedulerBridge, lifecycleListener, DebugBehavior.SILENT)
                         .build();
-        sFeedSchedulerBridge.initializeFeedDependencies(
+        schedulerBridge.initializeFeedDependencies(
                 sFeedProcessScope.getRequestManager(), sFeedProcessScope.getSessionManager());
     }
+
+    private static Configuration createConfiguration() {
+        return new Configuration.Builder()
+                .put(ConfigKey.FEED_SERVER_HOST, "https://www.google.com")
+                .put(ConfigKey.FEED_SERVER_PATH_AND_PARAMS,
+                        "/httpservice/noretry/NowStreamService/FeedQuery")
+                .put(ConfigKey.SESSION_LIFETIME_MS, 300000L)
+                .build();
+    }
+
+    /**
+     * Creates a {@link FeedProcessScope} using the provided {@link FeedScheduler} and
+     * {@link NetworkClient}. Call {@link #clearFeedProcessScopeForTesting()} to reset the
+     * FeedProcessScope after testing is complete.
+     *
+     * @param feedScheduler A {@link FeedScheduler} to use for testing.
+     * @param networkClient A {@link NetworkClient} to use for testing.
+     */
+    @VisibleForTesting
+    static void createFeedProcessScopeForTesting(
+            FeedScheduler feedScheduler, NetworkClient networkClient) {
+        Configuration configHostApi = createConfiguration();
+        FeedAppLifecycleListener lifecycleListener =
+                new FeedAppLifecycleListener(new ThreadUtils());
+        sFeedScheduler = feedScheduler;
+        sFeedProcessScope = new FeedProcessScope
+                                    .Builder(configHostApi, Executors.newSingleThreadExecutor(),
+                                            new LoggingApiImpl(), networkClient, sFeedScheduler,
+                                            lifecycleListener, DebugBehavior.SILENT)
+                                    .build();
+    }
+
+    /** Resets the FeedProcessScope after testing is complete. */
+    @VisibleForTesting
+    static void clearFeedProcessScopeForTesting() {
+        if (sFeedScheduler != null) {
+            sFeedScheduler.destroy();
+            sFeedScheduler = null;
+        }
+
+        sFeedProcessScope = null;
+    }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java
new file mode 100644
index 0000000..9ec5062
--- /dev/null
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.feed;
+
+import com.google.android.libraries.feed.host.scheduler.SchedulerApi;
+
+/**
+ * An extension of the {@link SchedulerApi} with additional methods needed for scheduling logic
+ * in Chromium.
+ */
+public interface FeedScheduler extends SchedulerApi {
+    void destroy();
+
+    void onForegrounded();
+
+    void onFixedTimer(Runnable onCompletion);
+
+    void onTaskReschedule();
+
+    void onSuggestionConsumed();
+}
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java
index 15eda549..9981dd59 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java
@@ -22,7 +22,7 @@
  * Provides access to native implementations of SchedulerApi.
  */
 @JNINamespace("feed")
-public class FeedSchedulerBridge implements SchedulerApi {
+public class FeedSchedulerBridge implements FeedScheduler {
     private long mNativeBridge;
     private RequestManager mRequestManager;
     private SessionManager mSessionManager;
@@ -37,6 +37,7 @@
     }
 
     /** Cleans up the native half of this bridge. */
+    @Override
     public void destroy() {
         assert mNativeBridge != 0;
         nativeDestroy(mNativeBridge);
@@ -103,22 +104,26 @@
         nativeOnRequestError(mNativeBridge, networkResponseCode);
     }
 
+    @Override
     public void onForegrounded() {
         assert mNativeBridge != 0;
         nativeOnForegrounded(mNativeBridge);
     }
 
+    @Override
     public void onFixedTimer(Runnable onCompletion) {
         assert mNativeBridge != 0;
         // Convert to single argument Callback to make invoking from native more convenient.
         nativeOnFixedTimer(mNativeBridge, (Void ignored) -> onCompletion.run());
     }
 
+    @Override
     public void onTaskReschedule() {
         assert mNativeBridge != 0;
         nativeOnTaskReschedule(mNativeBridge);
     }
 
+    @Override
     public void onSuggestionConsumed() {
         assert mNativeBridge != 0;
         nativeOnSuggestionConsumed(mNativeBridge);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestFeedScheduler.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestFeedScheduler.java
new file mode 100644
index 0000000..2fab4a0
--- /dev/null
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestFeedScheduler.java
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.feed;
+
+import com.google.android.libraries.feed.host.scheduler.SchedulerApi;
+
+/** A {@link FeedScheduler} implementation for use in testing. */
+class TestFeedScheduler implements FeedScheduler {
+    @Override
+    public void destroy() {}
+
+    @Override
+    public void onForegrounded() {}
+
+    @Override
+    public void onFixedTimer(Runnable onCompletion) {}
+
+    @Override
+    public void onTaskReschedule() {}
+
+    @Override
+    public void onSuggestionConsumed() {}
+
+    @Override
+    public int shouldSessionRequestData(SessionManagerState sessionManagerState) {
+        return SchedulerApi.RequestBehavior.NO_REQUEST_WITH_CONTENT;
+    }
+
+    @Override
+    public void onReceiveNewContent(long contentCreationDateTimeMs) {}
+
+    @Override
+    public void onRequestError(int networkResponseCode) {}
+}
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java
new file mode 100644
index 0000000..ca313c2
--- /dev/null
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.feed;
+
+import com.google.android.libraries.feed.common.functional.Consumer;
+import com.google.android.libraries.feed.host.network.HttpRequest;
+import com.google.android.libraries.feed.host.network.HttpResponse;
+import com.google.android.libraries.feed.host.network.NetworkClient;
+
+/** A {@link NetworkClient} implementation for use in testing. */
+class TestNetworkClient implements NetworkClient {
+    @Override
+    public void send(HttpRequest request, Consumer<HttpResponse> responseConsumer) {}
+
+    @Override
+    public void close() throws Exception {}
+}
diff --git a/chrome/android/feed/dummy/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java b/chrome/android/feed/dummy/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
index c7b0506..1fdf5b39 100644
--- a/chrome/android/feed/dummy/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
+++ b/chrome/android/feed/dummy/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
@@ -23,4 +23,12 @@
             TabModelSelector tabModelSelector) {
         super(activity, nativePageHost, tabModelSelector);
     }
+
+    /**
+     * Configures the FeedNewTabPage for testing.
+     * @param inTestMode Whether test mode is enabled. If true, test implementations of Feed
+     *                   interfaces will be used to create the {@link FeedProcessScope}. If false,
+     *                   the FeedProcessScope will be reset.
+     */
+    public static void setInTestMode(boolean inTestMode) {}
 }
diff --git a/chrome/android/feed/feed_java_sources.gni b/chrome/android/feed/feed_java_sources.gni
index 3ed1ef5a..e4cecd3 100644
--- a/chrome/android/feed/feed_java_sources.gni
+++ b/chrome/android/feed/feed_java_sources.gni
@@ -19,9 +19,12 @@
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPageMediator.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedProcessScopeFactory.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedRefreshTask.java",
+    "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedScheduler.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSchedulerBridge.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedStorageBridge.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/StreamLifecycleManager.java",
+    "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestFeedScheduler.java",
+    "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/TestNetworkClient.java",
     "//chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/action/FeedActionHandler.java",
   ]
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 0c237131..3cf429e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -943,6 +943,8 @@
         VrModuleProvider.getDelegate().maybeRegisterVrEntryHook(this);
 
         OfflineIndicatorController.onUpdate();
+
+        if (getManualFillingController() != null) getManualFillingController().onResume();
     }
 
     @Override
@@ -960,6 +962,7 @@
         RecordUserAction.record("MobileGoToBackground");
         Tab tab = getActivityTab();
         if (tab != null) getTabContentManager().cacheTabThumbnail(tab);
+        if (getManualFillingController() != null) getManualFillingController().onPause();
 
         VrModuleProvider.getDelegate().maybeUnregisterVrEntryHook();
         markSessionEnd();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
index 9cc9297..d80708b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
@@ -52,11 +52,6 @@
         void onCloseAccessorySheet();
 
         /**
-         * Called when the whole accessory should be hidden (e.g. due to selecting a suggestion).
-         */
-        void onCloseKeyboardAccessory();
-
-        /**
          * Called when the normal keyboard should be brought back (e.g. the user dismissed a bottom
          * sheet manually because they didn't find a suitable suggestion).
          */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
index b61eeac..c5e84e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
@@ -112,6 +112,7 @@
     public void bind(
             KeyboardAccessoryModel model, KeyboardAccessoryView view, PropertyKey propertyKey) {
         if (propertyKey == PropertyKey.VISIBLE) {
+            view.setActiveTabColor(model.activeTab());
             view.setVisible(model.isVisible());
             return;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
index 247cf55f..0a6cd10 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
@@ -82,6 +82,14 @@
         mMediator.registerPasswordProvider(itemProvider);
     }
 
+    public void onResume() {
+        mMediator.resume();
+    }
+
+    public void onPause() {
+        mMediator.pause();
+    }
+
     // TODO(fhorschig): Should be @VisibleForTesting.
     /**
      * Allows access to the keyboard accessory. This can be used to explicitly modify the the bar of
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
index c33cef38..86a06c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
@@ -37,7 +37,8 @@
      * observers.
      * @param <T> The data that is sent to observers.
      */
-    private class ProviderCacheAdapter<T> extends KeyboardAccessoryData.PropertyProvider<T>
+    @VisibleForTesting
+    protected class ProviderCacheAdapter<T> extends KeyboardAccessoryData.PropertyProvider<T>
             implements KeyboardAccessoryData.Observer<T> {
         private final Tab mTab;
         private T[] mLastItems;
@@ -99,31 +100,25 @@
         @Override
         public void onSceneChange(Layout layout) {
             // Includes events like side-swiping between tabs and triggering contextual search.
-            mAccessorySheet.hide();
+            mKeyboardAccessory.dismiss();
         }
     };
 
     private final TabObserver mTabObserver = new EmptyTabObserver() {
         @Override
         public void onHidden(Tab tab) {
-            // TODO(fhorschig): Test that the accessory is reset and close if a tab changes.
-            // TODO(fhorschig): Test that this hides everything.
-            mAccessorySheet.hide();
-            resetAccessory();
+            mKeyboardAccessory.dismiss();
         }
 
         @Override
         public void onDestroyed(Tab tab) {
-            // TODO(fhorschig): Test that this hides everything.
-            mAccessorySheet.hide();
-            resetAccessory();
             mModel.remove(tab); // Clears tab if still present.
+            restoreCachedState(mActiveBrowserTab);
         }
 
         @Override
         public void onEnterFullscreenMode(Tab tab, FullscreenOptions options) {
-            // TODO(fhorschig): Test that this hides everything.
-            mAccessorySheet.hide();
+            mKeyboardAccessory.dismiss();
         }
     };
 
@@ -148,9 +143,8 @@
 
             @Override
             public void willCloseTab(Tab tab, boolean animate) {
-                mAccessorySheet.hide();
-                resetAccessory();
                 mModel.remove(tab);
+                restoreCachedState(mActiveBrowserTab);
             }
         };
         Tab currentTab = activity.getTabModelSelector().getCurrentTab();
@@ -173,7 +167,6 @@
     }
 
     void destroy() {
-        // TODO(fhorschig): Remove all tabs. Remove observers from tabs. Destroy all providers.
         mTabModelObserver.destroy();
         mKeyboardAccessory.destroy();
     }
@@ -190,6 +183,14 @@
         mPopup = popup;
     }
 
+    public void pause() {
+        mKeyboardAccessory.dismiss();
+    }
+
+    void resume() {
+        restoreCachedState(mActiveBrowserTab);
+    }
+
     @Override
     public void onChangeAccessorySheet(int tabIndex) {
         mAccessorySheet.setActiveTab(tabIndex);
@@ -211,13 +212,6 @@
     }
 
     @Override
-    public void onCloseKeyboardAccessory() {
-        assert mActivity != null : "ManualFillingMediator needs initialization.";
-        mAccessorySheet.hide();
-        UiUtils.hideKeyboard(mActivity.getCurrentFocus());
-    }
-
-    @Override
     public void onOpenKeyboard() {
         assert mActivity != null : "ManualFillingMediator needs initialization.";
         UiUtils.showKeyboard(mActivity.getCurrentFocus());
@@ -233,21 +227,18 @@
     }
 
     private void restoreCachedState(Tab browserTab) {
+        mKeyboardAccessory.dismiss();
+        clearTabs();
         AccessoryState state = getOrCreateAccessoryState(browserTab);
-        resetAccessory();
         if (state.mPasswordAccessorySheet != null) {
             addTab(state.mPasswordAccessorySheet.getTab());
         }
         if (state.mActionsProvider != null) state.mActionsProvider.notifyAboutCachedItems();
     }
 
-    private void resetAccessory() {
-        setTabs(new KeyboardAccessoryData.Tab[0]);
-    }
-
-    private void setTabs(KeyboardAccessoryData.Tab[] tabs) {
-        mKeyboardAccessory.setTabs(tabs);
-        mAccessorySheet.setTabs(tabs);
+    private void clearTabs() {
+        mKeyboardAccessory.setTabs(new KeyboardAccessoryData.Tab[0]);
+        mAccessorySheet.setTabs(new KeyboardAccessoryData.Tab[0]);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/VerificationState.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/VerificationState.java
new file mode 100644
index 0000000..80c99058
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/VerificationState.java
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+package org.chromium.chrome.browser.browserservices;
+
+import android.support.customtabs.CustomTabsService;
+
+import org.chromium.base.Callback;
+import org.chromium.base.Promise;
+
+/**
+ * Kicks off Digital Asset Link verification and remembers the result.
+ */
+public class VerificationState {
+    private final Promise<Boolean> mVerification = new Promise<>();
+
+    /**
+     * Verify the Digital Asset Links declared by the Android native client with the currently
+     * loading origin. See {@link #didVerificationFail()} for the result.
+     */
+    public VerificationState(String packageName, Origin origin, Callback<Boolean> onResult) {
+        mVerification.then(onResult);
+
+        new OriginVerifier(
+                (packageName2, origin2, verified, online) -> mVerification.fulfill(verified),
+                packageName, CustomTabsService.RELATION_HANDLE_ALL_URLS).start(origin);
+    }
+
+    /**
+     * @return Whether origin verification for the corresponding client failed. If verification is
+     * not complete, this will return false.
+     */
+    public boolean didVerificationFail() {
+        return mVerification.isFulfilled() && !mVerification.getResult();
+    }
+}
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 32bc7be..955f2e5f 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
@@ -17,6 +17,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.StrictMode;
+import android.os.SystemClock;
 import android.provider.Browser;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
@@ -375,6 +376,11 @@
         mBottomBarDelegate.setBottomBarHeight(height);
     }
 
+    public void loadUri(Uri uri) {
+        assert mMainTab != null;
+        loadUrlInTab(mMainTab, new LoadUrlParams(uri.toString()), SystemClock.elapsedRealtime());
+    }
+
     @Override
     public boolean shouldAllocateChildConnection() {
         return !mHasCreatedTabEarly && !mHasSpeculated
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 3fd95621..f269d251 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -226,8 +226,9 @@
 
         mTitleVisibilityState = IntentUtils.safeGetIntExtra(
                 intent, CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE, CustomTabsIntent.NO_TITLE);
-        mShowShareItem = IntentUtils.safeGetBooleanExtra(
-                intent, CustomTabsIntent.EXTRA_DEFAULT_SHARE_MENU_ITEM, false);
+        mShowShareItem = IntentUtils.safeGetBooleanExtra(intent,
+                CustomTabsIntent.EXTRA_DEFAULT_SHARE_MENU_ITEM,
+                mIsOpenedByChrome && mUiType == CustomTabsUiType.DEFAULT);
         mRemoteViews =
                 IntentUtils.safeGetParcelableExtra(intent, CustomTabsIntent.EXTRA_REMOTEVIEWS);
         mClickableViewIds = IntentUtils.safeGetIntArrayExtra(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
index 26f2c9f6..0aec1d92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs.dynamicmodule;
 
+import android.net.Uri;
 import android.view.View;
 
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
@@ -37,4 +38,9 @@
     public void setBottomBarHeight(int height) {
         mActivity.setBottomBarHeight(height);
     }
+
+    @Override
+    public void loadUri(Uri uri) {
+        mActivity.loadUri(uri);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl
index 17a8f35..4a69b0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs.dynamicmodule;
 
+import android.net.Uri;
 import org.chromium.chrome.browser.customtabs.dynamicmodule.IObjectWrapper;
 
 interface IActivityHost {
@@ -14,4 +15,12 @@
   void setOverlayView(in IObjectWrapper /* View */ overlayView) = 2;
 
   void setBottomBarHeight(int height) = 3;
+
+  /**
+   * Loads a URI in the existing CCT activity. This is used by features that
+   * want to show web content (e.g. saves when reopening a saved page).
+   *
+   * Introduced in API version 3.
+   */
+  void loadUri(in Uri uri) = 4;
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java
index 93eab9f..93b081b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java
@@ -17,11 +17,13 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.util.FeatureUtilities;
+import org.chromium.content_public.browser.BrowserStartupController;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.AndroidPermissionDelegate;
 import org.chromium.ui.base.PermissionCallback;
@@ -252,6 +254,10 @@
      */
     @CalledByNative
     private static void onDownloadStarted() {
+        if (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .isStartupSuccessfullyCompleted()) {
+            return;
+        }
         if (FeatureUtilities.isDownloadProgressInfoBarEnabled()) return;
         DownloadUtils.showDownloadStartToast(ContextUtils.getApplicationContext());
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index a9d3e82..5e4b1e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -1113,7 +1113,9 @@
      */
     private long getNativeDownloadManagerService() {
         if (mNativeDownloadManagerService == 0) {
-            mNativeDownloadManagerService = nativeInit();
+            mNativeDownloadManagerService =
+                    nativeInit(BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                                       .isStartupSuccessfullyCompleted());
         }
         return mNativeDownloadManagerService;
     }
@@ -1887,7 +1889,7 @@
     private static native boolean nativeIsSupportedMimeType(String mimeType);
     private static native int nativeGetAutoResumptionLimit();
 
-    private native long nativeInit();
+    private native long nativeInit(boolean isFullBrowserStarted);
     private native void nativeOpenDownload(long nativeDownloadManagerService, String downloadGuid,
             boolean isOffTheRecord, int source);
     private native void nativeResumeDownload(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java
index 28e34f8e..ece2b23 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java
@@ -14,10 +14,13 @@
 import org.chromium.chrome.browser.download.DownloadManagerService;
 import org.chromium.chrome.browser.download.DownloadManagerService.DownloadObserver;
 import org.chromium.chrome.browser.download.DownloadMetrics;
+import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
+import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.io.File;
@@ -150,6 +153,13 @@
         new Handler().post(() -> callback.onVisualsAvailable(id, null));
     }
 
+    /** @see OfflineContentProvider#getShareInfoForItem(ContentId, ShareCallback) */
+    public void getShareInfoForItem(OfflineItem item, ShareCallback callback) {
+        OfflineItemShareInfo info = new OfflineItemShareInfo();
+        info.uri = DownloadUtils.getUriForItem(new File(item.filePath));
+        new Handler().post(() -> callback.onShareInfoAvailable(item.id, info));
+    }
+
     /**
      * There could be some situations where we can't visually represent this download in the UI.
      * This should be handled in native/be more generic, but it's here in the glue for now.
@@ -160,4 +170,4 @@
         if (TextUtils.isEmpty(item.getDownloadInfo().getFileName())) return false;
         return true;
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
index 66e3172..a465f40c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
@@ -11,6 +11,7 @@
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.util.ArrayList;
@@ -133,6 +134,15 @@
         provider.removeThumbnailsFromDisk(id.id);
     }
 
+    /** @see OfflineContentProvider#getShareInfoForItem(ContentId, ShareCallback) */
+    public void getShareInfoForItem(OfflineItem item, ShareCallback callback) {
+        if (LegacyHelpers.isLegacyDownload(item.id)) {
+            mDownloadProvider.getShareInfoForItem(item, callback);
+        } else {
+            mProvider.getShareInfoForItem(item.id, callback);
+        }
+    }
+
     /** @see OfflineContentProvider#addObserver(OfflineContentProvider.Observer) */
     public void addObserver(OfflineContentProvider.Observer observer) {
         mObservers.addObserver(observer);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java
index 903f7c31..4e4b8991 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java
@@ -71,8 +71,8 @@
         ListItemModel model = new ListItemModel();
         DecoratedListItemModel decoratedModel = new DecoratedListItemModel(model);
         mView = new DateOrderedListView(context, decoratedModel);
-        mMediator = new DateOrderedListMediator(
-                offTheRecord, provider, deleteController, selectionDelegate, model);
+        mMediator = new DateOrderedListMediator(offTheRecord, provider, context::startActivity,
+                deleteController, selectionDelegate, model);
 
         mEmptyCoordinator =
                 new EmptyCoordinator(context, prefetchProvider, mMediator.getEmptySource());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
index 177c5f5..2339cd4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -4,7 +4,9 @@
 
 package org.chromium.chrome.browser.download.home.list;
 
+import android.content.Intent;
 import android.os.Handler;
+import android.support.v4.util.Pair;
 
 import org.chromium.base.CollectionUtil;
 import org.chromium.base.ContextUtils;
@@ -25,6 +27,7 @@
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.io.Closeable;
@@ -37,9 +40,20 @@
  * home.  This includes support for filtering, deleting, etc..
  */
 class DateOrderedListMediator {
+    /** Helper interface for handling share requests by the UI. */
+    @FunctionalInterface
+    public interface ShareController {
+        /**
+         * Will be called whenever {@link OfflineItem}s are being requested to be shared by the UI.
+         * @param intent The {@link Intent} representing the share action to broadcast to Android.
+         */
+        void share(Intent intent);
+    }
+
     private final Handler mHandler = new Handler();
 
     private final OfflineContentProviderGlue mProvider;
+    private final ShareController mShareController;
     private final ListItemModel mModel;
     private final DeleteController mDeleteController;
 
@@ -86,11 +100,12 @@
      * @param offTheRecord     Whether or not to include off the record items.
      * @param provider         The {@link OfflineContentProvider} to visually represent.
      * @param deleteController A class to manage whether or not items can be deleted.
+     * @param shareController  A class responsible for sharing downloaded item {@link Intent}s.
      * @param model            The {@link ListItemModel} to push {@code provider} into.
      */
     public DateOrderedListMediator(boolean offTheRecord, OfflineContentProvider provider,
-            DeleteController deleteController, SelectionDelegate<ListItem> selectionDelegate,
-            ListItemModel model) {
+            ShareController shareController, DeleteController deleteController,
+            SelectionDelegate<ListItem> selectionDelegate, ListItemModel model) {
         // Build a chain from the data source to the model.  The chain will look like:
         // [OfflineContentProvider] ->
         //     [OfflineItemSource] ->
@@ -102,6 +117,7 @@
         //                             [ListItemModel]
 
         mProvider = new OfflineContentProviderGlue(provider, offTheRecord);
+        mShareController = shareController;
         mModel = model;
         mDeleteController = deleteController;
 
@@ -122,7 +138,7 @@
         mModel.getProperties().setValue(
                 ListProperties.CALLBACK_RESUME, item -> mProvider.resumeDownload(item, true));
         mModel.getProperties().setValue(ListProperties.CALLBACK_CANCEL, mProvider::cancelDownload);
-        mModel.getProperties().setValue(ListProperties.CALLBACK_SHARE, item -> {});
+        mModel.getProperties().setValue(ListProperties.CALLBACK_SHARE, this ::onShareItem);
         mModel.getProperties().setValue(ListProperties.CALLBACK_REMOVE, this ::onDeleteItem);
         mModel.getProperties().setValue(ListProperties.PROVIDER_VISUALS, this ::getVisuals);
         mModel.getProperties().setValue(
@@ -203,6 +219,26 @@
         });
     }
 
+    private void onShareItem(OfflineItem item) {
+        onShareItems(CollectionUtil.newHashSet(item));
+    }
+
+    private void onShareItems(Collection<OfflineItem> items) {
+        final Collection<Pair<OfflineItem, OfflineItemShareInfo>> shareInfo = new ArrayList<>();
+
+        for (OfflineItem item : items) {
+            mProvider.getShareInfoForItem(item, (id, info) -> {
+                shareInfo.add(Pair.create(item, info));
+
+                // When we've gotten callbacks for all items, create and share the intent.
+                if (shareInfo.size() == items.size()) {
+                    Intent intent = ShareUtils.createIntent(shareInfo);
+                    if (intent != null) mShareController.share(intent);
+                }
+            });
+        }
+    }
+
     private Runnable getVisuals(
             OfflineItem item, int iconWidthPx, int iconHeightPx, VisualsCallback callback) {
         if (!UiUtils.canHaveThumbnails(item)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ShareUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ShareUtils.java
new file mode 100644
index 0000000..162b8af4d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ShareUtils.java
@@ -0,0 +1,106 @@
+// 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.
+
+package org.chromium.chrome.browser.download.home.list;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.util.Pair;
+import android.text.TextUtils;
+
+import org.chromium.base.CollectionUtil;
+import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Helper class containing utility methods to make sharing {@link OfflineItem}s easier. */
+public class ShareUtils {
+    private static final String DEFAULT_MIME_TYPE = "*/*";
+    private static final String MIME_TYPE_DELIMITER = "/";
+
+    private ShareUtils() {}
+
+    /**
+     * Creates an {@link Intent} that represents
+     * @param items A {@link Collection} of pairs of {@link OfflineItem}s and
+     *              {@link OfflineItemShareInfo}s.  The {@link OfflineItemShareInfo} contains extra
+     *              information about the specific {@link OfflineItem} required to properly build
+     *              the share {@link Intent}.
+     * @return      An {@link Intent} that can be sent through the Android framework that will share
+     *              {@code items} properly.  This might include specific {@link URI}s or it might
+     *              include text URLs depending on whether or not the item can be exposed and shared
+     *              directly.
+     * @see         OfflineContentProvider#getShareInfoForItem(ContentId, ShareCallback)
+     */
+    public static Intent createIntent(Collection<Pair<OfflineItem, OfflineItemShareInfo>> items) {
+        ArrayList<Uri> uris = new ArrayList<>();
+        Set<String> mimeTypes = new HashSet<>();
+        StringBuilder urls = new StringBuilder();
+
+        for (Pair<OfflineItem, OfflineItemShareInfo> item : items) {
+            mimeTypes.add(Intent.normalizeMimeType(item.first.mimeType));
+
+            Uri uri = item.second == null ? null : item.second.uri;
+            if (uri != null && uri.compareTo(Uri.EMPTY) != 0) {
+                uris.add(uri);
+            } else if (!TextUtils.isEmpty(item.first.pageUrl)) {
+                if (urls.length() > 0) urls.append("\n");
+                urls.append(item.first.pageUrl);
+            }
+        }
+
+        // If we have nothing to share, don't create the intent.  We should theoretically always
+        // have the pageURL, but this is a safety precaution.  In the future we could just use the
+        // title instead of the URL if the URL doesn't exist.
+        if (uris.isEmpty() && urls.length() == 0) return null;
+
+        boolean sendingText = urls.length() > 0;
+        boolean singleItem = ((sendingText ? 1 : 0) + uris.size()) == 1;
+
+        Intent intent = new Intent();
+
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setType(Intent.normalizeMimeType(resolveMimeType(mimeTypes)));
+        intent.setAction(singleItem ? Intent.ACTION_SEND : Intent.ACTION_SEND_MULTIPLE);
+
+        if (sendingText) intent.putExtra(Intent.EXTRA_TEXT, urls.toString());
+
+        if (items.size() == 1) {
+            intent.putExtra(Intent.EXTRA_SUBJECT, items.iterator().next().first.title);
+        }
+
+        if (uris.size() == 1) {
+            intent.putExtra(Intent.EXTRA_STREAM, uris.get(0));
+        } else if (uris.size() > 1) {
+            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+        }
+
+        return intent;
+    }
+
+    private static String resolveMimeType(Collection<String> mimeTypes) {
+        if (mimeTypes.isEmpty()) return DEFAULT_MIME_TYPE;
+        if (mimeTypes.size() == 1) return mimeTypes.iterator().next();
+
+        Set<String> firstParts = new HashSet<>();
+        Set<String> secondParts = new HashSet<>();
+
+        CollectionUtil.forEach(mimeTypes, mimeType -> {
+            String[] parts = mimeType.split(MIME_TYPE_DELIMITER);
+            firstParts.add(parts[0]);
+            secondParts.add(parts[1]);
+        });
+
+        if (firstParts.size() == 1) {
+            String secondPart = secondParts.size() > 1 ? "*" : secondParts.iterator().next();
+            return firstParts.iterator().next() + MIME_TYPE_DELIMITER + secondPart;
+        } else {
+            return DEFAULT_MIME_TYPE;
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java
index 39380014..b974ca4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java
@@ -10,6 +10,7 @@
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.util.ArrayList;
@@ -124,4 +125,7 @@
         }
         return filteredList;
     }
+
+    @Override
+    public void getShareInfoForItem(ContentId id, ShareCallback callback) {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
index 1516ea28..04e2fa10 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
@@ -124,6 +124,7 @@
     public void destroyServiceDelegate() {}
 
     private void getVisualsAndUpdateItem(OfflineItem item) {
+        if (item.refreshVisuals) mVisualsCache.remove(item.id);
         if (needsVisualsForUi(item)) {
             if (!mVisualsCache.containsKey(item.id)) {
                 // We don't have any visuals for this item yet.  Stash the current OfflineItem and,
@@ -214,8 +215,9 @@
             case OfflineItemState.PENDING:
             case OfflineItemState.INTERRUPTED:
             case OfflineItemState.PAUSED:
+            case OfflineItemState.COMPLETE:
                 return true;
-            // OfflineItemState.FAILED, OfflineItemState.COMPLETE,
+            // OfflineItemState.FAILED,
             // OfflineItemState.CANCELLED
             default:
                 return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index 495291eb..3eec5419 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -161,8 +161,10 @@
             itemRemovedCallback.onResult(suggestion.mTitle);
         }
 
-        public void updateSuggestionOfflineId(int position, Long newId, boolean isPrefetched) {
-            SnippetArticle article = mSuggestions.get(position);
+        public void updateSuggestionOfflineId(
+                SnippetArticle article, Long newId, boolean isPrefetched) {
+            int position = this.mSuggestions.indexOf(article);
+
             // The suggestions could have been removed / replaced in the meantime.
             if (position == -1) return;
 
@@ -597,8 +599,8 @@
                     && TextUtils.equals(item.getClientId().getNamespace(),
                                OfflinePageBridge.SUGGESTED_ARTICLES_NAMESPACE);
 
-            mSuggestionsList.updateSuggestionOfflineId(mSuggestions.indexOf(suggestion),
-                    item == null ? null : item.getOfflineId(), isPrefetched);
+            mSuggestionsList.updateSuggestionOfflineId(
+                    suggestion, item == null ? null : item.getOfflineId(), isPrefetched);
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index add0113c..f9243abe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -272,12 +272,10 @@
                 OmniboxResultItem selectedItem =
                         (OmniboxResultItem) mSuggestionListAdapter.getItem(
                                 mSuggestionList.getSelectedItemPosition());
-                // Set the UrlBar text to empty, so that it will trigger a text change when we
-                // set the text to the suggestion again.
-                setUrlBarTextEmpty();
                 setUrlBarText(
                         UrlBarData.forNonUrlText(selectedItem.getSuggestion().getFillIntoEdit()),
                         UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_END);
+                onTextChangedForAutocomplete();
                 mSuggestionList.setSelection(0);
                 return true;
             } else if (KeyNavigationUtil.isEnter(event)
@@ -931,6 +929,7 @@
             // This must be happen after requestUrlFocus(), which changes the selection.
             mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(pastedText),
                     UrlBar.ScrollType.NO_SCROLL, UrlBarCoordinator.SelectionState.SELECT_END);
+            onTextChangedForAutocomplete();
         } else {
             ToolbarManager.recordOmniboxFocusReason(ToolbarManager.OmniboxFocusReason.FAKE_BOX_TAP);
         }
@@ -1346,6 +1345,7 @@
 
                 mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(refineText),
                         UrlBar.ScrollType.NO_SCROLL, UrlBarCoordinator.SelectionState.SELECT_END);
+                onTextChangedForAutocomplete();
                 if (isUrlSuggestion) {
                     RecordUserAction.record("MobileOmniboxRefineSuggestion.Url");
                 } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index f19610e..0695564 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -36,6 +36,7 @@
 import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.WindowDelegate;
+import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.ui.UiUtils;
 
@@ -87,10 +88,13 @@
 
     private boolean mPendingScroll;
     private int mPreviousWidth;
-    private String mPreviousTldScrollText;
-    private int mPreviousTldScrollViewWidth;
-    private int mPreviousTldScrollResultXPosition;
-    private float mPreviousFontSize;
+
+    @ScrollType
+    private int mPreviousScrollType;
+    private String mPreviousScrollText;
+    private int mPreviousScrollViewWidth;
+    private int mPreviousScrollResultXPosition;
+    private float mPreviousScrollFontSize;
 
     // Used as a hint to indicate the text may contain an ellipsize span.  This will be true if an
     // ellispize span was applied the last time the text changed.  A true value here does not
@@ -616,6 +620,25 @@
      */
     private void scrollDisplayTextInternal(@ScrollType int scrollType) {
         mPendingScroll = false;
+
+        if (mFocused) return;
+
+        Editable text = getText();
+        if (TextUtils.isEmpty(text)) scrollType = ScrollType.SCROLL_TO_BEGINNING;
+
+        // Ensure any selection from the focus state is cleared.
+        setSelection(0);
+
+        int measuredWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
+        if (scrollType == mPreviousScrollType && TextUtils.equals(text, mPreviousScrollText)
+                && measuredWidth == mPreviousScrollViewWidth
+                // Font size is float but it changes in discrete range (eg small font, big font),
+                // therefore false negative using regular equality is unlikely.
+                && getTextSize() == mPreviousScrollFontSize) {
+            scrollTo(mPreviousScrollResultXPosition, getScrollY());
+            return;
+        }
+
         switch (scrollType) {
             case ScrollType.SCROLL_TO_TLD:
                 scrollToTLD();
@@ -624,21 +647,32 @@
                 scrollToBeginning();
                 break;
             default:
-                break;
+                // Intentional return to avoid clearing scroll state when no scroll was applied.
+                return;
         }
+
+        mPreviousScrollType = scrollType;
+        mPreviousScrollText = text.toString();
+        mPreviousScrollViewWidth = measuredWidth;
+        mPreviousScrollFontSize = getTextSize();
+        mPreviousScrollResultXPosition = getScrollX();
     }
 
     /**
      * Scrolls the omnibox text to show the very beginning of the text entered.
      */
     private void scrollToBeginning() {
-        if (mFocused) return;
-
-        setSelection(0);
-
         Editable text = getText();
         float scrollPos = 0f;
-        if (BidiFormatter.getInstance().isRtl(text)) {
+        if (TextUtils.isEmpty(text)) {
+            if (ApiCompatibilityUtils.isLayoutRtl(this)
+                    && BidiFormatter.getInstance().isRtl(getHint())) {
+                // Compared to below that uses getPrimaryHorizontal(1) due to 0 returning an
+                // invalid value, if the text is empty, getPrimaryHorizontal(0) returns the actual
+                // max scroll amount.
+                scrollPos = (int) getLayout().getPrimaryHorizontal(0) - getMeasuredWidth();
+            }
+        } else if (BidiFormatter.getInstance().isRtl(text)) {
             // RTL.
             float endPointX = getLayout().getPrimaryHorizontal(text.length());
             int measuredWidth = getMeasuredWidth();
@@ -652,42 +686,8 @@
      * Scrolls the omnibox text to bring the TLD into view.
      */
     private void scrollToTLD() {
-        if (mFocused) return;
-
-        // Ensure any selection from the focus state is cleared.
-        setSelection(0);
-
-        String previousTldScrollText = mPreviousTldScrollText;
-        int previousTldScrollViewWidth = mPreviousTldScrollViewWidth;
-        int previousTldScrollResultXPosition = mPreviousTldScrollResultXPosition;
-
-        mPreviousTldScrollText = null;
-        mPreviousTldScrollViewWidth = 0;
-        mPreviousTldScrollResultXPosition = 0;
-
         Editable url = getText();
-        if (url == null || url.length() < 1) {
-            int scrollX = 0;
-            if (ApiCompatibilityUtils.isLayoutRtl(this)
-                    && BidiFormatter.getInstance().isRtl(getHint())) {
-                // Compared to below that uses getPrimaryHorizontal(1) due to 0 returning an
-                // invalid value, if the text is empty, getPrimaryHorizontal(0) returns the actual
-                // max scroll amount.
-                scrollX = (int) getLayout().getPrimaryHorizontal(0) - getMeasuredWidth();
-            }
-            scrollTo(scrollX, getScrollY());
-            return;
-        }
-
         int measuredWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
-        if (TextUtils.equals(url, previousTldScrollText)
-                && measuredWidth == previousTldScrollViewWidth
-                // Font size is float but it changes in discrete range (eg small font, big font),
-                // therefore false negative using regular equality is unlikely.
-                && getTextSize() == mPreviousFontSize) {
-            scrollTo(previousTldScrollResultXPosition, getScrollY());
-            return;
-        }
 
         assert getLayout().getLineCount() == 1;
         float endPointX = getLayout().getPrimaryHorizontal(mOriginEndIndex);
@@ -710,11 +710,6 @@
             }
         }
         scrollTo((int) scrollPos, getScrollY());
-
-        mPreviousTldScrollText = url.toString();
-        mPreviousTldScrollViewWidth = measuredWidth;
-        mPreviousFontSize = getTextSize();
-        mPreviousTldScrollResultXPosition = (int) scrollPos;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
index 7104427..2a0729f1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
@@ -81,7 +81,8 @@
             }
         }
 
-        if (isNewTextEquivalentToExistingText(mUrlBarData, data) && mScrollType == scrollType) {
+        if (!mHasFocus && isNewTextEquivalentToExistingText(mUrlBarData, data)
+                && mScrollType == scrollType) {
             return false;
         }
         mUrlBarData = data;
@@ -119,6 +120,10 @@
         // Regardless of focus state, ensure the text content is the same.
         if (!TextUtils.equals(existingCharSequence, newCharSequence)) return false;
 
+        // If both existing and new text is empty, then treat them equal regardless of their
+        // spanned state.
+        if (TextUtils.isEmpty(newCharSequence)) return true;
+
         // When not focused, compare the emphasis spans applied to the text to determine
         // equality.  Internally, TextView applies many additional spans that need to be
         // ignored for this comparison to be useful, so this is scoped to only the span types
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 70618d8..3cfbbd27 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
@@ -46,7 +46,7 @@
                 continueHandleAccountChangeIfNeeded(appContext);
             }
         };
-        task.execute();
+        task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
     }
 
     private void continueHandleAccountChangeIfNeeded(final Context context) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
index d31c60f..e449900 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
@@ -42,6 +42,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.StreamUtil;
+import org.chromium.base.StrictModeContext;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.chrome.R;
@@ -53,9 +54,6 @@
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 /**
  * A helper class that helps to start an intent to share titles and URLs.
@@ -261,20 +259,15 @@
      * Clears all shared image files.
      */
     public static void clearSharedImages() {
-        new AsyncTask<Void>() {
-            @Override
-            protected Void doInBackground() {
-                try {
-                    File imagePath = UiUtils.getDirectoryForImageCapture(
-                            ContextUtils.getApplicationContext());
-                    deleteShareImageFiles(new File(imagePath, SHARE_IMAGES_DIRECTORY_NAME));
-                } catch (IOException ie) {
-                    // Ignore exception.
-                }
-                return null;
+        AsyncTask.SERIAL_EXECUTOR.execute(() -> {
+            try {
+                File imagePath =
+                        UiUtils.getDirectoryForImageCapture(ContextUtils.getApplicationContext());
+                deleteShareImageFiles(new File(imagePath, SHARE_IMAGES_DIRECTORY_NAME));
+            } catch (IOException ie) {
+                // Ignore exception.
             }
-        }
-                .execute();
+        });
     }
 
     /**
@@ -365,7 +358,7 @@
                 }
             }
         }
-                .execute();
+                .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
     }
 
     private static class ExternallyVisibleUriCallback implements Callback<String> {
@@ -547,39 +540,17 @@
         }
         if (isComponentValid) {
             boolean retrieved = false;
+            final PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
             try {
-                final PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
-                AsyncTask<Pair<Drawable, CharSequence>> task =
-                        new AsyncTask<Pair<Drawable, CharSequence>>() {
-                            @Override
-                            protected Pair<Drawable, CharSequence> doInBackground() {
-                                Drawable directShareIcon = null;
-                                CharSequence directShareTitle = null;
-                                try {
-                                    directShareIcon = pm.getActivityIcon(component);
-                                    ApplicationInfo ai =
-                                            pm.getApplicationInfo(component.getPackageName(), 0);
-                                    directShareTitle = pm.getApplicationLabel(ai);
-                                } catch (NameNotFoundException exception) {
-                                    // Use the default null values.
-                                }
-                                return new Pair<Drawable, CharSequence>(
-                                        directShareIcon, directShareTitle);
-                            }
-                        };
-                task.execute();
-                // TODO(ltian): Return nothing for the AsyncTask and have a callback to update the
-                // the menu.
-                Pair<Drawable, CharSequence> result =
-                        task.get(COMPONENT_INFO_READ_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
-                directShareIcon = result.first;
-                directShareTitle = result.second;
+                // TODO(dtrainor): Make asynchronous and have a callback to update the menu.
+                // https://crbug.com/729737
+                try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+                    directShareIcon = pm.getActivityIcon(component);
+                    ApplicationInfo ai = pm.getApplicationInfo(component.getPackageName(), 0);
+                    directShareTitle = pm.getApplicationLabel(ai);
+                }
                 retrieved = true;
-            } catch (InterruptedException ie) {
-                // Use the default null values.
-            } catch (ExecutionException ee) {
-                // Use the default null values.
-            } catch (TimeoutException te) {
+            } catch (NameNotFoundException exception) {
                 // Use the default null values.
             }
             CachedMetrics.BooleanHistogramSample isLastSharedAppInfoRetrieved =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ConsentBumpFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/ConsentBumpFragment.java
index 9efca195..0ac8784 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ConsentBumpFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/ConsentBumpFragment.java
@@ -7,6 +7,7 @@
 import android.os.Bundle;
 import android.support.annotation.IdRes;
 import android.support.annotation.StringRes;
+import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
 import android.view.ViewGroup;
 
@@ -18,8 +19,13 @@
  * users who are already signed in and have Sync enabled, so there's no need to sign in users.
  */
 public class ConsentBumpFragment extends SigninFragmentBase {
-    public static Bundle createArguments() {
-        return createArgumentsForConsentBumpFlow();
+    /**
+     * Creates arguments for instantiating this fragment.
+     * @param accountName The name of the account to show in the consent bump
+     * @return The bundle to pass to {@link Fragment#setArguments} or {@link Fragment#instantiate}
+     */
+    public static Bundle createArguments(String accountName) {
+        return createArgumentsForConsentBumpFlow(accountName);
     }
 
     // Every fragment must have a public default constructor.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
index eff7e04..1b7bca3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivity.java
@@ -68,10 +68,11 @@
 
     /**
      * Creates an {@link Intent} which can be used to start consent bump flow.
+     * @param accountName The name of the signed in account.
      */
-    public static Intent createIntentForConsentBump(Context context) {
-        return createIntentInternal(
-                context, ConsentBumpFragment.class, ConsentBumpFragment.createArguments());
+    public static Intent createIntentForConsentBump(Context context, String accountName) {
+        return createIntentInternal(context, ConsentBumpFragment.class,
+                ConsentBumpFragment.createArguments(accountName));
     }
 
     private static Intent createIntentInternal(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
index 8ac350ed..1015765 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
@@ -157,10 +157,14 @@
         return result;
     }
 
-    /** Creates an argument bundle for the consent bump screen. */
-    protected static Bundle createArgumentsForConsentBumpFlow() {
+    /**
+     * Creates an argument bundle for the consent bump screen.
+     * @param accountName The name of the signed in account.
+     */
+    protected static Bundle createArgumentsForConsentBumpFlow(String accountName) {
         Bundle result = new Bundle();
         result.putInt(ARGUMENT_SIGNIN_FLOW_TYPE, SigninFlowType.CONSENT_BUMP);
+        result.putString(ARGUMENT_ACCOUNT_NAME, accountName);
         return result;
     }
 
@@ -200,6 +204,11 @@
         return mSigninFlowType == SigninFlowType.FORCED;
     }
 
+    /** Returns whether this fragment is in Consent bump mode. */
+    protected boolean isConsentBump() {
+        return mSigninFlowType == SigninFlowType.CONSENT_BUMP;
+    }
+
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -363,7 +372,7 @@
     }
 
     private void onAccountPickerClicked() {
-        if (isForcedSignin() || !areControlsEnabled()) return;
+        if (isForcedSignin() || isConsentBump() || !areControlsEnabled()) return;
         showAccountPicker();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
index 33080a3f..8ef93ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
@@ -171,7 +171,7 @@
                     }
                 }
             };
-            task.execute();
+            task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
             return;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java
index 707dd20d..40d38e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java
@@ -6,7 +6,9 @@
 
 import android.graphics.drawable.Drawable;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
 
 /**
@@ -33,6 +35,14 @@
     public static final int TYPE_NOTIFICATION = 1;
 
     /**
+     * Snackbars that need to persist until acknowledged. These snackbars are stored in a queue and
+     * are lower priority than both {@link #TYPE_ACTION}, and {@link #TYPE_NOTIFICATION}. These must
+     * be dismissed one by one via a click. As such, snackbars of this type MUST call
+     * {@link #setAction(String, Object)} so that there is a way to remove them.
+     */
+    public static final int TYPE_PERSISTENT = 2;
+
+    /**
      * UMA Identifiers of features using snackbar. See SnackbarIdentifier enum in histograms.
      */
     public static final int UMA_TEST_SNACKBAR = -2;
@@ -97,6 +107,12 @@
         s.mController = controller;
         s.mType = type;
         s.mIdentifier = identifier;
+        if (type == TYPE_PERSISTENT) {
+            // For persistent snackbars we set a default action text to ensure the snackbar can be
+            // closed.
+            s.mActionText =
+                    ContextUtils.getApplicationContext().getResources().getString(R.string.ok);
+        }
         return s;
     }
 
@@ -145,6 +161,7 @@
      * use the default duration.
      */
     public Snackbar setDuration(int durationMs) {
+        assert !isTypePersistent() : "Persistent snackbars do not timeout.";
         mDurationMs = durationMs;
         return this;
     }
@@ -229,4 +246,11 @@
     boolean isTypeAction() {
         return mType == TYPE_ACTION;
     }
+
+    /**
+     * @return Whether the snackbar is of {@link #TYPE_PERSISTENT}.
+     */
+    boolean isTypePersistent() {
+        return mType == TYPE_PERSISTENT;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarCollection.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarCollection.java
index e8b2965..d7daac9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarCollection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarCollection.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.snackbar;
 
+import android.text.TextUtils;
+
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
 
 import java.util.Deque;
@@ -15,12 +17,15 @@
  */
 class SnackbarCollection {
     private Deque<Snackbar> mSnackbars = new LinkedList<>();
+    private Deque<Snackbar> mPersistentSnackbars = new LinkedList<>();
 
     /**
      * Adds a new snackbar to the collection. If the new snackbar is of
      * {@link Snackbar#TYPE_ACTION} and current snackbar is of
      * {@link Snackbar#TYPE_NOTIFICATION}, the current snackbar will be removed from the
-     * collection immediately.
+     * collection immediately. Snackbars of {@link Snackbar#TYPE_PERSISTENT} will appear after all
+     * action and notification type snackbars are dismissed and will be hidden if an action or
+     * notifications are added after it.
      */
     void add(Snackbar snackbar) {
         if (snackbar.isTypeAction()) {
@@ -28,6 +33,13 @@
                 removeCurrent(false);
             }
             mSnackbars.addFirst(snackbar);
+        } else if (snackbar.isTypePersistent()) {
+            // Although persistent snackbars set their action text by default, it is possible that
+            // the developer overrides it. This is a safeguard to ensure all persistent snackbars
+            // have a method of dismissal.
+            assert !TextUtils.isEmpty(snackbar.getActionText())
+                : "Persistent snackbars require action text.";
+            mPersistentSnackbars.addFirst(snackbar);
         } else {
             mSnackbars.addLast(snackbar);
         }
@@ -43,6 +55,9 @@
 
     private Snackbar removeCurrent(boolean isAction) {
         Snackbar current = mSnackbars.pollFirst();
+        if (current == null) {
+            current = mPersistentSnackbars.pollFirst();
+        }
         if (current != null) {
             SnackbarController controller = current.getController();
             if (isAction) controller.onAction(current.getActionData());
@@ -55,11 +70,15 @@
      * @return The snackbar that is currently displayed.
      */
     Snackbar getCurrent() {
-        return mSnackbars.peekFirst();
+        Snackbar current = mSnackbars.peekFirst();
+        if (current == null) {
+            current = mPersistentSnackbars.peekFirst();
+        }
+        return current;
     }
 
     boolean isEmpty() {
-        return mSnackbars.isEmpty();
+        return mSnackbars.isEmpty() && mPersistentSnackbars.isEmpty();
     }
 
     void clear() {
@@ -69,8 +88,14 @@
     }
 
     void removeCurrentDueToTimeout() {
+        Snackbar current = getCurrent();
+        if (current.isTypePersistent()) {
+            // In theory, this method should never be called on a persistent snackbar as the
+            // dismissal handler is disabled. As a precaution, we exit early if the snackbar is
+            // meant to be persistent.
+            return;
+        }
         removeCurrent(false);
-        Snackbar current;
         while ((current = getCurrent()) != null && current.isTypeAction()) {
             removeCurrent(false);
         }
@@ -79,8 +104,9 @@
     boolean removeMatchingSnackbars(SnackbarController controller) {
         boolean snackbarRemoved = false;
         Iterator<Snackbar> iter = mSnackbars.iterator();
-        while (iter.hasNext()) {
-            Snackbar snackbar = iter.next();
+        Iterator<Snackbar> persistentIter = mPersistentSnackbars.iterator();
+        while (iter.hasNext() || persistentIter.hasNext()) {
+            Snackbar snackbar = iter.hasNext() ? iter.next() : persistentIter.next();
             if (snackbar.getController() == controller) {
                 iter.remove();
                 controller.onDismissNoAction(snackbar.getActionData());
@@ -93,8 +119,9 @@
     boolean removeMatchingSnackbars(SnackbarController controller, Object data) {
         boolean snackbarRemoved = false;
         Iterator<Snackbar> iter = mSnackbars.iterator();
-        while (iter.hasNext()) {
-            Snackbar snackbar = iter.next();
+        Iterator<Snackbar> persistentIter = mPersistentSnackbars.iterator();
+        while (iter.hasNext() || persistentIter.hasNext()) {
+            Snackbar snackbar = iter.hasNext() ? iter.next() : persistentIter.next();
             if (snackbar.getController() == controller
                     && objectsAreEqual(snackbar.getActionData(), data)) {
                 iter.remove();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
index 1adc8077..c4f2e56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
@@ -24,7 +24,8 @@
  * When action button is clicked, this manager will call {@link SnackbarController#onAction(Object)}
  * in corresponding listener, and show the next entry. Otherwise if no action is taken by user
  * during {@link #DEFAULT_SNACKBAR_DURATION_MS} milliseconds, it will call
- * {@link SnackbarController#onDismissNoAction(Object)}.
+ * {@link SnackbarController#onDismissNoAction(Object)}. Note, snackbars of
+ * {@link Snackbar#TYPE_PERSISTENT} do not get automatically dismissed after a timeout.
  */
 public class SnackbarManager implements OnClickListener, InfoBarContainer.InfoBarContainerObserver {
     /**
@@ -51,7 +52,7 @@
         default void onAction(Object actionData) { }
 
         /**
-         * Called when the snackbar is dismissed by tiemout or UI enviroment change.
+         * Called when the snackbar is dismissed by timeout or UI environment change.
          * @param actionData Data object associated with the dismissed snackbar entry.
          */
         default void onDismissNoAction(Object actionData) { }
@@ -221,9 +222,11 @@
             }
 
             if (viewChanged) {
-                int durationMs = getDuration(currentSnackbar);
                 mUIThreadHandler.removeCallbacks(mHideRunnable);
-                mUIThreadHandler.postDelayed(mHideRunnable, durationMs);
+                if (!currentSnackbar.isTypePersistent()) {
+                    int durationMs = getDuration(currentSnackbar);
+                    mUIThreadHandler.postDelayed(mHideRunnable, durationMs);
+                }
                 mView.announceforAccessibility();
             }
         }
@@ -240,7 +243,7 @@
     }
 
     /**
-     * Disables the snackbar manager. This is only intented for testing purposes.
+     * Disables the snackbar manager. This is only intended for testing purposes.
      */
     @VisibleForTesting
     public void disableForTesting() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
index 208a157..42c203e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
@@ -10,10 +10,12 @@
 import android.view.View;
 
 import org.chromium.base.Callback;
+import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
+import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.util.FeatureUtilities;
@@ -112,24 +114,36 @@
         if (activity.isActivityDestroyed()) return;
 
         assert(stringId != 0 && accessibilityStringId != 0);
-        if (!tracker.shouldTriggerHelpUI(featureName)) return;
 
-        ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
+        // Post a request to show the IPH bubble to allow time for a layout pass. Since the bubble
+        // is shown on startup, the anchor view may not have a height initially see
+        // https://crbug.com/871537.
+        ThreadUtils.postOnUiThread(() -> {
+            if (activity.isActivityDestroyed()) return;
 
-        TextBubble textBubble =
-                new TextBubble(activity, anchorView, stringId, accessibilityStringId, rectProvider);
-        textBubble.setDismissOnTouchInteraction(true);
-        textBubble.addOnDismissListener(() -> anchorView.getHandler().postDelayed(() -> {
-            tracker.dismissed(featureName);
-            turnOffHighlightForTextBubble(appMenuHandler, anchorView);
-        }, ViewHighlighter.IPH_MIN_DELAY_BETWEEN_TWO_HIGHLIGHTS));
+            if (TextUtils.equals(featureName, FeatureConstants.NTP_BUTTON_FEATURE)
+                    && !canShowNTPButtonIPH(activity)) {
+                return;
+            }
 
-        turnOnHighlightForTextBubble(appMenuHandler, highlightMenuItemId, anchorView);
+            if (!tracker.shouldTriggerHelpUI(featureName)) return;
+            ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
 
-        int yInsetPx = activity.getResources().getDimensionPixelOffset(
-                R.dimen.text_bubble_menu_anchor_y_inset);
-        rectProvider.setInsetPx(0, 0, 0, yInsetPx);
-        textBubble.show();
+            TextBubble textBubble = new TextBubble(
+                    activity, anchorView, stringId, accessibilityStringId, rectProvider);
+            textBubble.setDismissOnTouchInteraction(true);
+            textBubble.addOnDismissListener(() -> anchorView.getHandler().postDelayed(() -> {
+                tracker.dismissed(featureName);
+                turnOffHighlightForTextBubble(appMenuHandler, anchorView);
+            }, ViewHighlighter.IPH_MIN_DELAY_BETWEEN_TWO_HIGHLIGHTS));
+
+            turnOnHighlightForTextBubble(appMenuHandler, highlightMenuItemId, anchorView);
+
+            int yInsetPx = activity.getResources().getDimensionPixelOffset(
+                    R.dimen.text_bubble_menu_anchor_y_inset);
+            rectProvider.setInsetPx(0, 0, 0, yInsetPx);
+            textBubble.show();
+        });
     }
 
     private static void turnOnHighlightForTextBubble(
@@ -152,7 +166,8 @@
     private static boolean canShowNTPButtonIPH(ChromeTabbedActivity activity) {
         View homeButton = activity.findViewById(R.id.home_button);
         return FeatureUtilities.isNewTabPageButtonEnabled()
-                && !activity.getCurrentTabModel().isIncognito() && homeButton != null
+                && !activity.getCurrentTabModel().isIncognito() && activity.getActivityTab() != null
+                && !NewTabPage.isNTPUrl(activity.getActivityTab().getUrl()) && homeButton != null
                 && homeButton.getVisibility() == View.VISIBLE;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java
index d353c7f..f8c990d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -25,6 +25,7 @@
 import com.google.vr.ndk.base.AndroidCompat;
 import com.google.vr.ndk.base.GvrLayout;
 
+import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
@@ -142,6 +143,34 @@
         mTabModelSelector = tabModelSelector;
         mVrBrowsingEnabled = mDelegate.isVrBrowsingEnabled();
 
+        mReprojectedRendering = setAsyncReprojectionEnabled(true);
+        if (mReprojectedRendering) {
+            // No need render to a Surface if we're reprojected. We'll be rendering with surfaceless
+            // EGL.
+            mPresentationView = new FrameLayout(mActivity);
+
+            // This can show up behind popups on standalone devices, so make sure it's black.
+            mPresentationView.setBackgroundColor(Color.BLACK);
+
+            // Only enable sustained performance mode when Async reprojection decouples the app
+            // framerate from the display framerate.
+            AndroidCompat.setSustainedPerformanceMode(mActivity, true);
+        } else {
+            if (VrShellDelegate.isDaydreamCurrentViewer()) {
+                // We need Async Reprojection on when entering VR browsing, because otherwise our
+                // GL context will be lost every time we're hidden, like when we go to the dashboard
+                // and come back.
+                // TODO(mthiesse): Supporting context loss turned out to be hard. We should consider
+                // spending more effort on supporting this in the future if it turns out to be
+                // important.
+                Log.e(TAG, "Could not turn async reprojection on for Daydream headset.");
+                throw new VrShellDelegate.VrUnsupportedException();
+            }
+            SurfaceView surfaceView = new SurfaceView(mActivity);
+            surfaceView.getHolder().addCallback(this);
+            mPresentationView = surfaceView;
+        }
+
         mActivity.getToolbarManager().setProgressBarEnabled(false);
 
         DisplayAndroid primaryDisplay = DisplayAndroid.getNonMultiDisplay(activity);
@@ -168,24 +197,6 @@
         // See VrShellDelegate#getEnterVrPendingIntent for why we need to do this.
         setReentryIntent(VrShellDelegate.getEnterVrPendingIntent(activity));
 
-        mReprojectedRendering = setAsyncReprojectionEnabled(true);
-        if (mReprojectedRendering) {
-            // No need render to a Surface if we're reprojected. We'll be rendering with surfaceless
-            // EGL.
-            mPresentationView = new FrameLayout(mActivity);
-
-            // This can show up behind popups on standalone devices, so make sure it's black.
-            mPresentationView.setBackgroundColor(Color.BLACK);
-
-            // Only enable sustained performance mode when Async reprojection decouples the app
-            // framerate from the display framerate.
-            AndroidCompat.setSustainedPerformanceMode(mActivity, true);
-        } else {
-            SurfaceView surfaceView = new SurfaceView(mActivity);
-            surfaceView.getHolder().addCallback(this);
-            mPresentationView = surfaceView;
-        }
-
         setPresentationView(mPresentationView);
 
         getUiLayout().setCloseButtonListener(mDelegate.getVrCloseButtonListener());
@@ -940,7 +951,7 @@
     @Override
     public void surfaceDestroyed(SurfaceHolder holder) {
         mVrCompositorSurfaceManager.surfaceDestroyed();
-        if (mNativeVrShell != 0) nativeSetSurface(mNativeVrShell, null);
+        VrShellDelegate.forceExitVrImmediately();
     }
 
     /** Creates and attaches a TabModelSelectorTabObserver to the tab model selector. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
index 96948b2..58e8ff77 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
@@ -214,6 +214,8 @@
 
     private long mNativeVrShellDelegate;
 
+    /* package */ final static class VrUnsupportedException extends RuntimeException {}
+
     private static final class VrLifecycleObserver
             implements ApplicationStatus.ActivityStateListener {
         @Override
@@ -802,7 +804,7 @@
         try {
             return isDaydreamReadyDevice() && DaydreamApi.isInVrSession(context);
         } catch (Exception ex) {
-            Log.e(TAG, "Unable to check if in vr session", ex);
+            Log.e(TAG, "Unable to check if in VR session", ex);
             return false;
         }
     }
@@ -1792,11 +1794,16 @@
         // The user has exited VR.
         RecordUserAction.record("VR.DOFF");
 
+        if (disableVrMode) setVrModeEnabled(mActivity, false);
+
+        // We get crashes on Android K related to surfaces if we manipulate the view hierarchy while
+        // finishing.
+        if (mActivity.isFinishing()) return;
+
         restoreWindowMode();
         mVrShell.pause();
         removeVrViews();
         destroyVrShell();
-        if (disableVrMode) setVrModeEnabled(mActivity, false);
 
         promptForFeedbackIfNeeded(stayingInChrome);
 
@@ -1906,6 +1913,8 @@
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             mVrShell = new VrShell(mActivity, this, tabModelSelector);
+        } catch (VrUnsupportedException e) {
+            return false;
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
index ca4bf862..6fae94f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
@@ -12,6 +12,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Bundle;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
@@ -146,8 +147,7 @@
         int badgeIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.BADGE_ICON_ID, 0);
         Bitmap badgeIcon = decodeBitmapFromDrawable(res, badgeIconId);
 
-        int splashIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.SPLASH_ID, 0);
-        Bitmap splashIcon = decodeBitmapFromDrawable(res, splashIconId);
+        Bitmap splashIcon = decodeSplashIcon(bundle, res, primaryIconId);
 
         return create(WebApkConstants.WEBAPK_ID_PREFIX + webApkPackageName, url, scope,
                 new Icon(primaryIcon), new Icon(badgeIcon), new Icon(splashIcon), name, shortName,
@@ -307,6 +307,66 @@
     }
 
     /**
+     * Decodes a bitmap drawable from the WebAPK's resources for a specific density.
+     */
+    private static Bitmap decodeBitmapFromDrawableForDensity(
+            Resources webApkResources, int resourceId, int density) {
+        if (resourceId == 0) {
+            return null;
+        }
+        try {
+            BitmapDrawable bitmapDrawable =
+                    (BitmapDrawable) ApiCompatibilityUtils.getDrawableForDensity(
+                            webApkResources, resourceId, density);
+            return bitmapDrawable != null ? bitmapDrawable.getBitmap() : null;
+        } catch (Resources.NotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Computes the density of app icon to use for the splash screen based on the device density.
+     */
+    private static int computeDensityforSplashIcon(int deviceDensity) {
+        if (deviceDensity < DisplayMetrics.DENSITY_HIGH) {
+            return DisplayMetrics.DENSITY_XHIGH;
+        }
+        if (deviceDensity < DisplayMetrics.DENSITY_XHIGH) {
+            return DisplayMetrics.DENSITY_XXHIGH;
+        }
+        return DisplayMetrics.DENSITY_XXXHIGH;
+    }
+
+    /**
+     * Decodes a splash icon with logic dependent on the device's density.
+     */
+    private static Bitmap decodeSplashIcon(
+            Bundle bundle, Resources webApkResources, int appIconId) {
+        DisplayMetrics metrics = webApkResources.getDisplayMetrics();
+        if (metrics == null) {
+            // We have no basis on which to choose a higher DPI, so default to primary icon.
+            return null;
+        }
+        int deviceDensity = metrics.densityDpi;
+        int splashIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.SPLASH_ID, 0);
+        boolean hasLargeSplashIcons = IntentUtils.safeGetBoolean(
+                bundle, WebApkMetaDataKeys.HAS_LARGE_SPLASH_ICONS, false);
+
+        if (deviceDensity >= DisplayMetrics.DENSITY_XXHIGH && hasLargeSplashIcons) {
+            // If the server was able to provide larger splash icons we use those. This can be
+            // one or both of xxhdpi and xxxhdpi. If only one exists the up/down sampling is only
+            // for a single density and will still look good.
+            return decodeBitmapFromDrawable(webApkResources, splashIconId);
+        }
+        // If there is no drawable for a density this will down-sample or up-sample whatever app
+        // icons are provided to fit the target density. This can result in lower graphical
+        // fidelity; however, Chrome already does this for xxxhdpi icons in most cases so this isn't
+        // a concern.
+        return decodeBitmapFromDrawableForDensity(
+                webApkResources, appIconId, computeDensityforSplashIcon(deviceDensity));
+    }
+
+    /**
      * Extracts long value from the WebAPK's meta data.
      * @param metaData WebAPK meta data to extract the long from.
      * @param name Name of the <meta-data> tag to extract the value from.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index d115c2f..ed5c3fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -17,7 +17,6 @@
 import android.os.SystemClock;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
-import android.support.customtabs.CustomTabsService;
 import android.support.customtabs.CustomTabsSessionToken;
 import android.support.customtabs.TrustedWebUtils;
 import android.text.TextUtils;
@@ -47,10 +46,9 @@
 import org.chromium.chrome.browser.browserservices.BrowserSessionContentUtils;
 import org.chromium.chrome.browser.browserservices.BrowserSessionDataProvider;
 import org.chromium.chrome.browser.browserservices.Origin;
-import org.chromium.chrome.browser.browserservices.OriginVerifier;
-import org.chromium.chrome.browser.browserservices.OriginVerifier.OriginVerificationListener;
 import org.chromium.chrome.browser.browserservices.TrustedWebActivityDisclosure;
 import org.chromium.chrome.browser.browserservices.UkmRecorder;
+import org.chromium.chrome.browser.browserservices.VerificationState;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.customtabs.CustomTabAppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
@@ -130,13 +128,9 @@
     private BrowserSessionDataProvider mBrowserSessionDataProvider;
 
     private TrustedWebContentProvider mTrustedWebContentProvider;
+    private VerificationState mVerificationState;
 
-    private class TrustedWebContentProvider
-            implements BrowserSessionContentHandler, OriginVerificationListener {
-        private boolean mVerificationFailed;
-        private OriginVerifier mOriginVerifier;
-        private final UkmRecorder mUkmRecorder = new UkmRecorder.Bridge();
-
+    private class TrustedWebContentProvider implements BrowserSessionContentHandler {
         @Override
         public void loadUrlAndTrackFromTimestamp(LoadUrlParams params, long timestamp) {}
 
@@ -176,45 +170,6 @@
                     .getPendingEntry();
             return entry != null ? entry.getUrl() : null;
         }
-
-        /**
-         * Verify the Digital Asset Links declared by the Android native client with the currently
-         * loading origin. See {@link TrustedWebContentProvider#didVerificationFail()} for the
-         * result.
-         */
-        void verifyRelationship() {
-            mOriginVerifier = new OriginVerifier(mTrustedWebContentProvider,
-                    getNativeClientPackageName(), CustomTabsService.RELATION_HANDLE_ALL_URLS);
-            mOriginVerifier.start(new Origin(mWebappInfo.uri()));
-        }
-
-        @Override
-        public void onOriginVerified(String packageName, Origin origin, boolean verified,
-                Boolean online) {
-            mVerificationFailed = !verified;
-            mOriginVerifier = null;
-
-            if (mVerificationFailed) {
-                getFullscreenManager().setPositionsForTabToNonFullscreen();
-                return;
-            }
-
-            BrowserServicesMetrics.recordTwaOpened();
-            TrustedWebActivityDisclosure.showIfNeeded(WebappActivity.this, packageName);
-
-            // When verification occurs instantly (eg the result is cached) then it returns before
-            // there is an active tab.
-            if (areTabModelsInitialized() && getActivityTab() != null) {
-                mUkmRecorder.recordTwaOpened(getActivityTab().getWebContents());
-            }
-        }
-
-        /**
-         * @return Whether origin verification for the corresponding client failed.
-         */
-        boolean didVerificationFail() {
-            return mVerificationFailed;
-        }
     }
 
     /** Initialization-on-demand holder. This exists for thread-safe lazy initialization. */
@@ -632,7 +587,26 @@
 
     @Override
     public void postInflationStartup() {
-        if (getBrowserSession() != null) mTrustedWebContentProvider.verifyRelationship();
+        if (getBrowserSession() != null) {
+            String packageName = getNativeClientPackageName();
+
+            mVerificationState = new VerificationState(packageName,
+                    new Origin(mWebappInfo.uri()), success -> {
+                if (!success) {
+                    getFullscreenManager().setPositionsForTabToNonFullscreen();
+                    return;
+                }
+
+                BrowserServicesMetrics.recordTwaOpened();
+                TrustedWebActivityDisclosure.showIfNeeded(this, packageName);
+
+                // When verification occurs instantly (eg the result is cached) then it returns
+                // before there is an active tab.
+                if (areTabModelsInitialized() && getActivityTab() != null) {
+                    new UkmRecorder.Bridge().recordTwaOpened(getActivityTab().getWebContents());
+                }
+            });
+        }
 
         super.postInflationStartup();
     }
@@ -1020,7 +994,7 @@
      */
     boolean didVerificationFail() {
         if (!isVerified()) return false;
-        return mTrustedWebContentProvider.didVerificationFail();
+        return mVerificationState.didVerificationFail();
     }
 
     /**
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
index 2ab0f5f1..50a3c5e 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
@@ -5,6 +5,7 @@
 <translation id="1036727731225946849">Agregando <ph name="WEBAPK_NAME" />…</translation>
 <translation id="1041308826830691739">De sitios web</translation>
 <translation id="1049743911850919806">Incógnito</translation>
+<translation id="1054301162707478098">Estás en modo privado.</translation>
 <translation id="10614374240317010">Nunca guardado</translation>
 <translation id="1068672505746868501">No traducir nunca páginas en <ph name="SOURCE_LANGUAGE" /></translation>
 <translation id="10713315585330490"><ph name="FILE_SIZE" /> - <ph name="DESCRIPTION" /></translation>
@@ -35,6 +36,9 @@
 <translation id="124116460088058876">Más idiomas</translation>
 <translation id="124678866338384709">Cerrar la pestaña actual</translation>
 <translation id="1258753120186372309">Doodle de Google: <ph name="DOODLE_DESCRIPTION" /></translation>
+<translation id="1259100630977430756">Una vez que cierres todas las pestañas en privado, los datos de las páginas que hayas visitado en ese modo no se guardarán en el historial del navegador, en la lista de cookies ni en el historial de búsquedas. Sí se guardarán los archivos que descargues y los favoritos que crees.
+
+Sin embargo, no vas a pasar completamente desapercibido. El modo de navegación privado no oculta tu información de navegación de un empleador, del proveedor de servicios de Internet ni de los sitios web que visitas.</translation>
 <translation id="127138278192656016">Usar la sincronización y todos los servicios</translation>
 <translation id="1272079795634619415">Interrumpir</translation>
 <translation id="1283039547216852943">Presiona para expandir</translation>
@@ -137,6 +141,7 @@
 <translation id="2021896219286479412">Controles en pantalla completa</translation>
 <translation id="2038563949887743358">Activar la opción para solicitar versión de escritorio</translation>
 <translation id="2045104531052923016">Otras apps: <ph name="GIGABYTES" /> gigabytes</translation>
+<translation id="2055670718290744343">Acelerador de búsqueda</translation>
 <translation id="2063713494490388661">Presionar para buscar</translation>
 <translation id="2079545284768500474">Deshacer</translation>
 <translation id="2082238445998314030">Resultado <ph name="RESULT_NUMBER" /> de <ph name="TOTAL_RESULTS" /></translation>
@@ -164,6 +169,7 @@
 <translation id="2234876718134438132">Sincronización y servicios</translation>
 <translation id="2259659629660284697">Exportar contraseñas…</translation>
 <translation id="2268044343513325586">Definir mejor</translation>
+<translation id="2280910239864711607">Abrir ventana nueva en modo privado</translation>
 <translation id="2286841657746966508">Dirección de facturación</translation>
 <translation id="230115972905494466">No se encontraron dispositivos compatibles</translation>
 <translation id="2315043854645842844">El sistema operativo no admite la selección de certificados del lado del cliente.</translation>
@@ -214,6 +220,7 @@
 <translation id="2621115761605608342">Permitir la ejecución de JavaScript para un sitio específico</translation>
 <translation id="2625189173221582860">Se copió la contraseña</translation>
 <translation id="2631006050119455616">Ahorrados</translation>
+<translation id="2633278372998075009">Pestañas privadas</translation>
 <translation id="2647434099613338025">Agregar idioma</translation>
 <translation id="2650751991977523696">¿Deseas volver a descargar el archivo?</translation>
 <translation id="2653659639078652383">Enviar</translation>
@@ -273,6 +280,7 @@
 <translation id="321773570071367578">Si olvidaste la frase de contraseña o quieres cambiar esta configuración, <ph name="BEGIN_LINK" />restablece la contraseña<ph name="END_LINK" /></translation>
 <translation id="3227137524299004712">Micrófono</translation>
 <translation id="3232754137068452469">Aplicación web</translation>
+<translation id="3234355010754616171">Nueva pestaña privada</translation>
 <translation id="3236059992281584593">1 minuto restante</translation>
 <translation id="3244271242291266297">MM</translation>
 <translation id="3254409185687681395">Agregar esta página a Favoritos</translation>
@@ -288,6 +296,7 @@
 <translation id="3350687908700087792">Cerrar todas las pestañas de incógnito</translation>
 <translation id="3365671512111106261">No está disponible cuando la función Ahorro de datos está activada</translation>
 <translation id="3367813778245106622">Volver a acceder para iniciar la sincronización</translation>
+<translation id="3377025655491224618">Pestaña privada</translation>
 <translation id="3384347053049321195">Compartir imagen</translation>
 <translation id="3386292677130313581">Preguntar antes de permitir que los sitios conozcan tu ubicación (recomendado)</translation>
 <translation id="3387650086002190359"><ph name="FILE_NAME" /> no se pudo descargar debido a errores del sistema de archivos.</translation>
@@ -385,6 +394,7 @@
 <translation id="4209895695669353772">Para obtener contenido personalizado y sugerido por Google, activa la sincronización</translation>
 <translation id="4226663524361240545">Es posible que las notificaciones hagan vibrar el dispositivo</translation>
 <translation id="4242533952199664413">Abrir la configuración</translation>
+<translation id="4243710787042215766">Abrir en una pestaña privada</translation>
 <translation id="424864128008805179">¿Quieres salir de Chrome?</translation>
 <translation id="4256782883801055595">Licencias de código abierto</translation>
 <translation id="4259722352634471385">Navegación bloqueada: <ph name="URL" /></translation>
@@ -465,6 +475,7 @@
 <translation id="4878404682131129617">Se produjo un error al establecer conexión a través del servidor proxy</translation>
 <translation id="4881695831933465202">Abrir</translation>
 <translation id="488187801263602086">Cambiar el nombre del archivo</translation>
+<translation id="4883379392681899581">Abandonar el modo privado</translation>
 <translation id="4885273946141277891">Cantidad de instancias de Chrome no admitidas</translation>
 <translation id="4910889077668685004">Apps de pago</translation>
 <translation id="4913161338056004800">Restablecer estadísticas</translation>
@@ -506,6 +517,7 @@
 <translation id="5224771365102442243">Con video</translation>
 <translation id="5233638681132016545">Nueva pestaña</translation>
 <translation id="5240817131241497236">Se cambiaron las opciones de configuración que controlan la sincronización, la personalización y otros servicios de Google en Chrome. Es posible que tu configuración actual se vea afectada.</translation>
+<translation id="5264003212305142034">Se puede modificar la <ph name="BEGIN_LINK1" />Configuración<ph name="END_LINK1" /> en cualquier momento. Es posible que usemos contenido de los sitios que visitas (así como tus interacciones y actividad de navegación) a fin de personalizar Chrome y otros servicios de Google, como el Traductor, la Búsqueda y los anuncios.</translation>
 <translation id="5271967389191913893">El dispositivo no puede abrir el contenido que se descargará.</translation>
 <translation id="528192093759286357">Arrastra el dedo desde la parte superior y toca el botón Atrás para salir de la pantalla completa.</translation>
 <translation id="5284584623296338184">Los cambios que hagas en tus favoritos, historial, contraseñas y otras opciones de configuración se seguirán sincronizando con tu cuenta de Google. Sin embargo, tus datos existentes seguirán almacenados en tu cuenta de Google.</translation>
@@ -591,6 +603,7 @@
 <translation id="583281660410589416">Desconocido</translation>
 <translation id="5833397272224757657">Usa el contenido de los sitios que visitas, tus interacciones y actividad de navegación para personalizar las opciones</translation>
 <translation id="5833984609253377421">Compartir vínculo</translation>
+<translation id="584427517463557805">Pestaña privada seleccionada</translation>
 <translation id="5854790677617711513">Hace más de 30 días</translation>
 <translation id="5858741533101922242">Chrome no puede activar el adaptador Bluetooth</translation>
 <translation id="5860033963881614850">Desactivado</translation>
@@ -620,6 +633,7 @@
 <translation id="6075798973483050474">Editar la Página principal</translation>
 <translation id="60923314841986378"><ph name="HOURS" /> horas restantes</translation>
 <translation id="60924377787140961">Pronto se mostrarán más artículos. Disfruta tu tarde.</translation>
+<translation id="6099151465289169210">Se seleccionaron las pestañas privadas</translation>
 <translation id="6108923351542677676">Configuración en curso…</translation>
 <translation id="6111020039983847643">datos utilizados</translation>
 <translation id="6112702117600201073">Actualizando la página</translation>
@@ -649,6 +663,7 @@
 <translation id="6320088164292336938">Vibrar</translation>
 <translation id="6324034347079777476">Sincronización del sistema Android inhabilitada</translation>
 <translation id="6333140779060797560">Compartir mediante <ph name="APPLICATION" /></translation>
+<translation id="6336451774241870485">Nueva pestaña privada</translation>
 <translation id="6337234675334993532">Encriptación</translation>
 <translation id="6341580099087024258">Preguntar dónde guardar los archivos</translation>
 <translation id="6343192674172527289">No se encontraron descargas</translation>
@@ -686,6 +701,7 @@
 <translation id="6593061639179217415">Sitio de escritorio</translation>
 <translation id="6600954340915313787">Se copió en Chrome.</translation>
 <translation id="6608650720463149374"><ph name="GIGABYTES" /> GB</translation>
+<translation id="6610147964972079463">Cerrar las pestañas privadas</translation>
 <translation id="6612358246767739896">Contenido protegido</translation>
 <translation id="6627583120233659107">Editar la carpeta</translation>
 <translation id="6643016212128521049">Borrar</translation>
@@ -789,6 +805,7 @@
 <translation id="7453467225369441013">Esta acción te hace salir de la mayoría de los sitios. No saldrás de tu cuenta de Google.</translation>
 <translation id="7454641608352164238">No hay suficiente espacio</translation>
 <translation id="7455923816558154057">Presiona para ver</translation>
+<translation id="7465104139234185284">Cerrar todas las pestañas privadas</translation>
 <translation id="7473891865547856676">No, gracias</translation>
 <translation id="7475192538862203634">Si el mensaje aparece con frecuencia, intenta seguir estas <ph name="BEGIN_LINK" />sugerencias<ph name="END_LINK" />.</translation>
 <translation id="7475688122056506577">No se encontró la tarjeta SD. Es posible que falten algunos archivos.</translation>
@@ -884,6 +901,7 @@
 <translation id="8220488350232498290">Contenido descargado: <ph name="GIGABYTES" /> gigabytes</translation>
 <translation id="8249310407154411074">Mover al principio</translation>
 <translation id="8250920743982581267">Documentos</translation>
+<translation id="825412236959742607">Chrome quitó parte del contenido de esta página porque usa demasiada memoria.</translation>
 <translation id="8260126382462817229">Intenta volver a acceder</translation>
 <translation id="8261506727792406068">Borrar</translation>
 <translation id="8266862848225348053">Ubicación de las descargas</translation>
@@ -979,6 +997,7 @@
 <translation id="9070377983101773829">Iniciar búsqueda por voz</translation>
 <translation id="9071742570345586758">Para ver contenido de realidad virtual, instala los servicios de RV de Google</translation>
 <translation id="9074336505530349563">Para obtener contenido personalizado y sugerido por Google, accede a tu cuenta y activa la sincronización</translation>
+<translation id="9080642952018487277">Acceder al modo privado</translation>
 <translation id="9086455579313502267">No se puede acceder a la red</translation>
 <translation id="9099018167121903954">Contenido descargado: <ph name="KILOBYTES" /> kilobytes</translation>
 <translation id="9100505651305367705">Se ofrece mostrar artículos en una vista simplificada, cuando es compatible</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
index 8418d6fe..d07b161 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
@@ -5,6 +5,7 @@
 <translation id="1036727731225946849">正在添加<ph name="WEBAPK_NAME" />…</translation>
 <translation id="1041308826830691739">来自网站</translation>
 <translation id="1049743911850919806">隐身</translation>
+<translation id="1054301162707478098">您已进入私密模式。</translation>
 <translation id="10614374240317010">一律不保存</translation>
 <translation id="1068672505746868501">一律不翻译源语言为<ph name="SOURCE_LANGUAGE" />的网页</translation>
 <translation id="10713315585330490"><ph name="FILE_SIZE" /> - <ph name="DESCRIPTION" /></translation>
@@ -35,6 +36,9 @@
 <translation id="124116460088058876">更多语言</translation>
 <translation id="124678866338384709">关闭当前标签页</translation>
 <translation id="1258753120186372309">Google 涂鸦:<ph name="DOODLE_DESCRIPTION" /></translation>
+<translation id="1259100630977430756">在您关闭所有私密标签页后,您在其中查看的网页不会在浏览器历史记录、Cookie 存储区或搜索记录中留下任何痕迹。不过,您下载的所有文件或创建的书签均会保留下来。
+
+但是,这并不意味着您能完全隐身。即使您进入私密模式,您的雇主、互联网服务提供商和您访问的网站仍然能看到您的浏览活动。</translation>
 <translation id="127138278192656016">使用同步功能和所有服务</translation>
 <translation id="1272079795634619415">停止</translation>
 <translation id="1283039547216852943">点按即可展开</translation>
@@ -137,6 +141,7 @@
 <translation id="2021896219286479412">全屏网站控件</translation>
 <translation id="2038563949887743358">开启“请求切换到桌面版网站”</translation>
 <translation id="2045104531052923016">其他应用已占用的空间:<ph name="GIGABYTES" /> GB</translation>
+<translation id="2055670718290744343">搜索加速器</translation>
 <translation id="2063713494490388661">点按搜索</translation>
 <translation id="2079545284768500474">撤消</translation>
 <translation id="2082238445998314030">第 <ph name="RESULT_NUMBER" /> 条结果,共 <ph name="TOTAL_RESULTS" /> 条</translation>
@@ -164,6 +169,7 @@
 <translation id="2234876718134438132">同步功能和 Google 服务</translation>
 <translation id="2259659629660284697">导出密码…</translation>
 <translation id="2268044343513325586">优化</translation>
+<translation id="2280910239864711607">在私密模式下打开新标签页</translation>
 <translation id="2286841657746966508">帐单邮寄地址</translation>
 <translation id="230115972905494466">未找到任何兼容设备</translation>
 <translation id="2315043854645842844">操作系统不支持选择客户端证书。</translation>
@@ -214,6 +220,7 @@
 <translation id="2621115761605608342">允许特定网站运行 JavaScript。</translation>
 <translation id="2625189173221582860">已复制密码</translation>
 <translation id="2631006050119455616">已节省</translation>
+<translation id="2633278372998075009">私密标签页</translation>
 <translation id="2647434099613338025">添加语言</translation>
 <translation id="2650751991977523696">是否重新下载文件?</translation>
 <translation id="2653659639078652383">提交</translation>
@@ -273,6 +280,7 @@
 <translation id="321773570071367578">如果您忘记了密码或想更改此设置,请<ph name="BEGIN_LINK" />重置同步设置<ph name="END_LINK" /></translation>
 <translation id="3227137524299004712">麦克风</translation>
 <translation id="3232754137068452469">网络应用</translation>
+<translation id="3234355010754616171">新私密标签页</translation>
 <translation id="3236059992281584593">还剩 1 分钟</translation>
 <translation id="3244271242291266297">MM</translation>
 <translation id="3254409185687681395">为此页添加书签</translation>
@@ -288,6 +296,7 @@
 <translation id="3350687908700087792">关闭所有隐身标签页</translation>
 <translation id="3365671512111106261">在流量节省程序处于开启状态时不可用</translation>
 <translation id="3367813778245106622">重新登录以开始同步</translation>
+<translation id="3377025655491224618">私密标签页</translation>
 <translation id="3384347053049321195">分享图片</translation>
 <translation id="3386292677130313581">在允许网站获悉您的位置信息前先询问(推荐)</translation>
 <translation id="3387650086002190359">未能成功下载 <ph name="FILE_NAME" />,因为文件系统出现了错误。</translation>
@@ -385,6 +394,7 @@
 <translation id="4209895695669353772">要获取 Google 推荐的个性化内容,请开启同步功能</translation>
 <translation id="4226663524361240545">收到通知时设备会振动</translation>
 <translation id="4242533952199664413">打开“设置”</translation>
+<translation id="4243710787042215766">在私密标签页中打开</translation>
 <translation id="424864128008805179">退出 Chrome?</translation>
 <translation id="4256782883801055595">开放源代码许可</translation>
 <translation id="4259722352634471385">已屏蔽 <ph name="URL" /></translation>
@@ -465,6 +475,7 @@
 <translation id="4878404682131129617">未能成功通过代理服务器建立隧道</translation>
 <translation id="4881695831933465202">打开</translation>
 <translation id="488187801263602086">重命名文件</translation>
+<translation id="4883379392681899581">退出私密模式</translation>
 <translation id="4885273946141277891">Chrome 实例数量已超出上限。</translation>
 <translation id="4910889077668685004">付款应用</translation>
 <translation id="4913161338056004800">重置统计信息</translation>
@@ -506,6 +517,7 @@
 <translation id="5224771365102442243">包含视频</translation>
 <translation id="5233638681132016545">打开新的标签页</translation>
 <translation id="5240817131241497236">Chrome 中控制同步、个性化和其他 Google 服务的设置已发生更改。这可能会影响您的当前设置。</translation>
+<translation id="5264003212305142034">您随时可以自定义<ph name="BEGIN_LINK1" />设置<ph name="END_LINK1" />。Google 可能会根据您访问的网站上的内容、您在浏览器中的活动和互动行为,为您提供个性化的 Chrome 体验和其他 Google 服务体验(例如翻译、搜索和广告)。</translation>
 <translation id="5271967389191913893">设备无法打开要下载的内容。</translation>
 <translation id="528192093759286357">从顶部向下拖动并触摸“返回”按钮,即可退出全屏模式。</translation>
 <translation id="5284584623296338184">对您的书签、历史记录、密码和其他设置所做的更改将不再同步到您的 Google 帐号。但是,您的现有数据将继续存储在您的 Google 帐号中。</translation>
@@ -591,6 +603,7 @@
 <translation id="583281660410589416">未知</translation>
 <translation id="5833397272224757657">根据您访问的网站上的内容以及您在浏览器中的活动和互动行为,提供个性化的使用体验</translation>
 <translation id="5833984609253377421">分享链接</translation>
+<translation id="584427517463557805">所选的私密标签页</translation>
 <translation id="5854790677617711513">30 天之前的</translation>
 <translation id="5858741533101922242">Chrome 无法开启蓝牙适配器</translation>
 <translation id="5860033963881614850">关闭</translation>
@@ -620,6 +633,7 @@
 <translation id="6075798973483050474">修改主页</translation>
 <translation id="60923314841986378">还剩 <ph name="HOURS" /> 小时</translation>
 <translation id="60924377787140961">我们很快将会为您奉上更多文章,伴您度过美好的午后时光!</translation>
+<translation id="6099151465289169210">已切换到私密标签页</translation>
 <translation id="6108923351542677676">正在设置…</translation>
 <translation id="6111020039983847643">已耗用的流量</translation>
 <translation id="6112702117600201073">正在刷新页面</translation>
@@ -649,6 +663,7 @@
 <translation id="6320088164292336938">振动</translation>
 <translation id="6324034347079777476">Android 系统同步功能已停用</translation>
 <translation id="6333140779060797560">通过<ph name="APPLICATION" />分享</translation>
+<translation id="6336451774241870485">新私密标签页</translation>
 <translation id="6337234675334993532">加密</translation>
 <translation id="6341580099087024258">询问文件保存位置</translation>
 <translation id="6343192674172527289">未找到任何下载内容</translation>
@@ -686,6 +701,7 @@
 <translation id="6593061639179217415">桌面版网站</translation>
 <translation id="6600954340915313787">已复制到 Chrome</translation>
 <translation id="6608650720463149374"><ph name="GIGABYTES" /> GB</translation>
+<translation id="6610147964972079463">关闭私密标签页</translation>
 <translation id="6612358246767739896">受保护的内容</translation>
 <translation id="6627583120233659107">修改文件夹</translation>
 <translation id="6643016212128521049">清除</translation>
@@ -789,6 +805,7 @@
 <translation id="7453467225369441013">您会从大多数网站退出,但不会退出自己的 Google 帐号。</translation>
 <translation id="7454641608352164238">空间不足</translation>
 <translation id="7455923816558154057">点按即可查看</translation>
+<translation id="7465104139234185284">关闭所有私密标签页</translation>
 <translation id="7473891865547856676">不,谢谢</translation>
 <translation id="7475192538862203634">如果您频繁遇到此问题,请尝试按这些<ph name="BEGIN_LINK" />建议<ph name="END_LINK" />操作。</translation>
 <translation id="7475688122056506577">找不到 SD 卡。您的某些文件可能会丢失。</translation>
@@ -884,6 +901,7 @@
 <translation id="8220488350232498290">下载内容已占用的空间:<ph name="GIGABYTES" /> GB</translation>
 <translation id="8249310407154411074">移至顶部</translation>
 <translation id="8250920743982581267">文档</translation>
+<translation id="825412236959742607">此网页占用的内存过多,因此 Chrome 移除了部分内容。</translation>
 <translation id="8260126382462817229">请尝试重新登录</translation>
 <translation id="8261506727792406068">删除</translation>
 <translation id="8266862848225348053">下载内容保存位置</translation>
@@ -979,6 +997,7 @@
 <translation id="9070377983101773829">开始语音搜索</translation>
 <translation id="9071742570345586758">要查看虚拟实境内容,请安装 Google VR 服务</translation>
 <translation id="9074336505530349563">要获取 Google 推荐的个性化内容,请登录您的帐号并开启同步功能</translation>
+<translation id="9080642952018487277">进入私密模式</translation>
 <translation id="9086455579313502267">无法访问网络</translation>
 <translation id="9099018167121903954">下载内容已占用的空间:<ph name="KILOBYTES" /> KB</translation>
 <translation id="9100505651305367705">询问是否使用简化版视图显示受支持的文章</translation>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 8288ddf..4165b00 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -169,6 +169,7 @@
   "java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityClient.java",
   "java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityDisclosure.java",
   "java/src/org/chromium/chrome/browser/browserservices/UkmRecorder.java",
+  "java/src/org/chromium/chrome/browser/browserservices/VerificationState.java",
   "java/src/org/chromium/chrome/browser/browsing_data/UrlFilters.java",
   "java/src/org/chromium/chrome/browser/childaccounts/ChildAccountFeedbackReporter.java",
   "java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java",
@@ -502,6 +503,7 @@
   "java/src/org/chromium/chrome/browser/download/home/list/ListProperties.java",
   "java/src/org/chromium/chrome/browser/download/home/list/ListPropertyViewBinder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java",
+  "java/src/org/chromium/chrome/browser/download/home/list/ShareUtils.java",
   "java/src/org/chromium/chrome/browser/download/home/list/UiUtils.java",
   "java/src/org/chromium/chrome/browser/download/home/snackbars/DeleteUndoCoordinator.java",
   "java/src/org/chromium/chrome/browser/download/home/snackbars/UndoUiUtils.java",
@@ -2171,6 +2173,7 @@
   "junit/src/org/chromium/chrome/browser/download/home/glue/FileDeletionQueueTest.java",
   "junit/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutatorTest.java",
   "junit/src/org/chromium/chrome/browser/download/home/list/ItemUtilsTest.java",
+  "junit/src/org/chromium/chrome/browser/download/home/list/ShareUtilsTest.java",
   "junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java",
   "junit/src/org/chromium/chrome/browser/download/DownloadResumptionSchedulerTest.java",
   "junit/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtilsTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 082b9b3d..a69f95a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -9,6 +9,7 @@
 import android.content.DialogInterface;
 import android.content.pm.ActivityInfo;
 import android.graphics.Point;
+import android.os.Build;
 import android.os.Debug;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
@@ -29,6 +30,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
@@ -1544,7 +1546,11 @@
     @Feature({"Android-TabSwitcher"})
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     @RetryOnFailure
-    public void testToolbarSwipeNextTabNone() throws InterruptedException, TimeoutException {
+    @DisableIf.Build(message = "crbug.com/871554", supported_abis_includes = "arm64-v8a",
+            sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP_MR1,
+            sdk_is_less_than = Build.VERSION_CODES.N)
+    public void
+    testToolbarSwipeNextTabNone() throws InterruptedException, TimeoutException {
         ChromeTabUtils.newTabFromMenu(
                 InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
         UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
index 48abc03..312eb6837 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -198,6 +198,45 @@
 
     @Test
     @SmallTest
+    public void testResumingTheAppDismissesAllInputMethods()
+            throws InterruptedException, TimeoutException {
+        mHelper.loadTestPage(false);
+        mHelper.createTestTab();
+
+        // Focus the field to bring up the accessory.
+        mHelper.clickPasswordField();
+        mHelper.waitForKeyboard();
+
+        // Click the tab to show the sheet and hide the keyboard.
+        whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
+        mHelper.waitForKeyboardToDisappear();
+        whenDisplayed(withId(R.id.keyboard_accessory_sheet));
+
+        // Simulate backgrounding the main activity.
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { mActivityTestRule.getActivity().onPauseWithNative(); });
+
+        // This should completely dismiss any input method.
+        mHelper.waitForKeyboardToDisappear();
+        mHelper.waitToBeHidden(withId(R.id.keyboard_accessory_sheet));
+        mHelper.waitToBeHidden(withId(R.id.keyboard_accessory));
+
+        // Simulate foregrounding the main activity.
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { mActivityTestRule.getActivity().onResumeWithNative(); });
+
+        // Clicking the field should bring it back up
+        mHelper.clickPasswordField();
+        mHelper.waitForKeyboard();
+
+        // Click the tab to show the sheet and hide the keyboard.
+        whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
+        mHelper.waitForKeyboardToDisappear();
+        whenDisplayed(withId(R.id.keyboard_accessory_sheet));
+    }
+
+    @Test
+    @SmallTest
     public void testPressingBackButtonHidesAccessorySheet()
             throws InterruptedException, TimeoutException {
         mHelper.loadTestPage(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
index 0db33b7d..64e17a71 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
@@ -79,6 +79,7 @@
 import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.GestureStateListener;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.RenderCoordinates;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.ui.test.util.UiRestriction;
@@ -629,6 +630,8 @@
         WebContents webContents = mActivityTestRule.getWebContents();
         GestureListenerManager.fromWebContents(webContents).addListener(gestureStateListener);
         View view = webContents.getViewAndroidDelegate().getContainerView();
+        int maxScrollOffset =
+                RenderCoordinates.fromWebContents(webContents).getMaxVerticalScrollPixInt();
 
         // Verify that suggestions are not shown before scroll.
         ThreadUtils.runOnUiThreadBlocking(
@@ -636,10 +639,10 @@
         assertEquals("Bottom sheet should be hidden before scroll.", BottomSheet.SheetState.HIDDEN,
                 mBottomSheet.getSheetState());
 
-        // Scroll the page to 30% and verify that the suggestions are not shown. The pixel to scroll
-        // is hard coded (approximately) based on the html height of the TEST_PAGE.
+        // Scroll the page to 30% and verify that the suggestions are not shown.
         int callCount = scrollChangedCallback.getCallCount();
-        ThreadUtils.runOnUiThreadBlocking(() -> view.scrollBy(0, 3000));
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> view.scrollBy(0, Math.round(maxScrollOffset * 0.3f)));
         scrollChangedCallback.waitForCallback(callCount);
 
         // Simulate call to show content without browser controls being hidden.
@@ -648,9 +651,10 @@
         assertEquals("Bottom sheet should be hidden on 30% scroll percentage.",
                 BottomSheet.SheetState.HIDDEN, mBottomSheet.getSheetState());
 
-        // Scroll the page to approximately 60% and verify that the suggestions are shown.
+        // Scroll the page 20% more for a total of 50% and verify that the suggestions are shown.
         callCount = scrollChangedCallback.getCallCount();
-        ThreadUtils.runOnUiThreadBlocking(() -> view.scrollBy(0, 3000));
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> view.scrollBy(0, Math.round(maxScrollOffset * 0.2f)));
         scrollChangedCallback.waitForCallback(callCount);
 
         // Simulate call to show content without browser controls being hidden.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
index 3ea71ea2..4ab139c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
@@ -27,6 +27,7 @@
 import org.chromium.components.offline_items_collection.OfflineItemFilter;
 import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
 import org.chromium.components.offline_items_collection.OfflineItemState;
+import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.text.SimpleDateFormat;
@@ -161,7 +162,14 @@
         }
 
         @Override
-        public void getVisualsForItem(ContentId id, VisualsCallback callback) {}
+        public void getVisualsForItem(ContentId id, VisualsCallback callback) {
+            mHandler.post(() -> callback.onVisualsAvailable(id, null));
+        }
+
+        @Override
+        public void getShareInfoForItem(ContentId id, ShareCallback callback) {
+            mHandler.post(() -> callback.onShareInfoAvailable(id, null));
+        }
     }
 
     /** Stubs out all attempts to get thumbnails for files. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index 3ee9e6b..73e09837 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -46,6 +46,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.bookmarks.BookmarkActivity;
 import org.chromium.chrome.browser.download.DownloadActivity;
+import org.chromium.chrome.browser.feed.FeedNewTabPage;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.ntp.cards.SignInPromo;
@@ -70,6 +71,7 @@
 import org.chromium.chrome.test.util.OmniboxTestUtils;
 import org.chromium.chrome.test.util.RenderTestRule;
 import org.chromium.chrome.test.util.browser.ChromeModernDesign;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.RecyclerViewTestUtils;
@@ -129,8 +131,18 @@
         }
     }
 
+    /** Parameter provider for enabling/disabling "Interest Feed Content Suggestions". */
+    public static class InterestFeedParams implements ParameterProvider {
+        @Override
+        public Iterable<ParameterSet> getParameters() {
+            return Arrays.asList(new ParameterSet().value(false).name("DisableInterestFeed"),
+                    new ParameterSet().value(true).name("EnableInterestFeed"));
+        }
+    }
+
     private static final String TEST_PAGE = "/chrome/test/data/android/navigate/simple.html";
 
+    private boolean mInterestFeedEnabled;
     private Tab mTab;
     private NewTabPage mNtp;
     private View mFakebox;
@@ -151,6 +163,17 @@
         mChromeModernProcessor.clearTestState();
     }
 
+    @ParameterAnnotations.UseMethodParameterBefore(InterestFeedParams.class)
+    public void setupInterestFeed(boolean interestFeedEnabled) {
+        mInterestFeedEnabled = interestFeedEnabled;
+        if (mInterestFeedEnabled) {
+            Features.getInstance().enable(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS);
+            FeedNewTabPage.setInTestMode(true);
+        } else {
+            Features.getInstance().disable(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS);
+        }
+    }
+
     @Before
     public void setUp() throws Exception {
         mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
@@ -199,6 +222,7 @@
     @After
     public void tearDown() throws Exception {
         mTestServer.stopAndDestroyServer();
+        if (mInterestFeedEnabled) FeedNewTabPage.setInTestMode(false);
     }
 
     @Test
@@ -235,7 +259,8 @@
     @Feature({"NewTabPage", "FeedNewTabPage"})
     @EnableFeatures({ChromeFeatureList.SIMPLIFIED_NTP})
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-    public void testSimplifiedNtp_BookmarksShortcuts() {
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testSimplifiedNtp_BookmarksShortcuts(boolean interestFeedEnabled) {
         ActivityMonitor activityMonitor = InstrumentationRegistry.getInstrumentation().addMonitor(
                 BookmarkActivity.class.getName(),
                 new Instrumentation.ActivityResult(Activity.RESULT_OK, null), true);
@@ -253,7 +278,8 @@
     @Feature({"NewTabPage", "FeedNewTabPage"})
     @EnableFeatures({ChromeFeatureList.SIMPLIFIED_NTP})
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-    public void testSimplifiedNtp_DownloadsShortcuts() {
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testSimplifiedNtp_DownloadsShortcuts(boolean interestFeedEnabled) {
         ActivityMonitor activityMonitor = InstrumentationRegistry.getInstrumentation().addMonitor(
                 DownloadActivity.class.getName(),
                 new Instrumentation.ActivityResult(Activity.RESULT_OK, null), true);
@@ -271,7 +297,9 @@
     @Feature({"NewTabPage", "FeedNewTabPage"})
     @EnableFeatures({ChromeFeatureList.SIMPLIFIED_NTP})
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-    public void testSimplifiedNtp_DefaultSearchEngineChange() throws Exception {
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testSimplifiedNtp_DefaultSearchEngineChange(boolean interestFeedEnabled)
+            throws Exception {
         View logo = mNtp.getView().findViewById(R.id.search_provider_logo);
         View shortcuts = mNtp.getView().findViewById(R.id.shortcuts);
         Assert.assertEquals(View.VISIBLE, logo.getVisibility());
@@ -381,7 +409,7 @@
      */
     @Test
     @SmallTest
-    @Feature({"NewTabPage", "FeedNewTabPage"})
+    @Feature({"NewTabPage"})
     public void testClickMostVisitedItem() throws InterruptedException {
         ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() {
             @Override
@@ -412,7 +440,8 @@
     @Test
     @SmallTest
     @Feature({"NewTabPage", "FeedNewTabPage"})
-    public void testOpenMostVisitedItemInIncognitoTab()
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testOpenMostVisitedItemInIncognitoTab(boolean interestFeedEnabled)
             throws InterruptedException, ExecutionException {
         ChromeTabUtils.invokeContextMenuAndOpenInANewTab(mActivityTestRule,
                 mTileGridLayout.getChildAt(0),
@@ -426,7 +455,8 @@
     @Test
     @SmallTest
     @Feature({"NewTabPage", "FeedNewTabPage"})
-    public void testRemoveMostVisitedItem() throws ExecutionException {
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testRemoveMostVisitedItem(boolean interestFeedEnabled) throws ExecutionException {
         SiteSuggestion testSite = mSiteSuggestions.get(0);
         View mostVisitedItem = mTileGridLayout.getChildAt(0);
         ArrayList<View> views = new ArrayList<>();
@@ -443,7 +473,7 @@
 
     @Test
     @MediumTest
-    @Feature({"NewTabPage", "FeedNewTabPage"})
+    @Feature({"NewTabPage"})
     public void testUrlFocusAnimationsDisabledOnLoad() throws InterruptedException {
         Assert.assertFalse(getUrlFocusAnimationsDisabled());
         ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() {
@@ -468,7 +498,7 @@
 
     @Test
     @LargeTest
-    @Feature({"NewTabPage", "FeedNewTabPage"})
+    @Feature({"NewTabPage"})
     public void testUrlFocusAnimationsEnabledOnFailedLoad() throws Exception {
         // TODO(jbudorick): switch this to EmbeddedTestServer.
         TestWebServer webServer = TestWebServer.start();
@@ -536,7 +566,8 @@
     @Test
     @SmallTest
     @Feature({"NewTabPage", "FeedNewTabPage"})
-    public void testSetSearchProviderInfo() throws Throwable {
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testSetSearchProviderInfo(boolean interestFeedEnabled) throws Throwable {
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -558,7 +589,8 @@
     @Test
     @SmallTest
     @Feature({"NewTabPage", "FeedNewTabPage"})
-    public void testPlaceholder() {
+    @ParameterAnnotations.UseMethodParameter(InterestFeedParams.class)
+    public void testPlaceholder(boolean interestFeedEnabled) {
         final NewTabPageLayout ntpLayout = mNtp.getNewTabPageLayout();
         final View logoView = ntpLayout.findViewById(R.id.search_provider_logo);
         final View searchBoxView = ntpLayout.findViewById(R.id.search_box);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/snackbar/SnackbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/snackbar/SnackbarTest.java
index 3c2f67b..5c739ff 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/snackbar/SnackbarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/snackbar/SnackbarTest.java
@@ -23,6 +23,8 @@
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for {@link SnackbarManager}.
  */
@@ -65,11 +67,13 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testStackQueueOrder() {
+    public void testStackQueuePersistentOrder() {
         final Snackbar stackbar = Snackbar.make("stack", mDefaultController,
                 Snackbar.TYPE_ACTION, Snackbar.UMA_TEST_SNACKBAR);
         final Snackbar queuebar = Snackbar.make("queue", mDefaultController,
                 Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_TEST_SNACKBAR);
+        final Snackbar persistent = Snackbar.make("persistent", mDefaultController,
+                Snackbar.TYPE_PERSISTENT, Snackbar.UMA_TEST_SNACKBAR);
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -88,8 +92,18 @@
                 mManager.showSnackbar(queuebar);
                 Assert.assertTrue("Snackbar not showing", mManager.isShowing());
                 Assert.assertEquals(
-                        "Snackbars on stack should not be cancled by snackbars on queue", stackbar,
-                        mManager.getCurrentSnackbarForTesting());
+                        "Snackbars on stack should not be cancelled by snackbars on queue",
+                        stackbar, mManager.getCurrentSnackbarForTesting());
+            }
+        });
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mManager.showSnackbar(persistent);
+                Assert.assertTrue("Snackbar not showing", mManager.isShowing());
+                Assert.assertEquals(
+                        "Snackbars on stack should not be cancelled by persistent snackbars",
+                        stackbar, mManager.getCurrentSnackbarForTesting());
             }
         });
         CriteriaHelper.pollUiThread(new Criteria("Snackbar on queue not shown") {
@@ -98,7 +112,15 @@
                 return mManager.isShowing() && mManager.getCurrentSnackbarForTesting() == queuebar;
             }
         });
-        CriteriaHelper.pollUiThread(new Criteria("Snackbar did not time out") {
+        CriteriaHelper.pollUiThread(new Criteria("Snackbar on queue not timed out") {
+            @Override
+            public boolean isSatisfied() {
+                return mManager.isShowing()
+                        && mManager.getCurrentSnackbarForTesting() == persistent;
+            }
+        });
+        ThreadUtils.runOnUiThread(() -> mManager.onClick(null));
+        CriteriaHelper.pollUiThread(new Criteria("Persistent snackbar did not get cleared") {
             @Override
             public boolean isSatisfied() {
                 return !mManager.isShowing();
@@ -109,18 +131,34 @@
     @Test
     @SmallTest
     @RetryOnFailure
-    public void testQueueStackOrder() {
+    public void testPersistentQueueStackOrder() {
         final Snackbar stackbar = Snackbar.make("stack", mDefaultController,
                 Snackbar.TYPE_ACTION, Snackbar.UMA_TEST_SNACKBAR);
         final Snackbar queuebar = Snackbar.make("queue", mDefaultController,
                 Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_TEST_SNACKBAR);
+        final Snackbar persistent = Snackbar.make("persistent", mDefaultController,
+                Snackbar.TYPE_PERSISTENT, Snackbar.UMA_TEST_SNACKBAR);
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mManager.showSnackbar(persistent);
+            }
+        });
+        CriteriaHelper.pollUiThread(new Criteria("First snackbar not shown") {
+            @Override
+            public boolean isSatisfied() {
+                return mManager.isShowing()
+                        && mManager.getCurrentSnackbarForTesting() == persistent;
+            }
+        });
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mManager.showSnackbar(queuebar);
             }
         });
-        CriteriaHelper.pollUiThread(new Criteria("First snackbar not shown") {
+        CriteriaHelper.pollUiThread(new Criteria(
+                "Persistent snackbar was not cleared by queue snackbar") {
             @Override
             public boolean isSatisfied() {
                 return mManager.isShowing() && mManager.getCurrentSnackbarForTesting() == queuebar;
@@ -143,6 +181,14 @@
         CriteriaHelper.pollUiThread(new Criteria("Snackbar did not time out") {
             @Override
             public boolean isSatisfied() {
+                return mManager.isShowing()
+                        && mManager.getCurrentSnackbarForTesting() == persistent;
+            }
+        });
+        ThreadUtils.runOnUiThread(() -> mManager.onClick(null));
+        CriteriaHelper.pollUiThread(new Criteria("Persistent snackbar did not get cleared") {
+            @Override
+            public boolean isSatisfied() {
                 return !mManager.isShowing();
             }
         });
@@ -181,4 +227,35 @@
             }
         });
     }
+
+    @Test
+    @SmallTest
+    public void testPersistentSnackbar() throws InterruptedException {
+        int timeout = 100;
+        SnackbarManager.setDurationForTesting(timeout);
+        final Snackbar snackbar = Snackbar.make("persistent", mDismissController,
+                Snackbar.TYPE_PERSISTENT, Snackbar.UMA_TEST_SNACKBAR);
+        mDismissed = false;
+        ThreadUtils.runOnUiThread(() -> mManager.showSnackbar(snackbar));
+        CriteriaHelper.pollUiThread(new Criteria("Persistent Snackbar not shown.") {
+            @Override
+            public boolean isSatisfied() {
+                return mManager.isShowing() && mManager.getCurrentSnackbarForTesting() == snackbar;
+            }
+        });
+        TimeUnit.MILLISECONDS.sleep(timeout);
+        CriteriaHelper.pollUiThread(new Criteria("Persistent snackbar timed out.") {
+            @Override
+            public boolean isSatisfied() {
+                return mManager.isShowing() && !mDismissed;
+            }
+        });
+        ThreadUtils.runOnUiThread(() -> mManager.onClick(null));
+        CriteriaHelper.pollUiThread(new Criteria("Persistent snackbar not removed on action.") {
+            @Override
+            public boolean isSatisfied() {
+                return !mManager.isShowing();
+            }
+        });
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedVrController.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedVrController.java
index 62021ed..78e7ea34 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedVrController.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedVrController.java
@@ -24,17 +24,38 @@
  */
 public class EmulatedVrController {
     public enum ScrollDirection { UP, DOWN, LEFT, RIGHT }
+    private static final int FIRST_INPUT_DELAY_MS = 500;
     private final ControllerTestApi mApi;
+    private boolean mHaveSentInputSinceEnteringVr;
 
     public EmulatedVrController(Context context) {
         mApi = new ControllerTestApi(context);
     }
 
     public ControllerTestApi getApi() {
+        // We flakily disconnect and reconnect the controller immediately after VR entry, which can
+        // cause controller input to get eaten. Sleeping a bit after VR entry fixes this, so instead
+        // of adding a bunch of sleeps everywhere, sleep for a bit before sending the first input
+        // after VR entry.
+        // TODO(https://crbug.com/870031): Remove this sleep if/when the controller disconnect/
+        // reconnect issue caused by DON flow skipping that flakily eats controller input is
+        // resolved.
+        if (!mHaveSentInputSinceEnteringVr) {
+            SystemClock.sleep(FIRST_INPUT_DELAY_MS);
+            mHaveSentInputSinceEnteringVr = true;
+        }
         return mApi;
     }
 
     /**
+     * Resets the flag used to keep track of whether we have sent input since entering VR. Should
+     * be called anytime the emulated controller is used and a test re-enters VR.
+     */
+    public void resetFirstInputFlag() {
+        mHaveSentInputSinceEnteringVr = false;
+    }
+
+    /**
      * Touch and release the touchpad to perform a controller click.
      */
     public void performControllerClick() {
@@ -50,7 +71,7 @@
      * the button is currently pressed or not.
      */
     public void sendClickButtonToggleEvent() {
-        mApi.buttonEvent.sendClickButtonToggleEvent();
+        getApi().buttonEvent.sendClickButtonToggleEvent();
     }
 
     /**
@@ -58,7 +79,7 @@
      * Or, if the button is already pressed, releases and quickly presses again.
      */
     public void pressReleaseTouchpadButton() {
-        mApi.buttonEvent.sendClickButtonEvent();
+        getApi().buttonEvent.sendClickButtonEvent();
     }
 
     /**
@@ -66,7 +87,7 @@
      * Or, if the button is already pressed, releases and quickly presses again.
      */
     public void pressReleaseAppButton() {
-        mApi.buttonEvent.sendAppButtonEvent();
+        getApi().buttonEvent.sendAppButtonEvent();
     }
 
     /**
@@ -74,22 +95,22 @@
      * orientation quaternion.
      */
     public void recenterView() {
-        mApi.buttonEvent.sendHomeButtonToggleEvent();
+        getApi().buttonEvent.sendHomeButtonToggleEvent();
         // A valid position must be sent a short time after the home button
         // is pressed in order for recentering to actually complete, and no
         // way to be signalled that we should send the event, so sleep
         SystemClock.sleep(500);
         // We don't care where the controller is pointing when recentering occurs as long
         // as it results in a successful recenter, so send an arbitrary, valid orientation
-        mApi.moveEvent.sendMoveEvent(0.0f, 0.0f, 0.0f, 1.0f);
-        mApi.buttonEvent.sendHomeButtonToggleEvent();
+        getApi().moveEvent.sendMoveEvent(0.0f, 0.0f, 0.0f, 1.0f);
+        getApi().buttonEvent.sendHomeButtonToggleEvent();
     }
 
     /**
      * Performs a short home button press/release, which launches the Daydream Home app.
      */
     public void goToDaydreamHome() {
-        mApi.buttonEvent.sendShortHomeButtonEvent();
+        getApi().buttonEvent.sendShortHomeButtonEvent();
     }
 
     /**
@@ -140,7 +161,7 @@
         int delay = 500;
         long simulatedDelay = TimeUnit.MILLISECONDS.toNanos(delay);
         long timestamp = mApi.touchEvent.startTouchSequence(0.5f, 0.5f, simulatedDelay, delay);
-        mApi.touchEvent.endTouchSequence(0.5f, 0.5f, timestamp, simulatedDelay, delay);
+        getApi().touchEvent.endTouchSequence(0.5f, 0.5f, timestamp, simulatedDelay, delay);
     }
 
     /**
@@ -164,7 +185,7 @@
         long timestamp = mApi.touchEvent.startTouchSequence(xStart, yStart, simulatedDelay, speed);
         timestamp = mApi.touchEvent.dragFromTo(
                 xStart, yStart, xEnd, yEnd, steps, timestamp, simulatedDelay, speed);
-        mApi.touchEvent.endTouchSequence(xEnd, yEnd, timestamp, simulatedDelay, speed);
+        getApi().touchEvent.endTouchSequence(xEnd, yEnd, timestamp, simulatedDelay, speed);
     }
 
     /**
@@ -176,7 +197,7 @@
      * @param w the w component of the quaternion.
      */
     public void moveControllerInstant(float x, float y, float z, float w) {
-        mApi.moveEvent.sendMoveEvent(x, y, z, w, 0);
+        getApi().moveEvent.sendMoveEvent(x, y, z, w, 0);
     }
 
     /**
@@ -192,7 +213,7 @@
         if (startAngles.length != 3 || endAngles.length != 3) {
             throw new IllegalArgumentException("Angle arrays must be length 3");
         }
-        mApi.moveEvent.sendMoveEvent(new float[] {startAngles[0], endAngles[0]},
+        getApi().moveEvent.sendMoveEvent(new float[] {startAngles[0], endAngles[0]},
                 new float[] {startAngles[1], endAngles[1]},
                 new float[] {startAngles[2], endAngles[2]}, steps, delayBetweenSteps);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
index 18796fc2..d2b0952 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
@@ -25,6 +25,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.StrictModeContext;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Restriction;
@@ -48,6 +49,7 @@
 import org.chromium.content.browser.test.util.JavaScriptUtils;
 
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * End-to-end tests for state transitions in VR, e.g. exiting WebVR presentation
@@ -503,4 +505,30 @@
                     VrShellDelegate.EXIT_VR_RESULT, Activity.RESULT_OK, null);
         });
     }
+
+    /**
+     * Verifies that we fail to enter VR when Async Reprojection fails to be turned on with a
+     * Daydream View headset paired.
+     */
+    @Test
+    @Restriction({RESTRICTION_TYPE_VIEWER_DAYDREAM})
+    @MediumTest
+    public void testVrUnsupportedWhenReprojectionFails() throws InterruptedException {
+        AtomicBoolean failed = new AtomicBoolean(false);
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            try (StrictModeContext smc = StrictModeContext.allowDiskWrites()) {
+                VrShell vrShell = new VrShell(
+                        mTestRule.getActivity(), VrShellDelegateUtils.getDelegateInstance(), null) {
+                    @Override
+                    public boolean setAsyncReprojectionEnabled(boolean enabled) {
+                        return false;
+                    }
+                };
+            } catch (VrShellDelegate.VrUnsupportedException e) {
+                failed.set(true);
+            }
+        });
+        Assert.assertTrue(
+                "Creating VrShell didn't fail when Async Reprojection failed.", failed.get());
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
index b00f5a5..c20aaeb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
@@ -386,10 +386,6 @@
             throws InterruptedException {
         framework.loadUrlAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S);
         framework.enterSessionWithUserGestureOrFail();
-        // TODO(https://crbug.com/870031): Remove this sleep if/when the controller disconnect/
-        // reconnect issue caused by DON flow skipping that flakily eats the app button press is
-        // resolved.
-        SystemClock.sleep(500);
         EmulatedVrController controller = new EmulatedVrController(mTestRule.getActivity());
         controller.pressReleaseAppButton();
         assertAppButtonEffect(true /* shouldHaveExited */, framework);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
index 37dfeee..c5ca59b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -8,6 +8,7 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -284,9 +285,100 @@
         assertThat(keyboardAccessoryModel.getActionList().size(), is(0));
     }
 
-    // TODO(fhorschig): Test that updating tab1 works if tab2 is active.
-    // TODO(fhorschig): Test that destroying a tab cleans the model.
-    // TODO(fhorschig): Test that unregistering a provider affects only one tab.
+    @Test
+    public void testUpdatesInactiveAccessory() {
+        ManualFillingMediator mediator = mController.getMediatorForTesting();
+        KeyboardAccessoryModel keyboardAccessoryModel =
+                mediator.getKeyboardAccessory().getMediatorForTesting().getModelForTesting();
+
+        // Open a tab.
+        Tab tab = addTab(mediator, 1111, null);
+        // Add an action provider that hasn't provided actions yet.
+        PropertyProvider<Action> delayedProvider = new PropertyProvider<>();
+        mController.registerActionProvider(delayedProvider);
+        assertThat(keyboardAccessoryModel.getActionList().size(), is(0));
+
+        // Create and switch to a new tab:
+        Tab secondTab = addTab(mediator, 1111, tab);
+        PropertyProvider<Action> provider = new PropertyProvider<>();
+        mController.registerActionProvider(provider);
+
+        // And provide data to the active tab.
+        provider.notifyObservers(new Action[] {
+                new Action("Test Action", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
+        // Now, have the delayed provider provide data for the backgrounded tab.
+        delayedProvider.notifyObservers(
+                new Action[] {new Action("Delayed", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
+
+        // The current tab should not be influenced by the delayed provider.
+        assertThat(keyboardAccessoryModel.getActionList().size(), is(1));
+        assertThat(keyboardAccessoryModel.getActionList().get(0).getCaption(), is("Test Action"));
+
+        // Switching tabs back should only show the action that was received in the background.
+        switchTab(mediator, secondTab, tab);
+        assertThat(keyboardAccessoryModel.getActionList().size(), is(1));
+        assertThat(keyboardAccessoryModel.getActionList().get(0).getCaption(), is("Delayed"));
+    }
+
+    @Test
+    public void testDestroyingTabCleansModelForThisTab() {
+        ManualFillingMediator mediator = mController.getMediatorForTesting();
+        KeyboardAccessoryModel keyboardAccessoryModel =
+                mediator.getKeyboardAccessory().getMediatorForTesting().getModelForTesting();
+        AccessorySheetModel accessorySheetModel = mController.getMediatorForTesting()
+                                                          .getAccessorySheet()
+                                                          .getMediatorForTesting()
+                                                          .getModelForTesting();
+
+        Provider<Item> firstTabProvider = new PropertyProvider<>();
+        PropertyProvider<Action> firstActionProvider = new PropertyProvider<>();
+        Provider<Item> secondTabProvider = new PropertyProvider<>();
+        PropertyProvider<Action> secondActionProvider = new PropertyProvider<>();
+
+        // Simulate opening a new tab:
+        Tab firstTab = addTab(mediator, 1111, null);
+        mController.registerPasswordProvider(firstTabProvider);
+        mController.registerActionProvider(firstActionProvider);
+        firstTabProvider.notifyObservers(new Item[] {
+                Item.createSuggestion("FirstPassword", "FirstPassword", true, result -> {}, null)});
+        firstActionProvider.notifyObservers(new Action[] {
+                new Action("2BDestroyed", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
+
+        // Create and switch to a new tab: (because destruction shouldn't rely on tab to be active)
+        addTab(mediator, 2222, firstTab);
+        mController.registerPasswordProvider(secondTabProvider);
+        mController.registerActionProvider(secondActionProvider);
+        secondTabProvider.notifyObservers(new Item[] {Item.createSuggestion(
+                "SecondPassword", "SecondPassword", true, result -> {}, null)});
+        secondActionProvider.notifyObservers(
+                new Action[] {new Action("2BKept", GENERATE_PASSWORD_AUTOMATIC, (action) -> {})});
+
+        // The current tab should be valid.
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(1));
+        assertThat(accessorySheetModel.getTabList().size(), is(1));
+        assertThat(keyboardAccessoryModel.getActionList().size(), is(1));
+        assertThat(keyboardAccessoryModel.getActionList().get(0).getCaption(), is("2BKept"));
+
+        // Request destruction of the first Tab:
+        mediator.getTabObserverForTesting().onDestroyed(firstTab);
+
+        // The current tab should not be influenced by the destruction.
+        assertThat(keyboardAccessoryModel.getTabList().size(), is(1));
+        assertThat(accessorySheetModel.getTabList().size(), is(1));
+        assertThat(keyboardAccessoryModel.getActionList().size(), is(1));
+        assertThat(keyboardAccessoryModel.getActionList().get(0).getCaption(), is("2BKept"));
+
+        // The other tabs data should be gone.
+        ManualFillingMediator.AccessoryState oldState = mediator.getModelForTesting().get(firstTab);
+        if (oldState == null)
+            return; // Having no state is fine - it would be completely destroyed then.
+
+        assertThat(oldState.mActionsProvider, nullValue());
+
+        if (oldState.mPasswordAccessorySheet == null)
+            return; // Having no password sheet is fine - it would be completely destroyed then.
+        assertThat(oldState.mPasswordAccessorySheet.getModelForTesting().size(), is(0));
+    }
 
     /**
      * Creates a tab and calls the observer events as if it was just created and switched to.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/ShareUtilsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/ShareUtilsTest.java
new file mode 100644
index 0000000..4cf3c75
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/list/ShareUtilsTest.java
@@ -0,0 +1,176 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.download.home.list;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.util.Pair;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.CollectionUtil;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
+
+/** Unit tests for the ShareUtils class. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ShareUtilsTest {
+    @Test
+    public void testNoContent() {
+        Assert.assertNull(ShareUtils.createIntent(CollectionUtil.newArrayList()));
+        Assert.assertNull(ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem(null, "text/plain", "", null), createItem("", "text/plain", "", ""))));
+    }
+
+    @Test
+    public void testAction() {
+        Intent intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null)));
+        Assert.assertEquals(Intent.ACTION_SEND, intent.getAction());
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.chrome.com", "text/plain", "", null)));
+        Assert.assertEquals(Intent.ACTION_SEND, intent.getAction());
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("", "text/plain", "", "http://www.chrome.com")));
+        Assert.assertEquals(Intent.ACTION_SEND_MULTIPLE, intent.getAction());
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("", "text/plain", "", "http://www.google.com"),
+                createItem("", "text/plain", "", "http://www.chrome.com")));
+        Assert.assertEquals(Intent.ACTION_SEND_MULTIPLE, intent.getAction());
+    }
+
+    @Test
+    public void testFlags() {
+        Intent intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null)));
+        Assert.assertNotEquals(0, intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    @Test
+    public void testExtraText() {
+        Intent intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null)));
+        Assert.assertEquals("http://www.google.com", intent.getStringExtra(Intent.EXTRA_TEXT));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.chrome.com", "text/plain", "", "http://www.chrome.com")));
+        Assert.assertEquals("http://www.google.com", intent.getStringExtra(Intent.EXTRA_TEXT));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.chrome.com", "text/plain", "", null)));
+        Assert.assertEquals("http://www.google.com\nhttp://www.chrome.com",
+                intent.getStringExtra(Intent.EXTRA_TEXT));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("", "text/plain", "", "http://www.google.com")));
+        Assert.assertFalse(intent.hasExtra(Intent.EXTRA_TEXT));
+    }
+
+    @Test
+    public void testExtraSubject() {
+        Intent intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "title", null)));
+        Assert.assertEquals("title", intent.getStringExtra(Intent.EXTRA_SUBJECT));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "title1", null),
+                createItem(
+                        "http://www.chrome.com", "text/plain", "title2", "http://www.chrome.com")));
+        Assert.assertFalse(intent.hasExtra(Intent.EXTRA_SUBJECT));
+    }
+
+    @Test
+    public void testExtraStream() {
+        Intent intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null)));
+        Assert.assertFalse(intent.hasExtra(Intent.EXTRA_STREAM));
+        Assert.assertNull(intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("", "text/plain", "", "http://www.google.com")));
+        Assert.assertEquals(
+                Uri.parse("http://www.google.com"), intent.getParcelableExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", "http://www.google.com")));
+        Assert.assertEquals(
+                Uri.parse("http://www.google.com"), intent.getParcelableExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("", "text/plain", "", "http://www.google.com"),
+                createItem("http://www.chrome.com", "text/plain", "", "")));
+        Assert.assertEquals(
+                Uri.parse("http://www.google.com"), intent.getParcelableExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("", "text/plain", "", "http://www.google.com"),
+                createItem("http://www.chrome.com", "text/plain", "", "http://www.chrome.com")));
+        Assert.assertEquals(CollectionUtil.newArrayList(Uri.parse("http://www.google.com"),
+                                    Uri.parse("http://www.chrome.com")),
+                intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("", "text/plain", "", "http://www.google.com"),
+                createItem("", "text/plain", "", "http://www.chrome.com")));
+        Assert.assertEquals(CollectionUtil.newArrayList(Uri.parse("http://www.google.com"),
+                                    Uri.parse("http://www.chrome.com")),
+                intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null)));
+        Assert.assertFalse(intent.hasExtra(Intent.EXTRA_STREAM));
+        Assert.assertNull(intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM));
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.chrome.com", "text/plain", "", null)));
+        Assert.assertFalse(intent.hasExtra(Intent.EXTRA_STREAM));
+        Assert.assertNull(intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM));
+    }
+
+    @Test
+    public void testType() {
+        Intent intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null)));
+        Assert.assertEquals(Intent.normalizeMimeType("text/plain"), intent.getType());
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.google.com", "text/html", "", null),
+                createItem("http://www.google.com", "text/html", "", null)));
+        Assert.assertEquals(Intent.normalizeMimeType("text/*"), intent.getType());
+
+        intent = ShareUtils.createIntent(CollectionUtil.newArrayList(
+                createItem("http://www.google.com", "text/plain", "", null),
+                createItem("http://www.google.com", "application/octet-stream", "", null)));
+        Assert.assertEquals(Intent.normalizeMimeType("*/*"), intent.getType());
+    }
+
+    private static Pair<OfflineItem, OfflineItemShareInfo> createItem(
+            String pageUrl, String mimeType, String title, String uri) {
+        OfflineItem item = new OfflineItem();
+        item.pageUrl = pageUrl;
+        item.mimeType = mimeType;
+        item.title = title;
+
+        OfflineItemShareInfo info = new OfflineItemShareInfo();
+        if (uri != null) info.uri = Uri.parse(uri);
+
+        return Pair.create(item, info);
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java
index 4b8cfff..c5b1855 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java
@@ -272,6 +272,7 @@
             {
                 add(buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS));
                 add(buildOfflineItem(new ContentId("2", "B"), OfflineItemState.PENDING));
+                add(buildOfflineItem(new ContentId("3", "C"), OfflineItemState.COMPLETE));
                 add(buildOfflineItem(new ContentId("5", "E"), OfflineItemState.INTERRUPTED));
                 add(buildOfflineItem(new ContentId("7", "G"), OfflineItemState.PAUSED));
             }
@@ -279,7 +280,6 @@
 
         ArrayList<OfflineItem> uninterestingItems = new ArrayList<OfflineItem>() {
             {
-                add(buildOfflineItem(new ContentId("3", "C"), OfflineItemState.COMPLETE));
                 add(buildOfflineItem(new ContentId("6", "F"), OfflineItemState.FAILED));
             }
         };
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
index 964763a..c819328 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -441,6 +441,13 @@
         assertNull(snippets.get(0).getOfflinePageOfflineId());
         assertEquals(Long.valueOf(1L), snippets.get(1).getOfflinePageOfflineId());
         assertEquals(Long.valueOf(2L), snippets.get(2).getOfflinePageOfflineId());
+
+        // TODO(bauerb): Once this code switches away from partial bind callbacks in favor of
+        // property keys, verify that this is an offline badge update.
+        verify(mObserver).onItemRangeChanged(
+                eq(section), eq(0), eq(1), any(PartialBindCallback.class));
+        verify(mObserver).onItemRangeChanged(
+                eq(section), eq(2), eq(1), any(PartialBindCallback.class));
     }
 
     @Test
@@ -476,6 +483,45 @@
 
     @Test
     @Feature({"Ntp"})
+    public void testOfflineStatusIgnoredIfSuggestionRemoved() {
+        final List<SnippetArticle> suggestions =
+                mSuggestionsSource.createAndSetSuggestions(2, TEST_CATEGORY_ID);
+        assertNull(suggestions.get(0).getOfflinePageOfflineId());
+        assertNull(suggestions.get(1).getOfflinePageOfflineId());
+
+        final OfflinePageItem item0 = createOfflinePageItem(suggestions.get(0).mUrl, 0L);
+        mBridge.setIsOfflinePageModelLoaded(true);
+        mBridge.setItems(Collections.singletonList(item0));
+
+        SuggestionsSection section = createSectionWithSuggestions(suggestions);
+
+        // The offline status should propagate.
+        assertEquals(Long.valueOf(0L), suggestions.get(0).getOfflinePageOfflineId());
+        assertNull(suggestions.get(1).getOfflinePageOfflineId());
+
+        // Let the fake bridge answer requests asynchronously.
+        mBridge.setAnswersRequestsImmediately(false);
+        final OfflinePageItem item1 = createOfflinePageItem(suggestions.get(1).mUrl, 1L);
+        mBridge.setItems(Arrays.asList(item0, item1));
+        mBridge.fireOfflinePageModelLoaded();
+
+        // Remove a suggestion while an OfflinePageItem callback is in progress.
+        section.removeSuggestionById(suggestions.get(1).mIdWithinCategory);
+        assertEquals(section.getSuggestionsCount(), 1);
+
+        // Reset any previous change notifications.
+        // TODO(bauerb): Once this code switches away from partial bind callbacks in favor of
+        // property keys, we can distinguish the offline badge update from others.
+        Mockito.<ListObserver>reset(mObserver);
+        mBridge.answerAllRequests();
+
+        // The offline status should not change.
+        assertNull(suggestions.get(1).getOfflinePageOfflineId());
+        verify(mObserver, never()).onItemRangeChanged(any(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    @Feature({"Ntp"})
     public void testViewAllAction() {
         // When all the actions are enabled, ViewAll always has the priority and is shown.
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java
index 80e8d51f..5c88aa3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java
@@ -82,6 +82,11 @@
     public void urlDataComparison_equals() {
         Assert.assertTrue(UrlBarMediator.isNewTextEquivalentToExistingText(null, null));
 
+        // Empty display text, regardless of spanned state.
+        Assert.assertTrue(UrlBarMediator.isNewTextEquivalentToExistingText(
+                UrlBarData.create(null, spannable(""), 0, 0, null),
+                UrlBarData.create(null, "", 0, 0, null)));
+
         // No editing text, equal display text
         Assert.assertTrue(UrlBarMediator.isNewTextEquivalentToExistingText(
                 UrlBarData.create(null, spannable("Test"), 0, 0, null),
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 0342213..c605f388 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-70.0.3515.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-70.0.3510.3_rc-r1.afdo.bz2
diff --git a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
index 01966fd..e060f056 100644
--- a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
+++ b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
@@ -22,6 +22,8 @@
     public static final String ORIENTATION = "org.chromium.webapk.shell_apk.orientation";
     public static final String THEME_COLOR = "org.chromium.webapk.shell_apk.themeColor";
     public static final String BACKGROUND_COLOR = "org.chromium.webapk.shell_apk.backgroundColor";
+    public static final String HAS_LARGE_SPLASH_ICONS =
+            "org.chromium.webapk.shell_apk.hasLargeSplashIcons";
     public static final String ICON_ID = "org.chromium.webapk.shell_apk.iconId";
     public static final String SPLASH_ID = "org.chromium.webapk.shell_apk.splashId";
 
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 85b920a..4d9094a 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -65,6 +65,7 @@
         <meta-data android:name="org.chromium.webapk.shell_apk.orientation" android:value="{{{orientation}}}" />
         <meta-data android:name="org.chromium.webapk.shell_apk.themeColor" android:value="{{{theme_color}}}" />
         <meta-data android:name="org.chromium.webapk.shell_apk.backgroundColor" android:value="{{{background_color}}}" />
+        <meta-data android:name="org.chromium.webapk.shell_apk.hasLargeSplashIcons" android:value="{{{has_large_splash_icons}}}" />
         <meta-data android:name="org.chromium.webapk.shell_apk.iconId" android:resource="@mipmap/app_icon" />
         <meta-data android:name="org.chromium.webapk.shell_apk.splashId" android:resource="@drawable/splash_icon" />
 
diff --git a/chrome/android/webapk/shell_apk/bound_manifest_config.json b/chrome/android/webapk/shell_apk/bound_manifest_config.json
index 71e78be..51be5688 100644
--- a/chrome/android/webapk/shell_apk/bound_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/bound_manifest_config.json
@@ -12,6 +12,7 @@
   "orientation": "portrait",
   "theme_color": "2147483648L",
   "background_color": "2147483648L",
+  "has_large_splash_icons": "false",
   "icon_urls_and_icon_murmur2_hashes": "http://www.pwa.rocks/icon1.png 0 http://www.pwa.rocks/icon2.png 0",
   "web_manifest_url": "https://pwa.rocks/pwa.webmanifest",
   "version_code": "1",
diff --git a/chrome/android/webapk/shell_apk/http_manifest_config.json b/chrome/android/webapk/shell_apk/http_manifest_config.json
index 1b0c9b68..044c4cd 100644
--- a/chrome/android/webapk/shell_apk/http_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/http_manifest_config.json
@@ -12,6 +12,7 @@
   "orientation": "portrait",
   "theme_color": "2147483648L",
   "background_color": "2147483648L",
+  "has_large_splash_icons": "false",
   "icon_urls_and_icon_murmur2_hashes": "http://www.pwa.rocks/icon1.png 0 http://www.pwa.rocks/icon2.png 0",
   "web_manifest_url": "https://pwa.rocks/pwa.webmanifest",
   "version_code": "1",
diff --git a/chrome/android/webapk/shell_apk/javatest_manifest_config.json b/chrome/android/webapk/shell_apk/javatest_manifest_config.json
index ceff57a..ffe8699b 100644
--- a/chrome/android/webapk/shell_apk/javatest_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/javatest_manifest_config.json
@@ -12,6 +12,7 @@
   "orientation": "portrait",
   "theme_color": "2147483648L",
   "background_color": "2147483648L",
+  "has_large_splash_icons": "false",
   "icon_urls_and_icon_murmur2_hashes": "http://www.pwa.rocks/icon1.png 0 http://www.pwa.rocks/icon2.png 0",
   "web_manifest_url": "https://pwa.rocks/pwa.webmanifest",
   "version_code": "1",
diff --git a/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java b/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java
index 3807ec4..131fbc98 100644
--- a/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java
+++ b/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java
@@ -27,6 +27,7 @@
 import org.chromium.base.FileUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.webapk.shell_apk.test.dex_optimizer.IDexOptimizerService;
 
@@ -139,6 +140,7 @@
     @Test
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT)
+    @DisabledTest(message = "crbug.com/871920")
     public void testLoadFromRemoteDataDir() {
         // Extract the dex file into another app's data directory and optimize the dex.
         String remoteDexFilePath = null;
diff --git a/chrome/android/webapk/shell_apk/maps_go_manifest_config.json b/chrome/android/webapk/shell_apk/maps_go_manifest_config.json
index 8008969..d9ac66a 100644
--- a/chrome/android/webapk/shell_apk/maps_go_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/maps_go_manifest_config.json
@@ -12,6 +12,7 @@
   "orientation": "portrait",
   "theme_color": "2147483648L",
   "background_color": "2147483648L",
+  "has_large_splash_icons": "false",
   "icon_urls_and_icon_murmur2_hashes": "https://maps.gstatic.com/mapfiles/maps_lite/pwa/icons/maps_pwa_icon_v0920_48x48.png 0 https://maps.gstatic.com/mapfiles/maps_lite/pwa/icons/maps_pwa_icon_v0920_72x72 0",
   "web_manifest_url": "https://maps.gstatic.com/tactile/worker/ml.json",
   "version_code": "1",
diff --git a/chrome/android/webapk/shell_apk/res/drawable-hdpi/splash_icon.xml b/chrome/android/webapk/shell_apk/res/drawable-hdpi/splash_icon.xml
deleted file mode 100644
index 0ea2a6b..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-hdpi/splash_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/drawable-mdpi/splash_icon.xml b/chrome/android/webapk/shell_apk/res/drawable-mdpi/splash_icon.xml
deleted file mode 100644
index 5e65be53..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-mdpi/splash_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/drawable-xhdpi/splash_icon.xml b/chrome/android/webapk/shell_apk/res/drawable-xhdpi/splash_icon.xml
deleted file mode 100644
index ab81c74..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-xhdpi/splash_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxxhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/drawable-xxhdpi/splash_icon.xml b/chrome/android/webapk/shell_apk/res/drawable-xxhdpi/splash_icon.xml
deleted file mode 100644
index ab81c74..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-xxhdpi/splash_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxxhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/splash_icon.xml b/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/splash_icon.xml
index ab81c74..7b00b3b 100644
--- a/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/splash_icon.xml
+++ b/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/splash_icon.xml
@@ -4,4 +4,4 @@
      found in the LICENSE file. -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxxhdpi"/>
+    android:src="@mipmap/app_icon"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap/app_icon_hdpi.png b/chrome/android/webapk/shell_apk/res/mipmap-hdpi/app_icon.png
similarity index 100%
rename from chrome/android/webapk/shell_apk/res/mipmap/app_icon_hdpi.png
rename to chrome/android/webapk/shell_apk/res/mipmap-hdpi/app_icon.png
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-hdpi/app_icon.xml b/chrome/android/webapk/shell_apk/res/mipmap-hdpi/app_icon.xml
deleted file mode 100644
index 07e31a49..0000000
--- a/chrome/android/webapk/shell_apk/res/mipmap-hdpi/app_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_hdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-hdpi/ic_launcher.xml b/chrome/android/webapk/shell_apk/res/mipmap-hdpi/ic_launcher.xml
index 77e7b552..bf4cd7b 100644
--- a/chrome/android/webapk/shell_apk/res/mipmap-hdpi/ic_launcher.xml
+++ b/chrome/android/webapk/shell_apk/res/mipmap-hdpi/ic_launcher.xml
@@ -4,4 +4,4 @@
      found in the LICENSE file. -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_hdpi"/>
+    android:src="@mipmap/app_icon"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap/app_icon_mdpi.png b/chrome/android/webapk/shell_apk/res/mipmap-mdpi/app_icon.png
similarity index 100%
rename from chrome/android/webapk/shell_apk/res/mipmap/app_icon_mdpi.png
rename to chrome/android/webapk/shell_apk/res/mipmap-mdpi/app_icon.png
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-mdpi/app_icon.xml b/chrome/android/webapk/shell_apk/res/mipmap-mdpi/app_icon.xml
deleted file mode 100644
index 5f22cd9e..0000000
--- a/chrome/android/webapk/shell_apk/res/mipmap-mdpi/app_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_mdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-mdpi/ic_launcher.xml b/chrome/android/webapk/shell_apk/res/mipmap-mdpi/ic_launcher.xml
index 0097029..bf4cd7b 100644
--- a/chrome/android/webapk/shell_apk/res/mipmap-mdpi/ic_launcher.xml
+++ b/chrome/android/webapk/shell_apk/res/mipmap-mdpi/ic_launcher.xml
@@ -4,4 +4,4 @@
      found in the LICENSE file. -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_mdpi"/>
+    android:src="@mipmap/app_icon"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap/app_icon_xhdpi.png b/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/app_icon.png
similarity index 100%
rename from chrome/android/webapk/shell_apk/res/mipmap/app_icon_xhdpi.png
rename to chrome/android/webapk/shell_apk/res/mipmap-xhdpi/app_icon.png
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/app_icon.xml b/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/app_icon.xml
deleted file mode 100644
index 5e65be53..0000000
--- a/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/app_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/ic_launcher.xml b/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/ic_launcher.xml
index 67f1839..bf4cd7b 100644
--- a/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/ic_launcher.xml
+++ b/chrome/android/webapk/shell_apk/res/mipmap-xhdpi/ic_launcher.xml
@@ -4,4 +4,4 @@
      found in the LICENSE file. -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xhdpi"/>
+    android:src="@mipmap/app_icon"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap/app_icon_xxhdpi.png b/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/app_icon.png
similarity index 100%
rename from chrome/android/webapk/shell_apk/res/mipmap/app_icon_xxhdpi.png
rename to chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/app_icon.png
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/app_icon.xml b/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/app_icon.xml
deleted file mode 100644
index 0ea2a6b..0000000
--- a/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/app_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/ic_launcher.xml b/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/ic_launcher.xml
index 25cdc31..bf4cd7b 100644
--- a/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/ic_launcher.xml
+++ b/chrome/android/webapk/shell_apk/res/mipmap-xxhdpi/ic_launcher.xml
@@ -4,4 +4,4 @@
      found in the LICENSE file. -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxhdpi"/>
+    android:src="@mipmap/app_icon"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap/app_icon_xxxhdpi.png b/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/app_icon.png
similarity index 100%
rename from chrome/android/webapk/shell_apk/res/mipmap/app_icon_xxxhdpi.png
rename to chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/app_icon.png
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/app_icon.xml b/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/app_icon.xml
deleted file mode 100644
index ab81c74..0000000
--- a/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/app_icon.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxxhdpi"/>
diff --git a/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/ic_launcher.xml b/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/ic_launcher.xml
index b26ea32..bf4cd7b 100644
--- a/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/ic_launcher.xml
+++ b/chrome/android/webapk/shell_apk/res/mipmap-xxxhdpi/ic_launcher.xml
@@ -4,4 +4,4 @@
      found in the LICENSE file. -->
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@mipmap/app_icon_xxxhdpi"/>
+    android:src="@mipmap/app_icon"/>
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index 92e5bd92..ccbdc1d 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@
 # (including AndroidManifest.xml) is updated. This version should be incremented
 # prior to uploading a new ShellAPK to the WebAPK Minting Server.
 # Does not affect Chrome.apk
-template_shell_apk_version = 47
+template_shell_apk_version = 48
 
 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
 # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/unbound_manifest_config.json b/chrome/android/webapk/shell_apk/unbound_manifest_config.json
index 492ccb71..88f8f38 100644
--- a/chrome/android/webapk/shell_apk/unbound_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/unbound_manifest_config.json
@@ -13,6 +13,7 @@
   "orientation": "portrait",
   "theme_color": "2147483648L",
   "background_color": "2147483648L",
+  "has_large_splash_icons": "false",
   "icon_urls_and_icon_murmur2_hashes": "http://www.pwa.rocks/icon1.png 0 http://www.pwa.rocks/icon2.png 0",
   "web_manifest_url": "https://pwa.rocks/pwa.webmanifest",
   "version_code": "1",
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 7e1d27a..7b6a843a 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5075,6 +5075,12 @@
   <message name="IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE" desc="Text shown in the Crostini installer dialog when the container inside the VM is starting">
     This process may take a few minutes. Starting the Linux container.
   </message>
+  <message name="IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_MESSAGE" desc="Text shown in the Crostini installer dialog when fetching ssh keys">
+    This process may take a few minutes. Starting the Linux container.
+  </message>
+  <message name="IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_MESSAGE" desc="Text shown in the Crostini installer dialog when doing sshfs mount of container">
+    This process may take a few minutes. Starting the Linux container.
+  </message>
   <message name="IDS_CROSTINI_INSTALLER_RETRY_BUTTON" desc="Retry button of the Crostini installer dialog that starts the install steps again.">
     Retry
   </message>
@@ -5096,6 +5102,12 @@
   <message name="IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR" desc="Text shown in the Crostini installer dialog when the container fails to start inside the VM">
     The Linux container didn't start. Please try again.
   </message>
+  <message name="IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_ERROR" desc="Text shown in the Crostini installer dialog when there is an error fetching ssh keys">
+    Error configuring the Linux container to access files. Please try again.
+  </message>
+  <message name="IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_ERROR" desc="Text shown in the Crostini installer dialog when the container ssh mount fails">
+    Error mounting Linux files. Please try again.
+  </message>
   <message name="IDS_CROSTINI_UNINSTALLER_TITLE" desc="Title of the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files.">
     Delete Linux (Beta)
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 3a525470..1ab9625 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4705,6 +4705,9 @@
       <message name="IDS_NTP_CUSTOM_LINKS_EDIT_SHORTCUT" desc="The title for custom link edit shortcut dialog. (On the New Tab Page)">
         Edit shortcut
       </message>
+      <message name="IDS_UPLOAD_IMAGE_FORMAT" desc="The permitted upload image format for the custom background. (On the New Tab Page)">
+        *.jpeg, *.jpg, *.png
+      </message>
       <message name="IDS_NTP_CUSTOM_LINKS_NAME" desc="The title for custom link name input field on the edit shortcut dialog. (On the New Tab Page)">
         Name
       </message>
diff --git a/chrome/app/resources/chromium_strings_bn.xtb b/chrome/app/resources/chromium_strings_bn.xtb
index 37a7bd73..d60f4ce 100644
--- a/chrome/app/resources/chromium_strings_bn.xtb
+++ b/chrome/app/resources/chromium_strings_bn.xtb
@@ -230,6 +230,7 @@
 <translation id="8157153840442649507">এই ভাষায় Chromium  প্রদর্শিত হচ্ছে</translation>
 <translation id="81770708095080097">এই ফাইলটি বিপজ্জনক, তাই Chromium এটিকে অবরুদ্ধ করেছে।</translation>
 <translation id="8222496066431494154">আপনার ফোনে Chromium ইনস্টল করুন। আমরা আপনার অ্যাকাউন্ট ফিরিয়ে আনার ফোন নম্বরে একটি এসএমএস পাঠাব: <ph name="PHONE_NUMBER" /></translation>
+<translation id="825412236959742607">এই পৃষ্ঠাটি খুব বেশি মেমরি ব্যবহার করছে তাই Chrome কিছু কন্টেন্ট সরিয়ে দিয়েছে।</translation>
 <translation id="8269379391216269538">Chromium কে আরও  করে তুলতে সাহায্য করুন৷</translation>
 <translation id="8290862415967981663">এই ফাইলটি বিপজ্জনক হতে পারে, তাই Chromium এটিকে অবরুদ্ধ করেছে।</translation>
 <translation id="8330519371938183845">আপনার সব ডিভাইস জুড়ে Chromium সিঙ্ক করতে এবং নিজের মতো সাজিয়ে নিতে সাইন-ইন করুন</translation>
diff --git a/chrome/app/resources/chromium_strings_es-419.xtb b/chrome/app/resources/chromium_strings_es-419.xtb
index 6a38824..b729eb9 100644
--- a/chrome/app/resources/chromium_strings_es-419.xtb
+++ b/chrome/app/resources/chromium_strings_es-419.xtb
@@ -226,6 +226,7 @@
 <translation id="8157153840442649507">Chromium se muestra en este idioma</translation>
 <translation id="81770708095080097">Chromium bloqueó este archivo porque es peligroso.</translation>
 <translation id="8222496066431494154">Instala Chromium en el teléfono. Te enviaremos un SMS al número de teléfono de recuperación de la cuenta: <ph name="PHONE_NUMBER" /></translation>
+<translation id="825412236959742607">Chrome quitó parte del contenido de esta página porque usa demasiada memoria.</translation>
 <translation id="8269379391216269538">Ayudar a mejorar Chromium</translation>
 <translation id="8290862415967981663">Chromium bloqueó este archivo porque podría ser peligroso.</translation>
 <translation id="8330519371938183845">Accede para sincronizar y personalizar Chromium en todos tus dispositivos</translation>
diff --git a/chrome/app/resources/chromium_strings_te.xtb b/chrome/app/resources/chromium_strings_te.xtb
index 9cde13a0..cb77db6 100644
--- a/chrome/app/resources/chromium_strings_te.xtb
+++ b/chrome/app/resources/chromium_strings_te.xtb
@@ -122,7 +122,7 @@
 <translation id="5479196819031988440">Chromium OS ఈ పేజీని తెరవలేదు.</translation>
 <translation id="5480860683791598150">ఈ సైట్‌తో మీ స్థానాన్ని షేర్ చేయడానికి Chromiumకు మీ స్థాన యాక్సెస్ అవసరం</translation>
 <translation id="549669000822060376">దయచేసి Chromium తాజా సిస్టమ్ నవీకరణలను ఇన్‌స్టాల్ చేస్తున్నప్పుడు వేచి ఉండండి.</translation>
-<translation id="5514308096618405748">Linux (బీటా)గా అదనపు <ph name="BEGIN_LINK_CROS_OSS" />ఓపన్ సోర్స్ సాఫ్ట్‌వేర్‌<ph name="END_LINK_CROS_OSS" /> ద్వారా Chrome OS సాధ్యం అవుతుంది.</translation>
+<translation id="5514308096618405748">Linux (బీటా) లాగానే, Chrome OS కూడా అదనపు <ph name="BEGIN_LINK_CROS_OSS" />ఓపెన్ సోర్స్ సాఫ్ట్‌వేర్‌<ph name="END_LINK_CROS_OSS" />పై ఎంతగానో ఆధారపడుతుంది.</translation>
 <translation id="5529843986978123325">{0,plural, =1{Chromium OS 1 నిమిషంలో మళ్లీ ప్రారంభించబడుతుంది}other{Chromium OS # నిమిషాల్లో మళ్లీ ప్రారంభించబడుతుంది}}</translation>
 <translation id="5631814766731275228">Chromium పేరు మరియు చిత్రం</translation>
 <translation id="5634636535844844681">Chromiumకి Windows 7 లేదా అంతకంటే ఆధునికమైనది ఉండటం ఆవశ్యకం.</translation>
@@ -164,7 +164,7 @@
 <translation id="6475912303565314141">ఇది మీరు Chromiumని ప్రారంభించేటప్పుడు చూపబడే పేజీని కూడా నియంత్రిస్తుంది.</translation>
 <translation id="6485906693002546646">మీరు మీ Chromium అంశాలను సమకాలీకరించడానికి <ph name="PROFILE_EMAIL" />ని ఉపయోగిస్తున్నారు. మీ సమకాలీకరణ ప్రాధాన్యతను నవీకరించడానికి లేదా Google ఖాతా లేకుండా Chromiumని ఉపయోగించడానికి, <ph name="SETTINGS_LINK" />ను సందర్శించండి.</translation>
 <translation id="6510925080656968729">Chromiumని అన్ఇన్‌స్టాల్ చేయి</translation>
-<translation id="6570579332384693436">అక్షరక్రమ లోపాలను పరిష్కరించడానికి, Chrome మీరు వచన ఫీల్డ్‌లలో టైప్ చేసే వచనాన్ని Googleకి పంపుతుంది</translation>
+<translation id="6570579332384693436">అక్షరక్రమ లోపాలను పరిష్కరించడానికి, మీరు వచన ఫీల్డ్‌లలో టైప్ చేసే వచనాన్ని, Chromium Googleకి పంపుతుంది</translation>
 <translation id="6598877126913850652">Chromium నోటిఫికేషన్ సెట్టింగ్‌లకు వెళ్లు</translation>
 <translation id="6676384891291319759">ఇంటర్నెట్‌ను ఆక్సెస్ చెయ్యండి</translation>
 <translation id="6717134281241384636">మీ ప్రొఫైల్ క్రొత్త Chromium సంస్కరణ అయినందున ఇది ఉపయోగించబడదు.
@@ -228,11 +228,12 @@
 <translation id="8157153840442649507">Chromium ఈ భాషలో ప్రదర్శించబడుతోంది</translation>
 <translation id="81770708095080097">ఈ ఫైల్ అపాయకరమైనది, కాబట్టి Chromium దీన్ని బ్లాక్ చేసింది.</translation>
 <translation id="8222496066431494154">మీ ఫోన్‌లో Chromiumను ఇన్‌స్టాల్ చేయండి. మేము మీ ఖాతా పునరుద్ధరణ ఫోన్ నంబర్‌కు SMSను పంపుతాము: <ph name="PHONE_NUMBER" /></translation>
+<translation id="825412236959742607">ఈ పేజీ చాలా మెమరీని ఉపయోగిస్తుంది, కాబట్టి Chrome కొంత కంటెంట్‌ను తీసివేసింది.</translation>
 <translation id="8269379391216269538">Chromiumని మెరుగుపరచడంలో సహాయం అందించండి</translation>
 <translation id="8290862415967981663">ఈ ఫైల్ అపాయకరం కావచ్చు, కాబట్టి Chromium దీన్ని బ్లాక్ చేసింది.</translation>
 <translation id="8330519371938183845">మీ పరికరాల అంతటా Chromiumని సమకాలీకరించడం మరియు వ్యక్తిగతీకరించడం కోసం సైన్ ఇన్ చేయండి</translation>
 <translation id="8340674089072921962"><ph name="USER_EMAIL_ADDRESS" /> మునుపు Chromiumని ఉపయోగించింది</translation>
-<translation id="8375950122744241554">పర్యవేక్షించబడే వినియోగదారు ప్రొఫైల్‌లు Chromium 70తో ప్రారంభమయ్యే వాటిల్లో ఇకపై అందుబాటులో ఉండవు.</translation>
+<translation id="8375950122744241554">Chromium 70తో మొదలు పెట్టి, తర్వాతి వెర్షన్‌లలో పర్యవేక్షించబడే వినియోగదారు ప్రొఫైల్‌లు ఇకపై అందుబాటులో ఉండవు.</translation>
 <translation id="8379713241968949941">{0,plural, =1{ఒక గంటలో Chromium తిరిగి ప్రారంభించబడుతుంది}other{# గంటల్లో Chromium తిరిగి ప్రారంభించబడుతుంది}}</translation>
 <translation id="8453117565092476964">ఇన్‌స్టాలర్ ఆర్కైవ్ పాడైంది లేదా చెల్లదు. దయచేసి Chromiumని మళ్లీ డౌన్‌లోడ్ చేయండి.</translation>
 <translation id="8493179195440786826">Chromium కాలం చెల్లినది</translation>
diff --git a/chrome/app/resources/chromium_strings_zh-CN.xtb b/chrome/app/resources/chromium_strings_zh-CN.xtb
index e3a6578..3e0b996 100644
--- a/chrome/app/resources/chromium_strings_zh-CN.xtb
+++ b/chrome/app/resources/chromium_strings_zh-CN.xtb
@@ -232,6 +232,7 @@
 <translation id="8157153840442649507">Chromium 界面目前使用的是这种语言</translation>
 <translation id="81770708095080097">此文件存在危险,因此 Chromium 已将其拦截。</translation>
 <translation id="8222496066431494154">请在您的手机上安装 Chromium。我们会将一条短信发送到您帐号的辅助电话号码:<ph name="PHONE_NUMBER" /></translation>
+<translation id="825412236959742607">此网页占用的内存过多,因此 Chrome 移除了部分内容。</translation>
 <translation id="8269379391216269538">帮助我们改进Chromium</translation>
 <translation id="8290862415967981663">此文件可能存在危险,因此 Chromium 已将其拦截。</translation>
 <translation id="8330519371938183845">登录即可在您的所有设备上同步并个性化设置 Chromium</translation>
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb
index 752dfea..94405328 100644
--- a/chrome/app/resources/generated_resources_am.xtb
+++ b/chrome/app/resources/generated_resources_am.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">በ<ph name="PEPPER_PLUGIN_DOMAIN" /> ላይ ያለው <ph name="PEPPER_PLUGIN_NAME" /> ኮምፒውተርዎን መድረስ ይፈልጋል</translation>
 <translation id="2178614541317717477">CA Compromise</translation>
 <translation id="218070003709087997">ስንት ቅጂዎች መታተም እንዳለባቸው ለማመላከት ቁጥር ይጠቀሙ (ከ1 እስከ 999)።</translation>
-<translation id="2183558561014688873">የእርስዎ መሣሪያ ንቁ በሚህንበት እና ክፍት ሲሆን እርስዎ «Ok Google» በሚሉበት በማናቸውም ጊዜ የእርስዎን ረዳት ይድረሱበት።</translation>
 <translation id="2187895286714876935">የአገልጋይ ዕውቅና ማረጋገጫ ስህተት</translation>
 <translation id="2187906491731510095">ቅጥያዎች ተዘምነዋል</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> ክፈት</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">ከኩኪዎች በስተቀር ሁሉም በ<ph name="SITE" /> የተከማቸው ውሂብ ይሰረዛል።</translation>
 <translation id="237058345584060620">ቁልፍዎን ተጠቅመው ወደ መለያዎ ለመግባት ከዚህ መሣሪያ ጋር ያጣምሩት</translation>
 <translation id="2371076942591664043">&amp;ሲጠናቀቅ ክፈት</translation>
-<translation id="2376559921867170420">የእርስዎ Chromebook ሲቀናበር፣ የረዳት አዝራሩን ይጫኑ ወይም ከእርስዎ ረዳት በማናቸውም ጊዜ እገዛ ለማግኘት «Ok Google» ይበሉ።</translation>
 <translation id="2377319039870049694">ወደ የዝርዝር እይታ ቀይር</translation>
 <translation id="2377667304966270281">ከባድ ስህተቶች</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> ፋይሎች ተመርጠዋል</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">ሌላ አክል</translation>
 <translation id="3812525830114410218">መጥፎ የእውቅና ማረጋገጫ</translation>
 <translation id="3813296892522778813">የሚፈልጉትን ነገር ማግኘት ካልቻሉ ወደ <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome እገዛ<ph name="END_LINK_CHROMIUM" /> ይሂዱ</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">አልቀረበም</translation>
 <translation id="3819752733757735746">የማብሪያ/ማጥፊያ መዳረሻ (ኮምፒውተሩን በአንድ ወይም ሁለት ማብሪያ ማጥፊያዎች ይቆጣጠሩ)</translation>
 <translation id="3819800052061700452">&amp;በሙሉ ገጽ ማያ አሳይ</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">የተቀመጡ የጣት አሻራዎች</translation>
 <translation id="407173827865827707">ጠቅ ሲደረግ</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />፦ በመለያ የመግባት ስህተት</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">የኢሜይል ፈራሚ ሰርቲፊኬት</translation>
 <translation id="407520071244661467">የልኬት ለውጥ</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" />ን cast ማድረግ አልተቻለም።</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index d45b399d..ff38bc92 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">يريد <ph name="PEPPER_PLUGIN_NAME" /> الموجود على <ph name="PEPPER_PLUGIN_DOMAIN" /> الوصول إلى جهاز الكمبيوتر.</translation>
 <translation id="2178614541317717477">‏اختراق المرجع المصدق (CA)</translation>
 <translation id="218070003709087997">استخدم رقمًا للإشارة إلى عدد النُسخ المطلوب طباعتها (من 1 إلى 999).</translation>
-<translation id="2183558561014688873">‏يمكنك الوصول إلى "المساعد" في أي وقت تقول فيه "OK Google" عندما يكون جهازك نشطًا وتم إلغاء قفله.</translation>
 <translation id="2187895286714876935">خط استيراد شهادة الخادم</translation>
 <translation id="2187906491731510095">تم تحديث الإضافات.</translation>
 <translation id="2188881192257509750">فتح <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">سيتم حذف جميع البيانات المُخزَّنة بواسطة <ph name="SITE" /> باستثناء ملفات تعريف الارتباط.</translation>
 <translation id="237058345584060620">يمكنك إقران مفتاحك بهذا الجهاز حتى تتمكن من استخدامه لتسجيل الدخول إلى حسابك.</translation>
 <translation id="2371076942591664043">فتح الملفّ عند &amp;انتهاء التحميل</translation>
-<translation id="2376559921867170420">‏بعد إعداد جهاز Chromebook، يُرجى الضغط على زر "مساعد Google" أو قول عبارة "OK Google" لاستخدام المساعد في أي وقت.</translation>
 <translation id="2377319039870049694">تبديل إلى عرض القائمة</translation>
 <translation id="2377667304966270281">الأخطاء الجسيمة</translation>
 <translation id="2378075407703503998">تم تحديد <ph name="SELCTED_FILE_COUNT" /> من الملفات</translation>
@@ -1877,6 +1875,7 @@
 <translation id="381202950560906753">إضافة بصمة إصبع أخرى</translation>
 <translation id="3812525830114410218">شهادة سيئة</translation>
 <translation id="3813296892522778813">‏يمكنك الانتقال إلى <ph name="BEGIN_LINK_CHROMIUM" />مساعدة Google Chrome<ph name="END_LINK_CHROMIUM" /> إذا لم تتمكن من العثور عما تبحث عنه</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">غير متوفِّر</translation>
 <translation id="3819752733757735746">الوصول عبر مفتاح التحويل (التحكم في جهاز الكمبيوتر بمفتاح واحد فقط أو مفتاحين)</translation>
 <translation id="3819800052061700452">م&amp;لء الشاشة</translation>
@@ -2044,7 +2043,6 @@
 <translation id="4068776064906523561">بصمات الإصبع المحفوظة</translation>
 <translation id="407173827865827707">عند النقر</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: خطأ في تسجيل الدخول</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">شهادة توقيع البريد الإلكتروني</translation>
 <translation id="407520071244661467">تغيير الحجم</translation>
 <translation id="4075639477629295004">يتعذَر إرسال <ph name="FILE_NAME" />.</translation>
@@ -4043,7 +4041,7 @@
 <translation id="7175353351958621980">تم التحميل من:</translation>
 <translation id="7180611975245234373">تحديث</translation>
 <translation id="7180865173735832675">تخصيص</translation>
-<translation id="7182359331070524176">‏اختيار ألبوم صور Google</translation>
+<translation id="7182359331070524176">‏اختيار ألبوم من "صور Google"</translation>
 <translation id="7186088072322679094">البقاء مثبتًا في شريط الأدوات</translation>
 <translation id="7187428571767585875">إدخالات قاعدة بيانات المسجّلين التي ستتم إزالتها أو تغييرها:</translation>
 <translation id="7189234443051076392">التأكد من توفر مساحة كافية على جهازك</translation>
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb
index 2cc84b2..b11e691 100644
--- a/chrome/app/resources/generated_resources_bg.xtb
+++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> от <ph name="PEPPER_PLUGIN_DOMAIN" /> иска да осъществи достъп до компютъра ви</translation>
 <translation id="2178614541317717477">Компрометиране на сертифициращия орган</translation>
 <translation id="218070003709087997">Използвайте число, за да укажете колко копия да се отпечатат (от 1 до 999).</translation>
-<translation id="2183558561014688873">Осъществявайте достъп до Асистент всеки път, когато кажете „Ok Google“ и устройството ви е активно и отключено.</translation>
 <translation id="2187895286714876935">Грешка при импортирането на сертификат на сървър</translation>
 <translation id="2187906491731510095">Разширенията бяха актуализирани</translation>
 <translation id="2188881192257509750">Отваряне на <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">Ще бъдат изтрити всички съхранявани от <ph name="SITE" /> данни освен „бисквитките“.</translation>
 <translation id="237058345584060620">Сдвоете ключа си с това устройство, за да можете да използвате ключа за вход в профила си</translation>
 <translation id="2371076942591664043">Отваряне &amp;след изтегляне</translation>
-<translation id="2376559921867170420">Когато вашият Chromebook бъде настроен, натиснете бутона за Асистент или кажете „Ok Google“, за да получите помощ от Асистент по всяко време.</translation>
 <translation id="2377319039870049694">Превключване към списъчен изглед</translation>
 <translation id="2377667304966270281">Съществени грешки</translation>
 <translation id="2378075407703503998">Избрани са <ph name="SELCTED_FILE_COUNT" /> файла</translation>
@@ -1877,6 +1875,7 @@
 <translation id="381202950560906753">Добавяне на друг</translation>
 <translation id="3812525830114410218">Невалиден сертификат</translation>
 <translation id="3813296892522778813">Прегледайте <ph name="BEGIN_LINK_CHROMIUM" />помощното съдържание за Google Chrome<ph name="END_LINK_CHROMIUM" />, ако не можете да намерите търсеното</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Не е посочено</translation>
 <translation id="3819752733757735746">Достъп с превключване (контролиране на компютъра само с един или два превключвателя)</translation>
 <translation id="3819800052061700452">На &amp;цял екран</translation>
@@ -2048,7 +2047,6 @@
 <translation id="4068776064906523561">Запазени отпечатъци</translation>
 <translation id="407173827865827707">При кликване</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: Грешка при влизане в профила</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Сертификат за подписване на имейли</translation>
 <translation id="407520071244661467">Мащаб</translation>
 <translation id="4075639477629295004">Предаването на „<ph name="FILE_NAME" />“ не е възможно.</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index 2393cb9b..10accf9 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -401,6 +401,7 @@
 <translation id="1589055389569595240">বানান এবং ব্যাকরণ দেখান</translation>
 <translation id="1593594475886691512">ফরম্যাট করা হচ্ছে...</translation>
 <translation id="159359590073980872">ছবি ক্যাশে</translation>
+<translation id="1593926297800505364">পেমেন্ট পদ্ধতি সেভ করুন</translation>
 <translation id="1598233202702788831">আপনার প্রশাসক দ্বারা আপডেট অক্ষম করা হয়েছে।</translation>
 <translation id="1600857548979126453">পৃষ্ঠা ডিবাগার ব্যাকএন্ড অ্যাক্সেস করুন</translation>
 <translation id="1601560923496285236">প্রয়োগ করুন</translation>
@@ -510,6 +511,7 @@
 <translation id="1744060673522309905">ডোমেনে ডিভাইসটি যোগ করা যাবে না। ভাল করে দেখে নিন যে আপনার ডিভাইস যোগ করার সর্বাধিক সংখ্যা যেন অতিক্রম না করে।</translation>
 <translation id="1744108098763830590">পৃষ্ঠভূমি পৃষ্ঠা</translation>
 <translation id="1745520510852184940">সর্বদা এটিই করুন</translation>
+<translation id="1746417874336251387">Chromebook-এ আপনার ফোনের কানেকশন ব্যবহার করে এমন নতুন বৈশিষ্ট্যগুলির অফার</translation>
 <translation id="174937106936716857">মোট ফাইল সংখ্যা</translation>
 <translation id="175196451752279553">বন্ধ ট্যাবটি পু&amp;নঃরায় খুলুন</translation>
 <translation id="1753905327828125965">সর্বাধিক দেখা</translation>
@@ -640,8 +642,10 @@
 <translation id="1932098463447129402">আগে কখনও নয়</translation>
 <translation id="1933809209549026293">দয়া করে একটি মাউস বা কীবোর্ড সংযোগ করুন৷ যদি আপনি একটি ব্লুটুথ ডিভাইস ব্যবহার করে থাকেন তবে এটি যুক্ত করার জন্য তৈরি কিনা নিশ্চিত করুন৷</translation>
 <translation id="1936157145127842922">ফোল্ডারে দেখান</translation>
+<translation id="1938351510777341717">এক্সটার্নাল কমান্ড</translation>
 <translation id="1940546824932169984">সংযুক্ত ডিভাইস</translation>
 <translation id="1942765061641586207">চিত্রের রেজোলিউশন</translation>
+<translation id="1943097386230153518">নতুন পরিষেবা ইনস্টল করুন</translation>
 <translation id="1944921356641260203">আপডেট পাওয়া গেছে</translation>
 <translation id="1951615167417147110">একটি পৃষ্ঠা স্ক্রোল করুন</translation>
 <translation id="1954813140452229842">মাউন্টিং শেয়ারে সমস্যা। অনুগ্রহ করে আপনার ক্রেডেনশিয়াল যাচাই করে আবার চেষ্টা করুন।</translation>
@@ -790,7 +794,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> এ <ph name="PEPPER_PLUGIN_NAME" /> আপনার কম্পিউটার অ্যাক্সেস করতে চায়</translation>
 <translation id="2178614541317717477">CA আপোস</translation>
 <translation id="218070003709087997">কতগুলি কপি প্রিন্ট হবে তা নির্দিষ্ট করতে একটি সংখ্যা ব্যবহার করুন (১ থেকে ৯৯৯)।</translation>
-<translation id="2183558561014688873">আপনার ডিভাইস সক্রিয় এবং আনলক থাকাকালীন "OK Google" বলে যেকোনও সময়ে আপনার অ্যাসিস্ট্যান্ট অ্যাক্সেস করুন।</translation>
 <translation id="2187895286714876935">সার্ভার শংসাপত্র  আমদানি  ত্রুটি</translation>
 <translation id="2187906491731510095">এক্সটেনশনগুলি আপডেট করা হয়েছে</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> খুলুন</translation>
@@ -919,7 +922,6 @@
 <translation id="2369536625682139252">কুকি ছাড়া <ph name="SITE" />-এর স্টোর করা সমস্ত ডেটা মুছে দেওয়া হবে।</translation>
 <translation id="237058345584060620">এই ডিভাইসের সাথে আপনার কী পেয়ার করুন যাতে আপনার অ্যাকাউন্টে সাইন-ইন করার সময় আপনি এটি ব্যবহার করতে পারেন</translation>
 <translation id="2371076942591664043">&amp;সম্পন্ন হলে খুলুন</translation>
-<translation id="2376559921867170420">আপনার Chromebook সেট-আপ করা হয়ে গেলে, অ্যাসিস্ট্যান্টের থেকে যেকোনও সময় সাহায্য পেতে অ্যাসিস্ট্যান্ট বোতামটি প্রেস করুন অথবা "Ok Google" বলুন।</translation>
 <translation id="2377319039870049694">তালিকা দৃশ্যে যান</translation>
 <translation id="2377667304966270281">হার্ড ফল্ট</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> টি ফাইল নির্বাচিত</translation>
@@ -1108,6 +1110,7 @@
 <translation id="2653659639078652383">জমা দিন</translation>
 <translation id="265390580714150011">ক্ষেত্রের মান</translation>
 <translation id="2654166010170466751">সাইটগুলিকে পেমেন্ট হ্যান্ডলার ইনস্টল করার অনুমতি দিন</translation>
+<translation id="2659381484350128933">ডিভাইসের উপর নির্ভর করে <ph name="FOOTNOTE_POINTER" /> বৈশিষ্ট্যের পরিবর্তন হবে</translation>
 <translation id="2660779039299703961">ইভেন্ট</translation>
 <translation id="266079277508604648">প্রিন্টারটি সংযুক্ত করা যায়নি। প্রিন্টারটি চালু আছে কিনা এবং ওয়াই-ফাই অথবা USB এর মাধ্যমে Chromebook এর সাথে সংযুক্ত আছে কিনা দেখে নিন।</translation>
 <translation id="2661146741306740526">১৬x৯</translation>
@@ -1215,6 +1218,7 @@
 <translation id="2803375539583399270">পিন নম্বর দিন</translation>
 <translation id="2805646850212350655">Microsoft Encrypting File System</translation>
 <translation id="2805756323405976993">অ্যাপ্স</translation>
+<translation id="2806891468525657116">শর্টকাটটি আগে থেকেই আছে</translation>
 <translation id="2807517655263062534">ডাউনলোড করা ফাইল এখানে দেখা যাবে</translation>
 <translation id="2809586584051668049">এবং আরও <ph name="NUMBER_ADDITIONAL_DISABLED" />টি</translation>
 <translation id="281133045296806353">বিদ্যমান ব্রাউজার সেশনে নতুন উইন্ডো তৈরি হয়েছে৷</translation>
@@ -1598,6 +1602,7 @@
 <translation id="3428419049384081277">আপনি সাইন-ইন করেছেন!</translation>
 <translation id="3429275422858276529">এই পৃষ্ঠা পরে সহজে খুঁজে পেতে বুকমার্ক করুন</translation>
 <translation id="3429599832623003132">$১টি আইটেম</translation>
+<translation id="3430342160185525240">আপনাকে বিজ্ঞপ্তিগুলি দেখানোর জন্য অ্যাসিস্ট্যান্টটি চালু করুন।</translation>
 <translation id="3432227430032737297">দেখানো সবগুলি সরান</translation>
 <translation id="3432757130254800023">স্থানীয় নেটওয়ার্কের প্রদর্শনগুলিতে অডিও এবং ভিডিও পাঠান</translation>
 <translation id="3432762828853624962">শেয়ার্ড ওয়ার্কার</translation>
@@ -1870,6 +1875,7 @@
 <translation id="381202950560906753">আরেকটি জুড়ুন</translation>
 <translation id="3812525830114410218">খারাপ শংসাপত্র</translation>
 <translation id="3813296892522778813">আপনি যা খুঁজছেন তা খুঁজে না পেলে <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome সহায়তায়<ph name="END_LINK_CHROMIUM" /> যান</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">উল্লেখ নেই</translation>
 <translation id="3819752733757735746">অ্যাক্সেস সুইচ করুন (মাত্র এক বা দুই সুইচের মাধ্যমে কম্পিউটার নিয়ন্ত্রণ করুন)</translation>
 <translation id="3819800052061700452">&amp;পূর্ণ-স্ক্রিন</translation>
@@ -1961,6 +1967,7 @@
 <translation id="3941565636838060942">এই প্রোগ্রামের অ্যাক্সেস লুকানোর জন্য, আপনাকে নিয়ন্ত্রণ প্যানেলে <ph name="CONTROL_PANEL_APPLET_NAME" /> ব্যবহার করে এটি আনইনস্টল করতে হবে৷
 
 আপনি কি <ph name="CONTROL_PANEL_APPLET_NAME" /> শুরু করতে চান?</translation>
+<translation id="394183848452296464">শর্টকাট তৈরি করা যাবে না</translation>
 <translation id="3943582379552582368">&amp;ফিরুন</translation>
 <translation id="3943857333388298514">আটকে দিন</translation>
 <translation id="3948116654032448504">&amp;চিত্রের জন্য <ph name="SEARCH_ENGINE" /> খুঁজুন</translation>
@@ -2038,7 +2045,6 @@
 <translation id="4068776064906523561">সংরক্ষিত আঙ্গুলের ছাপগুলি</translation>
 <translation id="407173827865827707">ক্লিক করা হলে</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: প্রবেশ করায় ত্রুটি</translation>
-<translation id="4071828814509176232">"OK Google"</translation>
 <translation id="4074900173531346617">ইমেল স্বাক্ষরকারীর শংসাপত্র</translation>
 <translation id="407520071244661467">স্কেল</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> কে কাস্ট করা যায়নি।</translation>
@@ -2268,6 +2274,7 @@
 <translation id="4481530544597605423">বিযুক্ত করা ডিভাইসগুলি</translation>
 <translation id="4482194545587547824">সার্চ এবং অন্যান্য Google পরিষেবাগুলি ব্যক্তিগতকৃত করতে Google আপনার ব্রাউজিং ইতিহাস ব্যবহার করতে পারে</translation>
 <translation id="4495419450179050807">এই পৃষ্ঠাতে দেখাবেন না</translation>
+<translation id="4499718683476608392">এক ক্লিকে ফর্মগুলি পূরণ করার জন্য ক্রেডিট কার্ড অটোফিল চালু করুন</translation>
 <translation id="4500114933761911433"><ph name="PLUGIN_NAME" /> ক্র্যাশ করে গেছে</translation>
 <translation id="450099669180426158">বিস্ময়বোধক চিহ্ন আইকন</translation>
 <translation id="4501530680793980440">সরানো নিশ্চিত করুন</translation>
@@ -3061,7 +3068,7 @@
 <translation id="5677503058916217575">পৃষ্ঠার ভাষা:</translation>
 <translation id="5677928146339483299">অবরুদ্ধ</translation>
 <translation id="5678550637669481956"><ph name="VOLUME_NAME" />-এর পড়া এবং লেখার অ্যাক্সেস মঞ্জুর করা হয়েছে৷</translation>
-<translation id="5678784840044122290">Linux অ্যাপকেশনটি আপনার টার্মিনালের মধ্যে পাওয়া যাবে এবং আপনার লঞ্চারে একটি আইকনও দেখাতে পারে।</translation>
+<translation id="5678784840044122290">Linux অ্যাপ্লিকেশনটি আপনার  টার্মিনালের মধ্যে পাওয়া যাবে এবং আপনার লঞ্চারে একটি আইকনও দেখাতে পারে।</translation>
 <translation id="5678955352098267522"><ph name="WEBSITE_1" />এ আপনার ডেটা পড়ে</translation>
 <translation id="5684661240348539843">সম্পদ শনাক্তকারী</translation>
 <translation id="5686799162999241776"><ph name="BEGIN_BOLD" />একটি আর্কাইভ বা ভার্চুয়াল ডিস্ক থেকে ডিসকানেক্ট করা যাবে না<ph name="END_BOLD" />
@@ -3110,6 +3117,7 @@
 <translation id="5752453871435543420">Chrome OS ক্লাউড ব্যাকআপ</translation>
 <translation id="5756163054456765343">সহায়তা কেন্দ্র</translation>
 <translation id="5759728514498647443"><ph name="APP_NAME" />-এর দ্বারা প্রিন্ট করার জন্য আপনার পাঠানো দস্তাবেজগুলি <ph name="APP_NAME" />-এর মাধ্যমে পঠন করা যায়৷</translation>
+<translation id="5762172915276660232">ক্রেডিট কার্ড সেটিংস</translation>
 <translation id="5763751966069581670">কোনও USB ডিভাইস খুঁজে পাওয়া যায়নি</translation>
 <translation id="5764483294734785780">এইরূপে অডিও সংর&amp;ক্ষণ করুন...</translation>
 <translation id="57646104491463491">পরিবর্তনের তারিখ</translation>
@@ -3181,6 +3189,7 @@
 <translation id="5855773610748894548">নিরাপদ মডিউল তৈরি করতে ত্রুটি হয়েছে।</translation>
 <translation id="5856721540245522153">ডিবাগিং বৈশিষ্ট্যাবলী সক্ষম করুন</translation>
 <translation id="5857090052475505287">নতুন ফোল্ডার</translation>
+<translation id="585979798156957858">এক্সটার্নাল মেটা</translation>
 <translation id="5860033963881614850">বন্ধ করুন</translation>
 <translation id="5860209693144823476">ট্যাব ৩</translation>
 <translation id="5860491529813859533">চালু করুন</translation>
@@ -3491,6 +3500,7 @@
 <translation id="6327785803543103246">ওয়েব প্রক্সী স্বতঃআবিষ্কার</translation>
 <translation id="6333064448949140209">ফাইল ত্রুটিমুক্ত করার জন্য Google এ পাঠানো হবে</translation>
 <translation id="6333834492048057036">সার্চের জন্য ঠিকানা দণ্ডের উপর নজর রাখুন</translation>
+<translation id="6336451774241870485">নতুন ব্যক্তিগত ট্যাব</translation>
 <translation id="6339668969738228384"><ph name="USER_EMAIL_ADDRESS" /> এর জন্য একটি নতুন প্রোফাইল তৈরি করুন</translation>
 <translation id="6340017061976355871">সার্ভারে সংযোগ করা যায়নি। অনুগ্রহ করে আপনার নেটওয়ার্ক সংযোগ যাচাই করে আবার চেষ্টা করুন। যদি সমস্যাটি চলতে থাকে তাহলে আপনার Chromebook রিস্টার্ট করুন।</translation>
 <translation id="6340071272923955280">ইন্টারনেট প্রিন্ট প্রোটোকল (IPPS)</translation>
@@ -3671,6 +3681,7 @@
 <translation id="6606070663386660533">ট্যাব ৮</translation>
 <translation id="6607272825297743757">ফাইলের তথ্য</translation>
 <translation id="6607831829715835317">আরও সরঞ্জা&amp;ম</translation>
+<translation id="6610147964972079463">ব্যক্তিগত ট্যাব বন্ধ করুন</translation>
 <translation id="6612358246767739896">সুরক্ষিত সামগ্রী</translation>
 <translation id="6613452264606394692">এই পৃষ্ঠাটি বুকমার্ক করে দ্রুত এখানে ফিরে আসুন</translation>
 <translation id="6614893213975402384">আপডেট এবং অ্যাপ ইনস্টল করুন। চালিয়ে যাওয়ার অর্থ, আপনি সম্মতি দেন যে এই ডিভাইসটি নিজে থেকেই Google, আপনার পরিষেবা প্রদানকারী এবং আপনার ডিভাইসের প্রস্তুতকারকের ওয়েবসাইট থেকে হয়ত মোবাইল ডেটা ব্যবহার করে অ্যাপ এবং আপডেট ডাউনলোড করে ইনস্টল করতে পারে। এই অ্যাপগুলির মধ্যে কিছু অ্যাপ, অ্যাপ মধ্যস্থ কেনাকাটার অফার করে। আপনি যেকোনও সময়ে এই অ্যাপগুলি সরিয়ে দিতে পারেন। <ph name="BEGIN_LINK1" />আরও জানুন<ph name="END_LINK1" /></translation>
@@ -3741,6 +3752,7 @@
 <translation id="6710213216561001401">পূর্ববর্তী</translation>
 <translation id="6718273304615422081">জিপ করা হচ্ছে...</translation>
 <translation id="671928215901716392">স্ক্রিন লক করুন</translation>
+<translation id="6720847671508630642">Chromebook ব্যবহার করে নিজে থেকে Android-এর সেরা বিষয়গুলি শেয়ার করুন। কম্পিউটার থেকে টেক্সট, ফোনের ইন্টারনেট কানেকশন শেয়ার এবং Chromebook-এর স্ক্রিন আনলক করতে আপনার ফোন কানেক্ট করুন।<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />আরও জানুন<ph name="LINK_END" /></translation>
 <translation id="6721678857435001674">আপনার নিরাপত্তা কী-এর কোম্পানির নাম এবং মডেলটি দেখুন</translation>
 <translation id="6721972322305477112">&amp;File</translation>
 <translation id="672213144943476270">দয়া করে অতিথি হিসাবে ব্রাউজ করার আগে আপনার প্রোফাইলটি আনলক করুন।</translation>
@@ -3887,6 +3899,7 @@
 <translation id="6970856801391541997">প্রিন্ট নির্দিষ্ট পৃষ্ঠাসমূহ</translation>
 <translation id="6972180789171089114">অডিও/ভিডিও</translation>
 <translation id="6973630695168034713">ফোল্ডারগুলি</translation>
+<translation id="6974609594866392343">অফলাইন ডেমো মোড</translation>
 <translation id="6976108581241006975">JavaScript কনসোল</translation>
 <translation id="6977381486153291903">ফার্মওয়ের পুনর্বিবেচনাগুলি</translation>
 <translation id="6978121630131642226">সার্চ ইঞ্জিনসমূহ</translation>
@@ -4480,6 +4493,7 @@
 <translation id="7857949311770343000">আপনি কি এই পৃষ্ঠাটিকে নতুন ট্যাব পৃষ্ঠা হিসাবে আশা করছিলেন?</translation>
 <translation id="786073089922909430">পরিষেবা: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7861215335140947162">&amp;ডাউনলোড করা</translation>
+<translation id="7864662577698025113">নতুন পরিষেবা যোগ করুন</translation>
 <translation id="7868378670806575181">{NUM_COOKIES,plural, =1{১টি কুকি}one{#টি কুকি}other{#টি কুকি}}</translation>
 <translation id="786957569166715433"><ph name="DEVICE_NAME" /> - যুক্ত করা হয়েছে</translation>
 <translation id="7870730066603611552">সেট-আপের পর সিঙ্কের বিকল্পগুলির রিভিউ</translation>
@@ -4995,6 +5009,7 @@
 <translation id="8666584013686199826">কোনও সাইট ইউএসবি ডিভাইস অ্যাক্সেস করতে চাইলে আমাকে জিজ্ঞাসা করুন</translation>
 <translation id="8667328578593601900"><ph name="FULLSCREEN_ORIGIN" /> এখন সম্পূর্ণ স্ক্রীণে আছে এবং আপনার মাউস কার্সারকে অক্ষম করেছে৷</translation>
 <translation id="8669284339312441707">ওয়ার্মার</translation>
+<translation id="8669919703154928649">অ্যাসিস্ট্যান্টকে বিজ্ঞপ্তিগুলি দেখাতে দিন</translation>
 <translation id="8669949407341943408">সরানো  হচ্ছে...</translation>
 <translation id="8671210955687109937">মন্তব্য করতে পারবেন</translation>
 <translation id="8673026256276578048">ওয়েবে খুঁজুন...</translation>
@@ -5382,6 +5397,7 @@
 <translation id="964286338916298286">আপনার আইটি অ্যাডমিনিস্ট্রেটর আপনার ডিভাইসের জন্য Chrome গুডিজগুলিকে বন্ধ করেছেন৷</translation>
 <translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{অ্যাপ্লিকেশন}one{অ্যাপ্লিকেশনগুলি}other{অ্যাপ্লিকেশনগুলি}}</translation>
 <translation id="967007123645306417">এটি আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করিয়ে দেবে। আপনার বুকমার্ক, ইতিহাস, পাসওয়ার্ড সহ অন্যান্য সেটিংসের পরিবর্তনগুলি আপনার Google অ্যাকাউন্টের সাথে আর সিঙ্ক করা হবে না। কিন্তু, আগে থেকে থাকা আপনার ডেটা আপনার Google অ্যাকাউন্টে স্টোর থাকবে এবং <ph name="BEGIN_LINK" />Google ড্যাশবোর্ড<ph name="END_LINK" /> থেকে পরিচালনা করা যাবে।</translation>
+<translation id="967624055006145463">ডেটা স্টোর করা হয়েছে</translation>
 <translation id="968000525894980488">Google Play পরিষেবা চালু করুন।</translation>
 <translation id="968174221497644223">অ্যাপ্লিকেশন ক্যাশে</translation>
 <translation id="969096075394517431">ভাষাগুলি পরিবর্তন করুন</translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index e29648a..94b65ab 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">El connector <ph name="PEPPER_PLUGIN_NAME" /> del lloc web <ph name="PEPPER_PLUGIN_DOMAIN" /> vol accedir a l'ordinador</translation>
 <translation id="2178614541317717477">Compromís de CA</translation>
 <translation id="218070003709087997">Utilitza un número per indicar quantes còpies vols imprimir (entre 1 i 999).</translation>
-<translation id="2183558561014688873">Accedeix a l'Assistent en qualsevol moment dient "Ok Google" amb el dispositiu actiu i desbloquejat.</translation>
 <translation id="2187895286714876935">Error d'importació del certificat del servidor</translation>
 <translation id="2187906491731510095">S'han actualitzat les extensions</translation>
 <translation id="2188881192257509750">Obre <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Se suprimiran totes les dades que <ph name="SITE" /> hagi emmagatzemat, tret de les galetes.</translation>
 <translation id="237058345584060620">Vincula la teva clau amb aquest dispositiu per poder utilitzar-la per iniciar la sessió al teu compte</translation>
 <translation id="2371076942591664043">Obre quan &amp;acabi</translation>
-<translation id="2376559921867170420">Quan el dispositiu Chromebook estigui configurat, prem el botó de l'Assistent o digues "Ok Google" per obtenir ajuda de l'Assistent en qualsevol moment.</translation>
 <translation id="2377319039870049694">Canvia a la visualització de llista</translation>
 <translation id="2377667304966270281">Errors greus</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> fitxers seleccionats</translation>
@@ -1877,6 +1875,7 @@
 <translation id="381202950560906753">Afegeix-ne una altra</translation>
 <translation id="3812525830114410218">Certificat incorrecte</translation>
 <translation id="3813296892522778813">Si no trobes el que busques, ves a l'<ph name="BEGIN_LINK_CHROMIUM" />ajuda de Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">No s'ha proporcionat</translation>
 <translation id="3819752733757735746">Accés amb interruptors (controleu l'ordinador amb només un o dos interruptors)</translation>
 <translation id="3819800052061700452">&amp;Pantalla completa</translation>
@@ -2046,7 +2045,6 @@
 <translation id="4068776064906523561">Empremtes digitals desades</translation>
 <translation id="407173827865827707">En fer clic</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: error d'inici de sessió</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certificat del signant del correu electrònic</translation>
 <translation id="407520071244661467">Canvia l'escala</translation>
 <translation id="4075639477629295004">No es pot emetre <ph name="FILE_NAME" /></translation>
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb
index effcd14..e42ad85 100644
--- a/chrome/app/resources/generated_resources_cs.xtb
+++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Plugin <ph name="PEPPER_PLUGIN_NAME" /> v doméně <ph name="PEPPER_PLUGIN_DOMAIN" /> chce získat přístup k vašemu počítači</translation>
 <translation id="2178614541317717477">Ohrožení bezpečnosti certifikační autority</translation>
 <translation id="218070003709087997">Počet kopií, které chcete vytisknout, je třeba zadat jako číslo (od 1 do 999).</translation>
-<translation id="2183558561014688873">Když je zařízení aktivní a je odemknuté, můžete Asistenta kdykoliv aktivovat vyslovením fráze „Ok Google“.</translation>
 <translation id="2187895286714876935">Chyba při importu certifikátu serveru</translation>
 <translation id="2187906491731510095">Rozšíření byla aktualizována</translation>
 <translation id="2188881192257509750">Spustit aplikaci <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Všechna data uložená webem <ph name="SITE" /> kromě souborů cookie budou smazána</translation>
 <translation id="237058345584060620">Spárujte klíč s tímto zařízením, abyste se pomocí něj mohli přihlašovat ke svému účtu</translation>
 <translation id="2371076942591664043">Po dokončení otevřít</translation>
-<translation id="2376559921867170420">Když je Chromebook nastaven, získáte pomoc od Asistenta kdykoliv tak, že stisknete tlačítko Asistent nebo řeknete „OK Google“.</translation>
 <translation id="2377319039870049694">Přepnout na zobrazení seznamu</translation>
 <translation id="2377667304966270281">Chyby stránkování na disk</translation>
 <translation id="2378075407703503998">Vybrané soubory: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1877,6 +1875,7 @@
 <translation id="381202950560906753">Přidat další</translation>
 <translation id="3812525830114410218">Nesprávný certifikát</translation>
 <translation id="3813296892522778813">Pokud nemůžete najít, co hledáte, navštivte <ph name="BEGIN_LINK_CHROMIUM" />nápovědu Google Chrome<ph name="END_LINK_CHROMIUM" />.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Neposkytnuto</translation>
 <translation id="3819752733757735746">Přístup pomocí přepínačů (ovládání počítače pouze jedním nebo dvěma přepínači)</translation>
 <translation id="3819800052061700452">&amp;Celá obrazovka</translation>
@@ -2046,7 +2045,6 @@
 <translation id="4068776064906523561">Uložené otisky prstu</translation>
 <translation id="407173827865827707">Při kliknutí</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: chyba přihlášení</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certifikát autora podpisu e-mailu</translation>
 <translation id="407520071244661467">Měřítko</translation>
 <translation id="4075639477629295004">Soubor <ph name="FILE_NAME" /> nelze odeslat.</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index be54a71..5fb183b 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724">Pluginnet <ph name="PEPPER_PLUGIN_NAME" /> på <ph name="PEPPER_PLUGIN_DOMAIN" /> anmoder om adgang til din computer</translation>
 <translation id="2178614541317717477">Sammensat nøglecenter</translation>
 <translation id="218070003709087997">Brug et tal til at angive, hvor mange kopier der skal udskrives (1 til 999).</translation>
-<translation id="2183558561014688873">Få adgang til Google-assistenten, hver gang du siger "Ok Google", når din enhed er tændt og oplåst.</translation>
 <translation id="2187895286714876935">Fejl ved import af servercertifikat</translation>
 <translation id="2187906491731510095">Udvidelserne er opdateret</translation>
 <translation id="2188881192257509750">Åbn <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">Alle data, der lagres af <ph name="SITE" />, slettes – med undtagelse af cookies.</translation>
 <translation id="237058345584060620">Par din nøgle med denne enhed, så du kan bruge den til at logge ind på din konto</translation>
 <translation id="2371076942591664043">Åbn når &amp;færdigt</translation>
-<translation id="2376559921867170420">Når din Chromebook er konfigureret, kan du til enhver tid trykke på Assistent-knappen eller sige "Ok Google" for at for at få hjælp fra Google-assistenten.</translation>
 <translation id="2377319039870049694">Skift til listevisning</translation>
 <translation id="2377667304966270281">Hårde fejl</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> filer valgt</translation>
@@ -1877,6 +1875,7 @@
 <translation id="381202950560906753">Tilføj endnu et</translation>
 <translation id="3812525830114410218">Ugyldigt certifikat</translation>
 <translation id="3813296892522778813">Gå til <ph name="BEGIN_LINK_CHROMIUM" />Hjælp til Google Chrome<ph name="END_LINK_CHROMIUM" />, hvis du ikke kan finde det, du leder efter.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Ikke angivet</translation>
 <translation id="3819752733757735746">Kontaktadgang (styr computeren med blot én eller to kontakter)</translation>
 <translation id="3819800052061700452">&amp;Fuld skærm</translation>
@@ -2047,7 +2046,6 @@
 <translation id="4068776064906523561">Gemte fingeraftryk</translation>
 <translation id="407173827865827707">Ved klik</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: loginfejl</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certifikat til e-mailunderskriver</translation>
 <translation id="407520071244661467">Skaler</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> kunne ikke castes.</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 3771701e..a6f40bd 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724">Das Plug-in <ph name="PEPPER_PLUGIN_NAME" /> auf <ph name="PEPPER_PLUGIN_DOMAIN" /> möchte auf Ihren Computer zugreifen</translation>
 <translation id="2178614541317717477">Kompromittierung der Zertifizierungsstelle</translation>
 <translation id="218070003709087997">Geben Sie eine Zahl ein, um die Anzahl der zu druckenden Exemplare festzulegen (1 bis 999).</translation>
-<translation id="2183558561014688873">Bei aktivem Bildschirm und entsperrtem Gerät steht Ihnen Google Assistant jederzeit zur Verfügung, wenn Sie "Ok Google" sagen.</translation>
 <translation id="2187895286714876935">Fehler beim Importieren des Serverzertifikats</translation>
 <translation id="2187906491731510095">Erweiterungen wurden aktualisiert</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> öffnen</translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">Alle von <ph name="SITE" /> gespeicherten Daten werden gelöscht, mit Ausnahme von Cookies.</translation>
 <translation id="237058345584060620">Koppeln Sie Ihren Schlüssel mit diesem Gerät, um sich damit in Ihrem Konto anmelden zu können</translation>
 <translation id="2371076942591664043">Nach &amp;Download öffnen</translation>
-<translation id="2376559921867170420">Wenn Ihr Chromebook eingerichtet ist, können Sie die Assistant-Taste drücken oder "Ok Google" sagen, um sich jederzeit von Assistant helfen zu lassen.</translation>
 <translation id="2377319039870049694">Zur Listenansicht wechseln</translation>
 <translation id="2377667304966270281">Harte Fehler</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> Dateien ausgewählt</translation>
@@ -1875,6 +1873,7 @@
 <translation id="381202950560906753">Weitere hinzufügen</translation>
 <translation id="3812525830114410218">Ungültiges Zertifikat</translation>
 <translation id="3813296892522778813">Wenn Sie keine Ergebnisse erhalten, <ph name="BEGIN_LINK_CHROMIUM" />rufen Sie die Google Chrome-Hilfe auf<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Keine Angabe</translation>
 <translation id="3819752733757735746">Schalterzugriff (zum Steuern des Computers mit nur einem oder zwei Schaltern)</translation>
 <translation id="3819800052061700452">V&amp;ollbildmodus</translation>
@@ -2045,7 +2044,6 @@
 <translation id="4068776064906523561">Gespeicherte Fingerabdrücke</translation>
 <translation id="407173827865827707">Bei Klick</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: Anmeldefehler</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Zertifikat für E-Mail-Signaturen</translation>
 <translation id="407520071244661467">Skalieren</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> kann nicht gestreamt werden.</translation>
diff --git a/chrome/app/resources/generated_resources_el.xtb b/chrome/app/resources/generated_resources_el.xtb
index f122608..172da70 100644
--- a/chrome/app/resources/generated_resources_el.xtb
+++ b/chrome/app/resources/generated_resources_el.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Η προσθήκη <ph name="PEPPER_PLUGIN_NAME" /> στον τομέα <ph name="PEPPER_PLUGIN_DOMAIN" /> επιθυμεί να αποκτήσει πρόσβαση στον υπολογιστή σας</translation>
 <translation id="2178614541317717477">Παραβίαση αρχής έκδοσης πιστοποιητικών</translation>
 <translation id="218070003709087997">Χρησιμοποιήστε έναν αριθμό για να υποδείξετε πόσα αντίγραφα θα εκτυπωθούν (1 ή 999).</translation>
-<translation id="2183558561014688873">Μεταβείτε στον Βοηθό οποιαδήποτε στιγμή λέγοντας "OK Google", όταν η συσκευή σας είναι ενεργή και ξεκλείδωτη.</translation>
 <translation id="2187895286714876935">Σφάλμα εισαγωγής του πιστοποιητικού διακομιστή  </translation>
 <translation id="2187906491731510095">Οι επεκτάσεις ενημερώθηκαν</translation>
 <translation id="2188881192257509750">Άνοιγμα <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Όλα τα δεδομένα που αποθηκεύτηκαν από τον ιστότοπο <ph name="SITE" /> θα διαγραφούν, εκτός από τα cookie.</translation>
 <translation id="237058345584060620">Δημιουργήστε σύζευξη μεταξύ του κλειδιού σας και αυτής της συσκευής, για να μπορείτε να τη χρησιμοποιήσετε για σύνδεση στον λογαριασμό σας</translation>
 <translation id="2371076942591664043">Άνοιγμα κατά την &amp;ολοκλήρωση</translation>
-<translation id="2376559921867170420">Μετά τη ρύθμιση του Chromebook, πατήστε το κουμπί Βοηθού ή πείτε "OK Google" για να λάβετε βοήθεια από τον Βοηθό σας οποιαδήποτε στιγμή.</translation>
 <translation id="2377319039870049694">Εναλλαγή σε προβολή λίστας</translation>
 <translation id="2377667304966270281">Σοβαρά σφάλματα</translation>
 <translation id="2378075407703503998">Έχουν επιλεγεί <ph name="SELCTED_FILE_COUNT" /> αρχεία</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Προσθήκη άλλης συσκευής</translation>
 <translation id="3812525830114410218">Ακατάλληλο πιστοποιητικό</translation>
 <translation id="3813296892522778813">Μεταβείτε στη <ph name="BEGIN_LINK_CHROMIUM" />βοήθεια του Google Chrome<ph name="END_LINK_CHROMIUM" /> εάν δεν μπορείτε να βρείτε αυτό που αναζητάτε</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Άγνωστο</translation>
 <translation id="3819752733757735746">Πρόσβαση με διακόπτες (ελέγξτε τον υπολογιστή με έναν ή δύο διακόπτες μόνο)</translation>
 <translation id="3819800052061700452">&amp;Πλήρης οθόνη</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Αποθηκευμένα δακτυλικά αποτυπώματα</translation>
 <translation id="407173827865827707">Όταν κάνετε κλικ</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: σφάλμα σύνδεσης</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">Πιστοποιητικό υπηρεσίας υπογραφής ηλεκτρονικού ταχυδρομείου</translation>
 <translation id="407520071244661467">Κλίμακα</translation>
 <translation id="4075639477629295004">Δεν είναι δυνατή η μετάδοση του αρχείου <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb
index 9a587f793..7b7d817 100644
--- a/chrome/app/resources/generated_resources_en-GB.xtb
+++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> on <ph name="PEPPER_PLUGIN_DOMAIN" /> wants to access your computer</translation>
 <translation id="2178614541317717477">CA Compromise</translation>
 <translation id="218070003709087997">Use a number to indicate how many copies to print (1 to 999).</translation>
-<translation id="2183558561014688873">Access your Assistant any time you say 'Ok Google' when your device is awake and unlocked.</translation>
 <translation id="2187895286714876935">Server Certificate Import Error</translation>
 <translation id="2187906491731510095">Extensions updated</translation>
 <translation id="2188881192257509750">Open <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">All data stored by <ph name="SITE" /> will be deleted, except for cookies.</translation>
 <translation id="237058345584060620">Pair your key to this device so that you can use it to sign into your account</translation>
 <translation id="2371076942591664043">Open when &amp;done</translation>
-<translation id="2376559921867170420">When your Chromebook is set up, press the Assistant button or say "Ok Google" to get help from your Assistant at any time.</translation>
 <translation id="2377319039870049694">Switch to list view</translation>
 <translation id="2377667304966270281">Hard Faults</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> files selected</translation>
@@ -1878,6 +1876,7 @@
 <translation id="381202950560906753">Add another</translation>
 <translation id="3812525830114410218">Bad certificate</translation>
 <translation id="3813296892522778813">Go to <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome help<ph name="END_LINK_CHROMIUM" /> if you can't find what you're looking for</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Not provided</translation>
 <translation id="3819752733757735746">Switch access (control the computer with just one or two switches)</translation>
 <translation id="3819800052061700452">&amp;Full screen</translation>
@@ -2048,7 +2047,6 @@
 <translation id="4068776064906523561">Saved fingerprints</translation>
 <translation id="407173827865827707">On click</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: sign-in error</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Email Signer Certificate</translation>
 <translation id="407520071244661467">Scale</translation>
 <translation id="4075639477629295004">Unable to cast <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index 81b6be6..bd3fceb 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -398,6 +398,7 @@
 <translation id="1589055389569595240">Mostrar ortografía y gramática</translation>
 <translation id="1593594475886691512">Aplicando formato...</translation>
 <translation id="159359590073980872">Caché de imagen</translation>
+<translation id="1593926297800505364">Guardar la forma de pago</translation>
 <translation id="1598233202702788831">Tu administrador inhabilitó las actualizaciones.</translation>
 <translation id="1600857548979126453">Acceder al servidor del depurador de páginas</translation>
 <translation id="1601560923496285236">Aplicar</translation>
@@ -508,6 +509,7 @@
 <translation id="1744060673522309905">No se pudo unir el dispositivo al dominio. Asegúrate de no haber superado la cantidad de dispositivos que puedes agregar.</translation>
 <translation id="1744108098763830590">página en segundo plano</translation>
 <translation id="1745520510852184940">Realizar siempre esta acción</translation>
+<translation id="1746417874336251387">Ofrece funciones nuevas que usan la conexión del teléfono a la Chromebook</translation>
 <translation id="174937106936716857">Cantidad total de archivos</translation>
 <translation id="175196451752279553">Volver a abrir una pestaña cerrada</translation>
 <translation id="1753905327828125965">Más visitados</translation>
@@ -638,8 +640,10 @@
 <translation id="1932098463447129402">No antes</translation>
 <translation id="1933809209549026293">Conecta un mouse o un teclado. Si usas un dispositivo Bluetooth, asegúrate de que esté preparado para la sincronización.</translation>
 <translation id="1936157145127842922">Mostrar en carpeta</translation>
+<translation id="1938351510777341717">Tecla externa Comando</translation>
 <translation id="1940546824932169984">Dispositivos conectados</translation>
 <translation id="1942765061641586207">Resolución de imagen</translation>
+<translation id="1943097386230153518">Instalar servicio nuevo</translation>
 <translation id="1944921356641260203">Actualización encontrada</translation>
 <translation id="1951615167417147110">Desplaza hacia arriba una página</translation>
 <translation id="1954813140452229842">Se produjo un error al activar el recurso compartido. Revisa tus credenciales y vuelve a intentarlo.</translation>
@@ -788,7 +792,6 @@
 <translation id="2178098616815594724">El complemento <ph name="PEPPER_PLUGIN_NAME" /> del dominio <ph name="PEPPER_PLUGIN_DOMAIN" /> desea acceder a tu computadora</translation>
 <translation id="2178614541317717477">Compromiso de entidad de certificación</translation>
 <translation id="218070003709087997">Usa un número para indicar la cantidad de copias que deseas imprimir (1 a 999).</translation>
-<translation id="2183558561014688873">Accede a tu Asistente cada vez que digas "OK Google" cuando tu dispositivo esté activo y desbloqueado.</translation>
 <translation id="2187895286714876935">Error en el servidor de importación de certificado</translation>
 <translation id="2187906491731510095">Se actualizaron las extensiones</translation>
 <translation id="2188881192257509750">Abrir <ph name="APPLICATION" /></translation>
@@ -917,7 +920,6 @@
 <translation id="2369536625682139252">Se borrarán todos los datos que almacenó <ph name="SITE" />, excepto las cookies.</translation>
 <translation id="237058345584060620">Sincroniza la llave con este dispositivo y podrás usarla para acceder a tu cuenta</translation>
 <translation id="2371076942591664043">Abrir al &amp;finalizar</translation>
-<translation id="2376559921867170420">Cuando tu Chromebook esté configurada, presiona el botón del Asistente o di "Ok Google" para obtener ayuda en cualquier momento.</translation>
 <translation id="2377319039870049694">Cambiar a la vista de lista</translation>
 <translation id="2377667304966270281">Fallos graves</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> archivos seleccionados</translation>
@@ -1105,6 +1107,7 @@
 <translation id="2653659639078652383">Enviar</translation>
 <translation id="265390580714150011">Valor de campo</translation>
 <translation id="2654166010170466751">Permitir que los sitios instalen controladores de pago</translation>
+<translation id="2659381484350128933"><ph name="FOOTNOTE_POINTER" />Las funciones varían según el dispositivo</translation>
 <translation id="2660779039299703961">Evento</translation>
 <translation id="266079277508604648">No se puede establecer conexión con la impresora. Comprueba que esté encendida y conectada a la Chromebook mediante Wi-Fi o USB.</translation>
 <translation id="2661146741306740526">16 x 9</translation>
@@ -1211,6 +1214,7 @@
 <translation id="2803375539583399270">Ingresar PIN</translation>
 <translation id="2805646850212350655">Sistema de encriptación de archivos de Microsoft</translation>
 <translation id="2805756323405976993">Aplicaciones</translation>
+<translation id="2806891468525657116">El acceso directo ya existe</translation>
 <translation id="2807517655263062534">Los archivos que descargas aparecen aquí</translation>
 <translation id="2809586584051668049">y <ph name="NUMBER_ADDITIONAL_DISABLED" /> más</translation>
 <translation id="281133045296806353">Se creó una nueva ventana en la sesión existente del navegador.</translation>
@@ -1597,6 +1601,7 @@
 <translation id="3428419049384081277">¡Accediste!</translation>
 <translation id="3429275422858276529">Agrega esta página a favoritos para encontrarla fácilmente más tarde</translation>
 <translation id="3429599832623003132">$1 elementos</translation>
+<translation id="3430342160185525240">Permite que el Asistente te muestre notificaciones.</translation>
 <translation id="3432227430032737297">Quitar todo lo que se muestra</translation>
 <translation id="3432757130254800023">Enviar audio y video a pantallas en la red local</translation>
 <translation id="3432762828853624962">Shared Workers</translation>
@@ -1869,6 +1874,7 @@
 <translation id="381202950560906753">Agregar otra</translation>
 <translation id="3812525830114410218">Certificado incorrecto</translation>
 <translation id="3813296892522778813">Consulta la <ph name="BEGIN_LINK_CHROMIUM" />Ayuda de Google Chrome<ph name="END_LINK_CHROMIUM" /> si no encuentras lo que estás buscando</translation>
+<translation id="3813984289128269159">OK Google</translation>
 <translation id="3817579325494460411">No proporcionada</translation>
 <translation id="3819752733757735746">Accesibilidad mejorada (controlar la computadora con solo uno o dos cambios)</translation>
 <translation id="3819800052061700452">&amp;Pantalla completa</translation>
@@ -1961,6 +1967,7 @@
   <ph name="CONTROL_PANEL_APPLET_NAME" /> en el Panel de control.
 
   ¿Quieres iniciar <ph name="CONTROL_PANEL_APPLET_NAME" />?</translation>
+<translation id="394183848452296464">No se puede crear el acceso directo</translation>
 <translation id="3943582379552582368">&amp;Atrás</translation>
 <translation id="3943857333388298514">Pegar</translation>
 <translation id="3948116654032448504">Buscar imagen en <ph name="SEARCH_ENGINE" /></translation>
@@ -2038,7 +2045,6 @@
 <translation id="4068776064906523561">Huellas digitales guardadas</translation>
 <translation id="407173827865827707">Al hacer clic</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: error de acceso</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Enviar por correo electrónico el certificado del firmante</translation>
 <translation id="407520071244661467">Escala</translation>
 <translation id="4075639477629295004">No se puede transmitir <ph name="FILE_NAME" />.</translation>
@@ -2268,6 +2274,7 @@
 <translation id="4481530544597605423">Dispositivos no sincronizados</translation>
 <translation id="4482194545587547824">Es posible que Google use tu historial de navegación para personalizar Búsqueda y otros servicios de Google</translation>
 <translation id="4495419450179050807">No mostrar en esta página</translation>
+<translation id="4499718683476608392">Habilita Autocompletar datos de tarjetas de crédito para llenar formularios con un solo clic</translation>
 <translation id="4500114933761911433"><ph name="PLUGIN_NAME" /> se bloqueó</translation>
 <translation id="450099669180426158">Ícono de signo de exclamación</translation>
 <translation id="4501530680793980440">Confirmar eliminación</translation>
@@ -3111,6 +3118,7 @@
 <translation id="5752453871435543420">Copia de seguridad en la nube del Sistema operativo Chrome</translation>
 <translation id="5756163054456765343">C&amp;entro de ayuda</translation>
 <translation id="5759728514498647443"><ph name="APP_NAME" /> podrá leer los documentos que envíes a imprimir a través de <ph name="APP_NAME" />.</translation>
+<translation id="5762172915276660232">Configuración de tarjetas de crédito</translation>
 <translation id="5763751966069581670">No se encuentraron dispositivos USB</translation>
 <translation id="5764483294734785780">Guardar audio como...</translation>
 <translation id="57646104491463491">Fecha de modificación</translation>
@@ -3182,6 +3190,7 @@
 <translation id="5855773610748894548">Se produjo un error en el módulo de seguridad.</translation>
 <translation id="5856721540245522153">Habilitar funciones de depuración</translation>
 <translation id="5857090052475505287">Nueva carpeta</translation>
+<translation id="585979798156957858">Tecla externa Meta</translation>
 <translation id="5860033963881614850">Desactivado</translation>
 <translation id="5860209693144823476">Pestaña 3</translation>
 <translation id="5860491529813859533">Activar</translation>
@@ -3491,6 +3500,7 @@
 <translation id="6327785803543103246">Detección automática de proxy web</translation>
 <translation id="6333064448949140209">El archivo se envió a Google para depurarlo</translation>
 <translation id="6333834492048057036">El cursor se sitúa en la barra de direcciones para la búsqueda.</translation>
+<translation id="6336451774241870485">Nueva pestaña privada</translation>
 <translation id="6339668969738228384">Crear un perfil nuevo para <ph name="USER_EMAIL_ADDRESS" /></translation>
 <translation id="6340017061976355871">No se pudo establecer una conexión con el servidor. Comprueba la conexión de red y vuelve a intentarlo. Si el problema persiste, reinicia la Chromebook.</translation>
 <translation id="6340071272923955280">Protocolo de impresión por Internet (IPPS)</translation>
@@ -3672,6 +3682,7 @@
 <translation id="6606070663386660533">Pestaña 8</translation>
 <translation id="6607272825297743757">Información del archivo</translation>
 <translation id="6607831829715835317">Más herramientas</translation>
+<translation id="6610147964972079463">Cerrar las pestañas privadas</translation>
 <translation id="6612358246767739896">Contenido protegido</translation>
 <translation id="6613452264606394692">Para regresar aquí rápidamente, agrega esta página a favoritos</translation>
 <translation id="6614893213975402384">Instala actualizaciones y apps. Al continuar, aceptas que este dispositivo también descargue e instale automáticamente actualizaciones y apps de Google, tu administrador y el fabricante del dispositivo, posiblemente a través de datos móviles. Es posible que algunas de estas apps ofrezcan compras directas desde la aplicación. Puedes quitar las apps en cualquier momento. <ph name="BEGIN_LINK1" />Más información<ph name="END_LINK1" /></translation>
@@ -3742,6 +3753,7 @@
 <translation id="6710213216561001401">Anterior</translation>
 <translation id="6718273304615422081">Comprimiendo…</translation>
 <translation id="671928215901716392">Bloquear pantalla</translation>
+<translation id="6720847671508630642">Comparte lo mejor de Android con tu Chromebook de forma automática. Conecta tu teléfono para que puedas compartir su conexión a Internet, enviar mensajes de texto desde la computadora y desbloquear la pantalla de tu Chromebook.<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />Más información<ph name="LINK_END" /></translation>
 <translation id="6721678857435001674">Ver la marca y el modelo de tu llave de seguridad</translation>
 <translation id="6721972322305477112">&amp;Archivo</translation>
 <translation id="672213144943476270">Desbloquea tu perfil antes de navegar como invitado.</translation>
@@ -3888,6 +3900,7 @@
 <translation id="6970856801391541997">Imprimir páginas específicas</translation>
 <translation id="6972180789171089114">Audio/video</translation>
 <translation id="6973630695168034713">Carpetas</translation>
+<translation id="6974609594866392343">Modo de demostración sin conexión</translation>
 <translation id="6976108581241006975">Consola de JavaScript</translation>
 <translation id="6977381486153291903">Revisión de firmware</translation>
 <translation id="6978121630131642226">Motores de búsqueda</translation>
@@ -4482,6 +4495,7 @@
 <translation id="7857949311770343000">¿Esta es la página Nueva pestaña que esperabas ver?</translation>
 <translation id="786073089922909430">Servicio: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7861215335140947162">&amp;Descargas</translation>
+<translation id="7864662577698025113">Agregar un servicio nuevo</translation>
 <translation id="7868378670806575181">{NUM_COOKIES,plural, =1{1 cookie}other{# cookies}}</translation>
 <translation id="786957569166715433"><ph name="DEVICE_NAME" /> sincronizado</translation>
 <translation id="7870730066603611552">Revisar las opciones de sincronización después de la configuración</translation>
@@ -4997,6 +5011,7 @@
 <translation id="8666584013686199826">Preguntarme cuando un sitio intente acceder a dispositivos USB</translation>
 <translation id="8667328578593601900"><ph name="FULLSCREEN_ORIGIN" /> se está visualizando en pantalla completa y ha inhabilitado el cursor del mouse.</translation>
 <translation id="8669284339312441707">Cálido</translation>
+<translation id="8669919703154928649">Permitir que el Asistente te muestre notificaciones</translation>
 <translation id="8669949407341943408">Moviendo…</translation>
 <translation id="8671210955687109937">Se puede comentar</translation>
 <translation id="8673026256276578048">Buscar en la Web...</translation>
@@ -5384,6 +5399,7 @@
 <translation id="964286338916298286">El administrador de TI inhabilitó los accesorios de Chrome para tu dispositivo.</translation>
 <translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{Aplicación}other{Aplicaciones}}</translation>
 <translation id="967007123645306417">Con esta acción, saldrás de tus cuentas de Google. Los cambios en tus favoritos, historial, contraseñas y demás opciones de configuración ya no se sincronizarán con tu cuenta. Sin embargo, los datos existentes permanecerán almacenados allí y se podrán administrar en el <ph name="BEGIN_LINK" />Panel de control de Google<ph name="END_LINK" />.</translation>
+<translation id="967624055006145463">Datos almacenados</translation>
 <translation id="968000525894980488">Activa los Servicios de Google Play.</translation>
 <translation id="968174221497644223">Caché de aplicación</translation>
 <translation id="969096075394517431">Cambiar idiomas</translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index 61b2f82..9e3ac9d 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">El complemento <ph name="PEPPER_PLUGIN_NAME" /> de <ph name="PEPPER_PLUGIN_DOMAIN" /> quiere acceder a tu ordenador</translation>
 <translation id="2178614541317717477">Compromiso de entidad emisora de certificados</translation>
 <translation id="218070003709087997">Usa un número para indicar cuántas copias quieres imprimir (entre 1 y 999).</translation>
-<translation id="2183558561014688873">Accede al Asistente cuando digas "Ok Google" y tu dispositivo esté activo y desbloqueado</translation>
 <translation id="2187895286714876935">Error de importación del certificado de servidor</translation>
 <translation id="2187906491731510095">Se han actualizado las extensiones</translation>
 <translation id="2188881192257509750">Abrir <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Se eliminarán todos los datos que almacena <ph name="SITE" />, excepto las cookies.</translation>
 <translation id="237058345584060620">Vincula la llave con este dispositivo y podrás usarla para iniciar sesión en tu cuenta</translation>
 <translation id="2371076942591664043">Abrir al &amp;finalizar</translation>
-<translation id="2376559921867170420">Cuando hayas configurado el Chromebook, pulsa el botón del Asistente o di "Ok Google" para recibir ayuda del Asistente en cualquier momento.</translation>
 <translation id="2377319039870049694">Cambiar a vista de lista</translation>
 <translation id="2377667304966270281">Fallos graves</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> archivos seleccionados</translation>
@@ -1877,6 +1875,7 @@
 <translation id="381202950560906753">Añadir otra</translation>
 <translation id="3812525830114410218">Certificado erróneo</translation>
 <translation id="3813296892522778813">Si no puedes encontrar lo que estás buscando, consulta la <ph name="BEGIN_LINK_CHROMIUM" />ayuda de Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">No proporcionada</translation>
 <translation id="3819752733757735746">Acceso a interruptores (controla el ordenador con uno o dos interruptores)</translation>
 <translation id="3819800052061700452">&amp;Pantalla completa</translation>
@@ -2046,7 +2045,6 @@
 <translation id="4068776064906523561">Huellas digitales guardadas</translation>
 <translation id="407173827865827707">Al hacer clic</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: error de inicio de sesión</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certificado de firma de correo electrónico</translation>
 <translation id="407520071244661467">Escala</translation>
 <translation id="4075639477629295004">No se puede enviar <ph name="FILE_NAME" />.</translation>
@@ -4043,7 +4041,7 @@
 <translation id="7175353351958621980">Cargado desde:</translation>
 <translation id="7180611975245234373">Actualizar</translation>
 <translation id="7180865173735832675">Personalizar</translation>
-<translation id="7182359331070524176">Seleccionar un álbum de Google Fotos</translation>
+<translation id="7182359331070524176">Selecciona un álbum de Google Fotos</translation>
 <translation id="7186088072322679094">Mantener en la barra de herramientas</translation>
 <translation id="7187428571767585875">Entradas de registro que se van a eliminar o cambiar:</translation>
 <translation id="7189234443051076392">Deja suficiente espacio en tu dispositivo</translation>
diff --git a/chrome/app/resources/generated_resources_et.xtb b/chrome/app/resources/generated_resources_et.xtb
index 49cd3fbb..567add2 100644
--- a/chrome/app/resources/generated_resources_et.xtb
+++ b/chrome/app/resources/generated_resources_et.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> domeenil <ph name="PEPPER_PLUGIN_DOMAIN" /> soovib juurdepääsu teie arvutile</translation>
 <translation id="2178614541317717477">CA turvarike</translation>
 <translation id="218070003709087997">Kasutage numbrit, mis näitab, kui palju koopiaid printida (1 kuni 999).</translation>
-<translation id="2183558561014688873">Pääsete assistendile alati juurde, kui seade on sisse lülitatud ja avatud ning ütlete „Ok Google”.</translation>
 <translation id="2187895286714876935">Serveri sertifikaadi impordi viga</translation>
 <translation id="2187906491731510095">Laiendused on värskendatud</translation>
 <translation id="2188881192257509750">Ava <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Kõik saidi <ph name="SITE" /> talletatud andmed peale küpsisefailide kustutatakse.</translation>
 <translation id="237058345584060620">Siduge oma võti selle seadmega, et saaksite seda kasutada oma kontole sisselogimiseks</translation>
 <translation id="2371076942591664043">Ava, kui on &amp;valmis</translation>
-<translation id="2376559921867170420">Kui teie Chromebook on seadistatud, vajutage assistendi nuppu või öelge otsetee sõna „Ok Google”, et assistendilt abi paluda.</translation>
 <translation id="2377319039870049694">Lülita loendivaatele</translation>
 <translation id="2377667304966270281">Tõsised vead</translation>
 <translation id="2378075407703503998">Valitud on <ph name="SELCTED_FILE_COUNT" /> faili</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Lisa veel üks</translation>
 <translation id="3812525830114410218">Halb sertifikaat</translation>
 <translation id="3813296892522778813">Kui te ei leia otsitavat, avage <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome'i abi<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Puudub</translation>
 <translation id="3819752733757735746">Lülitiga juurdepääs (arvuti juhtimine vaid ühe või kahe lülitiga)</translation>
 <translation id="3819800052061700452">&amp;Täisekraan</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Salvestatud sõrmejäljed</translation>
 <translation id="407173827865827707">Klõpsamisel</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: sisselogimise viga</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Meili allkirjastamise sertifikaat</translation>
 <translation id="407520071244661467">Skaleeri</translation>
 <translation id="4075639477629295004">Faili <ph name="FILE_NAME" /> ei saa üle kanda.</translation>
diff --git a/chrome/app/resources/generated_resources_fa.xtb b/chrome/app/resources/generated_resources_fa.xtb
index 99b223e..d90d2c446 100644
--- a/chrome/app/resources/generated_resources_fa.xtb
+++ b/chrome/app/resources/generated_resources_fa.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724">افزایه <ph name="PEPPER_PLUGIN_NAME" /> در <ph name="PEPPER_PLUGIN_DOMAIN" /> می‌خواهد به رایانه شما دسترسی پیدا کند</translation>
 <translation id="2178614541317717477">‏بی اعتبارشدن CA</translation>
 <translation id="218070003709087997">استفاده از شماره برای نشان دادن تعداد کپی‌های چاپ (۱ تا ۹۹۹).</translation>
-<translation id="2183558561014688873">‏هرزمان که هنگام بیدار بودن و باز بودن قفل دستگاه می‌گویید «OK Google»، به «دستیار» دسترسی خواهید داشت.</translation>
 <translation id="2187895286714876935">خطای وارد کردن مجوز سرور</translation>
 <translation id="2187906491731510095">افزونه‌ها به‌روزرسانی شدند</translation>
 <translation id="2188881192257509750">باز کردن <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">همه داده‌هایی که <ph name="SITE" /> ذخیره کرده به‌جز کوکی‌ها حذف خواهد شد.</translation>
 <translation id="237058345584060620">کلیدتان را با این دستگاه مرتبط کنید تا بتوانید از آن برای ورود به سیستم حسابتان استفاده کنید</translation>
 <translation id="2371076942591664043">پس از &amp;تکمیل باز شود</translation>
-<translation id="2376559921867170420">‏وقتی Chromebook راه‌اندازی شد، دکمه «دستیار» را فشار دهید یا بگویید «OK Google» تا در هرزمانی از «دستیار» کمک بگیرید.</translation>
 <translation id="2377319039870049694">جابه‌جایی به نمای فهرستی</translation>
 <translation id="2377667304966270281">خطاهای سخت‌افزاری</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> فایل انتخاب شد</translation>
@@ -1875,6 +1873,7 @@
 <translation id="381202950560906753">افزودن دستگاه دیگر</translation>
 <translation id="3812525830114410218">گواهی نادرست</translation>
 <translation id="3813296892522778813">‏اگر نمی‌توانید چیزی را که می‌خواهید پیدا کنید،‌ به <ph name="BEGIN_LINK_CHROMIUM" />راهنمای Google Chrome‏<ph name="END_LINK_CHROMIUM" /> بروید</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">ارائه نشده است</translation>
 <translation id="3819752733757735746">دسترسی سوئیچ (رایانه را فقط با یک یا دو سوئیچ کنترل کنید)</translation>
 <translation id="3819800052061700452">&amp;تمام صفحه</translation>
@@ -2045,7 +2044,6 @@
 <translation id="4068776064906523561">اثرانگشت‌های ذخیره‌شده</translation>
 <translation id="407173827865827707">با کلیک</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: خطای ورود به سیستم</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">گواهی امضاکننده ایمیل</translation>
 <translation id="407520071244661467">مقیاس</translation>
 <translation id="4075639477629295004">ارسال محتوای <ph name="FILE_NAME" /> امکان‌پذیر نیست.</translation>
diff --git a/chrome/app/resources/generated_resources_fi.xtb b/chrome/app/resources/generated_resources_fi.xtb
index 9a11cdc..ac962ebb 100644
--- a/chrome/app/resources/generated_resources_fi.xtb
+++ b/chrome/app/resources/generated_resources_fi.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> verkkotunnuksessa <ph name="PEPPER_PLUGIN_DOMAIN" /> haluaa käyttää tietokonettasi.</translation>
 <translation id="2178614541317717477">Myöntäjäkompromissi</translation>
 <translation id="218070003709087997">Määritä tulostettavien kappaleiden määrä antamalla numero (1–999).</translation>
-<translation id="2183558561014688873">Käytä Assistantia sanomalla Ok Google koska vain, kun laite on päällä ja lukitus avattu.</translation>
 <translation id="2187895286714876935">Palvelimen varmenteen tuontivirhe</translation>
 <translation id="2187906491731510095">Laajennukset päivitetty</translation>
 <translation id="2188881192257509750">Avaa <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Tämä poistaa evästeitä lukuun ottamatta kaiken datan, jonka <ph name="SITE" /> tallensi.</translation>
 <translation id="237058345584060620">Yhdistä tämä laite ja suojausavain laitepariksi, jotta voit käyttää avainta kirjautumiseen.</translation>
 <translation id="2371076942591664043">Avaa, kun val&amp;mis</translation>
-<translation id="2376559921867170420">Kun Chromebook on määritetty, paina Assistant-painiketta tai sano Ok Google, niin voit puhua Assistantille koska tahansa.</translation>
 <translation id="2377319039870049694">Vaihda luettelonäkymään</translation>
 <translation id="2377667304966270281">Levyn sivuvirheet</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> tiedostoa on valittu</translation>
@@ -1880,6 +1878,7 @@
 <translation id="381202950560906753">Lisää toinen</translation>
 <translation id="3812525830114410218">Virheellinen varmenne</translation>
 <translation id="3813296892522778813">Jos et löydä etsimääsi, siirry <ph name="BEGIN_LINK_CHROMIUM" />Google Chromen ohjeisiin<ph name="END_LINK_CHROMIUM" />.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Ei annettu</translation>
 <translation id="3819752733757735746">Valitsimen käyttö (ohjaa tietokonetta yhdellä tai kahdella kytkimellä)</translation>
 <translation id="3819800052061700452">&amp;Koko näyttö</translation>
@@ -2047,7 +2046,6 @@
 <translation id="4068776064906523561">Tallennetut sormenjäljet</translation>
 <translation id="407173827865827707">Klikkaamalla</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: kirjautumisvirhe</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">Sähköpostin allekirjoitusvarmenne</translation>
 <translation id="407520071244661467">Asteikko</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> ei ole suoratoistettavissa.</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb
index a16c7d0..605e5cf 100644
--- a/chrome/app/resources/generated_resources_fil.xtb
+++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Gustong i-access ng <ph name="PEPPER_PLUGIN_NAME" /> sa <ph name="PEPPER_PLUGIN_DOMAIN" /> ang iyong computer</translation>
 <translation id="2178614541317717477">CA Compromise</translation>
 <translation id="218070003709087997">Gumamit ng numero upang maisaad kung gaano karaming kopya ang ipi-print (1 hanggang 999).</translation>
-<translation id="2183558561014688873">I-access ang iyong Assistant anumang oras na sabihin mo ang "OK Google" kapag nakailaw at naka-unlock ang iyong device.</translation>
 <translation id="2187895286714876935">Error sa Pag-import ng Certificate ng Server</translation>
 <translation id="2187906491731510095">Na-update ang mga extension</translation>
 <translation id="2188881192257509750">Buksan ang <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Ide-delete ang lahat ng data na na-store ng <ph name="SITE" />, maliban sa cookies.</translation>
 <translation id="237058345584060620">Ipares ang iyong key sa device na ito para magamit mo ito sa pag-sign in sa iyong account.</translation>
 <translation id="2371076942591664043">Buksan kapag &amp;tapos na</translation>
-<translation id="2376559921867170420">Kapag na-set up ang iyong Chromebook, pindutin ang button ng Assistant o sabihin ang "Ok Google" para humingi ng tulong sa Assistant mo anumang oras.</translation>
 <translation id="2377319039870049694">Lumipat sa list view</translation>
 <translation id="2377667304966270281">Mga Hard Fault</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> (na) file ang pinili</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Magdagdag ng isa pa</translation>
 <translation id="3812525830114410218">Maling certificate</translation>
 <translation id="3813296892522778813">Pumunta sa <ph name="BEGIN_LINK_CHROMIUM" />tulong ng Google Chrome<ph name="END_LINK_CHROMIUM" /> kung hindi mo makita ang hinahanap mo</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Hindi naibigay</translation>
 <translation id="3819752733757735746">Switch access (kontrolin ang computer gamit lang ang isa o dalawang switch)</translation>
 <translation id="3819800052061700452">&amp;Full screen</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Mga naka-save na fingerprint</translation>
 <translation id="407173827865827707">Sa pag-click</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: error sa pag-sign in</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">Certificate ng Email Signer</translation>
 <translation id="407520071244661467">Scale</translation>
 <translation id="4075639477629295004">Hindi ma-cast ang <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index d50a127..f6568ae 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Le plug-in <ph name="PEPPER_PLUGIN_NAME" /> provenant du domaine <ph name="PEPPER_PLUGIN_DOMAIN" /> demande l'accès à votre ordinateur</translation>
 <translation id="2178614541317717477">Autorité de certification compromise</translation>
 <translation id="218070003709087997">Indiquez le nombre de copies à imprimer (1 à 999).</translation>
-<translation id="2183558561014688873">Accédez à l'Assistant chaque fois que vous dites "Ok Google" quand votre appareil est allumé et déverrouillé.</translation>
 <translation id="2187895286714876935">Erreur d'importation du certificat serveur</translation>
 <translation id="2187906491731510095">Extensions mises à jour</translation>
 <translation id="2188881192257509750">Ouvrir <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Toutes les données stockées par <ph name="SITE" /> seront supprimées, sauf les cookies.</translation>
 <translation id="237058345584060620">Associez votre clé à cet appareil afin de pouvoir l'utiliser pour vous connecter à votre compte</translation>
 <translation id="2371076942591664043">Ouvrir une fois le téléchargement &amp;terminé</translation>
-<translation id="2376559921867170420">Lorsque votre Chromebook est configuré, appuyez sur le bouton de l'Assistant ou dites "Ok Google" pour obtenir son aide à tout moment.</translation>
 <translation id="2377319039870049694">Passer en mode Liste</translation>
 <translation id="2377667304966270281">Défauts matériels</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> fichiers sélectionnés</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Ajouter une autre empreinte</translation>
 <translation id="3812525830114410218">Certificat non fiable</translation>
 <translation id="3813296892522778813">Si vous ne trouvez pas ce que vous recherchez, consultez l'<ph name="BEGIN_LINK_CHROMIUM" />Aide Google Chrome<ph name="END_LINK_CHROMIUM" />.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Non indiqué</translation>
 <translation id="3819752733757735746">Switch Access (contrôler l'ordinateur avec un ou deux commutateurs seulement)</translation>
 <translation id="3819800052061700452">&amp;Plein écran</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Empreintes digitales enregistrées</translation>
 <translation id="407173827865827707">En cas de clic</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" /> : erreur de connexion</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certificat du signataire de courrier électronique</translation>
 <translation id="407520071244661467">Mise à l'échelle</translation>
 <translation id="4075639477629295004">Impossible de caster "<ph name="FILE_NAME" />"</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index 266f768..8963008 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -791,7 +791,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> પરનું <ph name="PEPPER_PLUGIN_NAME" /> તમારા કમ્પ્યુટરને ઍક્સેસ કરવા માગે છે</translation>
 <translation id="2178614541317717477">CA સમાધાન</translation>
 <translation id="218070003709087997">કેટલી કૉપિઝ છાપવાની છે તે બતાવવા માટે સંખ્યાનો ઉપયોગ કરો (1 થી 999 સુધીની).</translation>
-<translation id="2183558561014688873">જ્યારે તમારું ઉપકરણ સક્રિય અને અનલૉક કરેલું હોય, ત્યારે તમે ઇચ્છો ત્યારે "ઓકે Google" બોલીને આસિસ્ટંટની સહાય મેળવો.</translation>
 <translation id="2187895286714876935">સર્વર પ્રમાણપત્ર આયાત કરવામાં ભૂલ</translation>
 <translation id="2187906491731510095">એક્સ્ટેંશન અપડેટ કર્યા</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> ખોલો</translation>
@@ -920,7 +919,6 @@
 <translation id="2369536625682139252"><ph name="SITE" /> દ્વારા સ્ટોર કરેલો કુકી સિવાયનો, બધો ડેટા કાઢી નખાશે,</translation>
 <translation id="237058345584060620">આ ઉપકરણ સાથે તમારી કીનું જોડાણ કરો કે જેથી તમારા એકાઉન્ટમાં સાઇન ઇન કરવા માટે તમે તેનો ઉપયોગ કરી શકો</translation>
 <translation id="2371076942591664043">&amp;પૂર્ણ થાય ત્યારે ખોલો</translation>
-<translation id="2376559921867170420">જ્યારે તમારી Chromebook સેટ અપ કરેલ હોય, ત્યારે કોઈપણ સમયે તમારા આસિસ્ટંટની સહાય મેળવવા માટે આસિસ્ટંટ બટન દબાવો અથવા "ઓકે Google" બોલો.</translation>
 <translation id="2377319039870049694">સૂચિ દૃશ્ય પર સ્વિચ કરો</translation>
 <translation id="2377667304966270281">Hard Faults</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> ફાઇલો પસંદ કરી</translation>
@@ -1875,6 +1873,7 @@
 <translation id="381202950560906753">બીજી ઉમેરો</translation>
 <translation id="3812525830114410218">ખોટું પ્રમાણપત્ર</translation>
 <translation id="3813296892522778813">જો તમે શોધી રહ્યાં છો તે શોધી શકતાં ન હોવ તો <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome સહાય<ph name="END_LINK_CHROMIUM" /> પર જાઓ</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">પ્રદાન કરેલ નથી</translation>
 <translation id="3819752733757735746">સ્વિચ અ‍ૅક્સેસ (એક કે બે સ્વિચેસ વડે કમ્પ્યુટરને નિયંત્રિત કરો)</translation>
 <translation id="3819800052061700452">&amp;પૂર્ણ સ્ક્રીન</translation>
@@ -2045,7 +2044,6 @@
 <translation id="4068776064906523561">સાચવેલ ફિંગરપ્રિન્ટ</translation>
 <translation id="407173827865827707">ક્લિક કરવા પર</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: સાઇન ઇન ભૂલ</translation>
-<translation id="4071828814509176232">ઓકે Google</translation>
 <translation id="4074900173531346617">ઇમેઇલ હસ્તાક્ષરકર્તા પ્રમાણપત્ર</translation>
 <translation id="407520071244661467">સ્કેલ</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" />ને કાસ્ટ કરવામાં અસમર્થ.</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb
index a301464..93b6416 100644
--- a/chrome/app/resources/generated_resources_hi.xtb
+++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> पर <ph name="PEPPER_PLUGIN_NAME" /> आपके कंप्यूटर को एक्सेस करना चाहता है</translation>
 <translation id="2178614541317717477">CA समझौता</translation>
 <translation id="218070003709087997">प्रिंट की जाने वाली कॉपी की संख्या (1 से 999) दर्शाने के लिए किसी संख्या का उपयोग करें.</translation>
-<translation id="2183558561014688873">अपना डिवाइस चालू होने और अनलॉक होने पर कभी भी "OK Google" बोलें और अपनी Assistant सेवा एक्सेस करें.</translation>
 <translation id="2187895286714876935">सर्वर प्रमाणपत्र आयात गड़बड़ी</translation>
 <translation id="2187906491731510095">एक्सटेंशन अपडेट किए गए</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> खोलें</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">कुकी को छोड़कर, <ph name="SITE" /> का स्टोर किया हुआ सारा डेटा मिटा दिया जाएगा.</translation>
 <translation id="237058345584060620">अपनी 'सुरक्षा चाबी' को इस डिवाइस से जोड़ें ताकि आप अपने खाते में साइन इन करने के लिए इसका इस्तेमाल कर सकें</translation>
 <translation id="2371076942591664043">&amp;पू्र्ण होने पर खोलें</translation>
-<translation id="2376559921867170420">आपका Chromebook सेट अप हो जाने पर, किसी भी समय अपनी Assistant से मदद पाने के लिए Assistant बटन दबाएं या "OK Google" बोलें.</translation>
 <translation id="2377319039870049694">'सूची की तरह देखें' पर स्विच करें</translation>
 <translation id="2377667304966270281">हार्ड फ़ॉल्ट</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> फ़ाइलें चयनित</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">दूसरा जोड़ें</translation>
 <translation id="3812525830114410218">गलत प्रमाणपत्र</translation>
 <translation id="3813296892522778813">यदि आपको वह चीज़ नहीं मिल रही है जिसे आप खोज रहे हैं, तो <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome सहायता<ph name="END_LINK_CHROMIUM" /> पर जाएं</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">नहीं दिया गया</translation>
 <translation id="3819752733757735746">स्विच एक्सेस (बस एक या दो स्विच से कंप्यूटर नियंत्रित करें)</translation>
 <translation id="3819800052061700452">&amp;पूर्ण स्क्रीन</translation>
@@ -2048,7 +2047,6 @@
 <translation id="4068776064906523561">सहेजे गए फ़िंगरप्रिंट</translation>
 <translation id="407173827865827707">क्लिक करने पर</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: प्रवेश करने संबंधी गड़बड़ी</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">ईमेल हस्ताक्षरकर्ता प्रमाणपत्र</translation>
 <translation id="407520071244661467">स्केल</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> कास्ट नहीं हो पा रहा है.</translation>
@@ -3241,7 +3239,7 @@
 <translation id="5924047253200400718">सहायता प्राप्त करें<ph name="SCANNING_STATUS" /></translation>
 <translation id="5924527146239595929">नई फ़ोटो लें या मौजूदा फ़ोटो या आइकॉन चुनें.
     <ph name="LINE_BREAK" />
-    यह तस्वीर Chromebook के साइन इन स्क्रीन और लॉक स्क्रीन पर दिखाई देगी.</translation>
+    यह तस्वीर Chromebook की साइन इन स्क्रीन और लॉक स्क्रीन पर दिखाई देगी.</translation>
 <translation id="5925147183566400388">प्रमाणन अभ्यास कथन पॉइंटर</translation>
 <translation id="592880897588170157">PDF फ़ाइलों को Chrome में अपने आप खोलने के बजाय उन्हें डाउनलोड करें</translation>
 <translation id="5931146425219109062">आप जिन वेबसाइट पर जाते हैं, उन पर मौजूद अपना सभी डेटा पढ़ें और बदलें</translation>
diff --git a/chrome/app/resources/generated_resources_hr.xtb b/chrome/app/resources/generated_resources_hr.xtb
index 4933f51..f203caa 100644
--- a/chrome/app/resources/generated_resources_hr.xtb
+++ b/chrome/app/resources/generated_resources_hr.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> na domeni <ph name="PEPPER_PLUGIN_DOMAIN" /> želi pristupiti vašem računalu</translation>
 <translation id="2178614541317717477">CA kompromis</translation>
 <translation id="218070003709087997">Upotrijebite broj kako biste odredili broj primjeraka za ispis (od 1 do 999).</translation>
-<translation id="2183558561014688873">Pristupite Asistentu svaki put kad izgovorite "OK Google", a uređaj je aktivan i otključan.</translation>
 <translation id="2187895286714876935">Pogreška pri uvozu Certifikata poslužitelja</translation>
 <translation id="2187906491731510095">Proširenja ažurirana</translation>
 <translation id="2188881192257509750">Otvori aplikaciju <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Izbrisat će se svi podaci koje je pohranila web-lokacija <ph name="SITE" /> osim kolačića.</translation>
 <translation id="237058345584060620">Uparite ključ s ovim uređajem da biste ga mogli upotrebljavati za prijavu na račun</translation>
 <translation id="2371076942591664043">Otvori nakon &amp;dovršetka</translation>
-<translation id="2376559921867170420">Dok se Chromebook postavlja, pritisnite gumb Asistent ili recite "Ok Google" da biste dobili pomoć od Asistenta u bilo kojem trenutku</translation>
 <translation id="2377319039870049694">Prebaci na prikaz popisa</translation>
 <translation id="2377667304966270281">Pogreške tvrdog diska</translation>
 <translation id="2378075407703503998">Odabrane datoteke: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Dodaj još jedan</translation>
 <translation id="3812525830114410218">Neispravan certifikat</translation>
 <translation id="3813296892522778813">Ako ne možete pronaći ono što tražite, otvorite <ph name="BEGIN_LINK_CHROMIUM" />pomoć za Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Nenavedeno</translation>
 <translation id="3819752733757735746">Prekidač za pristup (upravljajte računalom uz pomoć jednog ili dvaju prekidača)</translation>
 <translation id="3819800052061700452">&amp;Puni ekran</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Spremljeni otisci prstiju</translation>
 <translation id="407173827865827707">Na klik</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: pogreška prijave</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certifikat potpisnika e-pošte</translation>
 <translation id="407520071244661467">Skaliranje</translation>
 <translation id="4075639477629295004">Nije moguće emitirati <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_hu.xtb b/chrome/app/resources/generated_resources_hu.xtb
index fb36811..c34c4ca 100644
--- a/chrome/app/resources/generated_resources_hu.xtb
+++ b/chrome/app/resources/generated_resources_hu.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">A(z) <ph name="PEPPER_PLUGIN_DOMAIN" /> webhelyen található <ph name="PEPPER_PLUGIN_NAME" /> bővítmény hozzá szeretne férni a számítógéphez</translation>
 <translation id="2178614541317717477">A tanúsítványkibocsátó veszélyeztetve</translation>
 <translation id="218070003709087997">Számmal jelezze, hogy hány példányt kell nyomtatni (1–999).</translation>
-<translation id="2183558561014688873">Segédjéhez bármikor hozzáférhet az „OK Google” kimondásával, ha eszköze nincs alvó üzemmódban, és fel is van oldva.</translation>
 <translation id="2187895286714876935">Hiba a szervertanúsítvány importálásánál</translation>
 <translation id="2187906491731510095">Bővítmények frissítve</translation>
 <translation id="2188881192257509750">A(z) <ph name="APPLICATION" /> megnyitása</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">A cookie-kat kivéve a(z) <ph name="SITE" /> által tárolt minden adat törlődik.</translation>
 <translation id="237058345584060620">Párosítsa a hardverkulcsot az eszközhöz, így bejelentkezhet fiókjába</translation>
 <translation id="2371076942591664043">Megnyitás, amikor &amp;kész</translation>
-<translation id="2376559921867170420">Miután beállította a Chromebookot, a Segéd-gomb megnyomásával, illetve az „Ok Google” kimondásával bármikor segítséget kérhet Segédjétől.</translation>
 <translation id="2377319039870049694">Váltás listanézetre</translation>
 <translation id="2377667304966270281">Súlyos laphiba</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> fájl kiválasztva</translation>
@@ -1880,6 +1878,7 @@
 <translation id="381202950560906753">Még egy hozzáadása</translation>
 <translation id="3812525830114410218">Helytelen tanúsítvány</translation>
 <translation id="3813296892522778813">Ha nem találja, amit keres, próbálkozzon a <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome súgójában<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Nincs megadva</translation>
 <translation id="3819752733757735746">Kapcsolóalapú hozzáférés (a számítógép irányítása egy vagy két kapcsolóval)</translation>
 <translation id="3819800052061700452">&amp;Teljes képernyő</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Mentett ujjlenyomatok</translation>
 <translation id="407173827865827707">Kattintásra</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: bejelentkezési hiba</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">E-mail aláíró tanúsítvány</translation>
 <translation id="407520071244661467">Átméretezés</translation>
 <translation id="4075639477629295004">Nem lehet átküldeni a következőt: <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index 3bba622..26ed3f17 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Plugin <ph name="PEPPER_PLUGIN_NAME" /> di <ph name="PEPPER_PLUGIN_DOMAIN" /> ingin mengakses komputer Anda</translation>
 <translation id="2178614541317717477">CA Mencurigakan</translation>
 <translation id="218070003709087997">Gunakan angka untuk mengindikasikan jumlah salinan yang akan dicetak (1 sampai 999).</translation>
-<translation id="2183558561014688873">Mengakses Asisten setiap kali Anda mengucapkan "Ok Google" saat perangkat aktif dan tidak terkunci</translation>
 <translation id="2187895286714876935">Kesalahan Impor Sertifikat Server</translation>
 <translation id="2187906491731510095">Ekstensi diupdate</translation>
 <translation id="2188881192257509750">Buka <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Semua data yang disimpan oleh <ph name="SITE" /> akan dihapus, kecuali cookie.</translation>
 <translation id="237058345584060620">Sambungkan kunci ke perangkat ini agar dapat digunakan untuk login ke akun</translation>
 <translation id="2371076942591664043">Buka setelah &amp;selesai</translation>
-<translation id="2376559921867170420">Jika Chromebook sudah disiapkan, tekan tombol Asisten dan ucapkan "OK Google" untuk mendapatkan bantuan dari Asisten kapan saja.</translation>
 <translation id="2377319039870049694">Beralih ke tampilan daftar</translation>
 <translation id="2377667304966270281">Hard Fault</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> file dipilih</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Tambahkan yang lain</translation>
 <translation id="3812525830114410218">Sertifikat buruk</translation>
 <translation id="3813296892522778813">Buka <ph name="BEGIN_LINK_CHROMIUM" />bantuan Google Chrome<ph name="END_LINK_CHROMIUM" /> jika tidak dapat menemukan yang Anda cari</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Tidak dicantumkan</translation>
 <translation id="3819752733757735746">Tuas akses (mengontrol komputer hanya menggunakan satu atau dua tuas)</translation>
 <translation id="3819800052061700452">Layar penuh</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Sidik jari yang disimpan</translation>
 <translation id="407173827865827707">Saat diklik</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: kesalahan saat masuk</translation>
-<translation id="4071828814509176232">“Ok Google”</translation>
 <translation id="4074900173531346617">Sertifikat Penandatangan Email</translation>
 <translation id="407520071244661467">Skala</translation>
 <translation id="4075639477629295004">Tidak dapat mentransmisikan <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_it.xtb b/chrome/app/resources/generated_resources_it.xtb
index f58b763..00be777e 100644
--- a/chrome/app/resources/generated_resources_it.xtb
+++ b/chrome/app/resources/generated_resources_it.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> su <ph name="PEPPER_PLUGIN_DOMAIN" /> vuole accedere al computer</translation>
 <translation id="2178614541317717477">Compromesso CA</translation>
 <translation id="218070003709087997">Specifica un numero per indicare la quantità di copie da stampare (da 1 a 999).</translation>
-<translation id="2183558561014688873">Accedi all'assistente ogni volta che pronunci "Ok Google" quando il tuo dispositivo è attivo e sbloccato.</translation>
 <translation id="2187895286714876935">Errore di importazione del certificato del server</translation>
 <translation id="2187906491731510095">Estensioni aggiornate</translation>
 <translation id="2188881192257509750">Apri <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Tutti i dati archiviati dal sito <ph name="SITE" />, eccetto i cookie, verranno eliminati.</translation>
 <translation id="237058345584060620">Accoppia il tuo token a questo dispositivo per poterlo utilizzare per accedere al tuo account.</translation>
 <translation id="2371076942591664043">Apri al &amp;termine</translation>
-<translation id="2376559921867170420">Dopo avere configurato il Chromebook, premi il pulsante Assistente o dì "Ok Google" per farti aiutare dall'assistente in qualsiasi momento.</translation>
 <translation id="2377319039870049694">Passa alla visualizzazione elenco</translation>
 <translation id="2377667304966270281">Errori hardware</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> file selezionati</translation>
@@ -1876,6 +1874,7 @@
 <translation id="381202950560906753">Aggiungine un'altra</translation>
 <translation id="3812525830114410218">Certificato non valido</translation>
 <translation id="3813296892522778813">Visita la <ph name="BEGIN_LINK_CHROMIUM" />guida di Google Chrome<ph name="END_LINK_CHROMIUM" /> se non riesci a trovare quello che cerchi</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Non fornito</translation>
 <translation id="3819752733757735746">Switch Access (consente l'utilizzo del computer semplicemente mediante uno o due sensori)</translation>
 <translation id="3819800052061700452">&amp;Schermo intero</translation>
@@ -2046,7 +2045,6 @@
 <translation id="4068776064906523561">Impronte digitali salvate</translation>
 <translation id="407173827865827707">Al clic</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: errore di accesso</translation>
-<translation id="4071828814509176232">"Ok Google"</translation>
 <translation id="4074900173531346617">Certificato del firmatario email</translation>
 <translation id="407520071244661467">Scala</translation>
 <translation id="4075639477629295004">Impossibile trasmettere <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb
index 2867fc5a8..bbe3c3f 100644
--- a/chrome/app/resources/generated_resources_iw.xtb
+++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> ב-<ph name="PEPPER_PLUGIN_DOMAIN" /> רוצה גישה למחשב שלך</translation>
 <translation id="2178614541317717477">‏רשות האישורים (CA) בסכנה</translation>
 <translation id="218070003709087997">ציין את מספר העותקים שיש להדפיס (1 עד 999).</translation>
-<translation id="2183558561014688873">‏גישה אל Assistant בכל פעם שאומרים "OK Google" כשהמכשיר ער ולא נעול.</translation>
 <translation id="2187895286714876935">שגיאת ייבוא של אישור שרת</translation>
 <translation id="2187906491731510095">התוספים עודכנו</translation>
 <translation id="2188881192257509750">פתח את <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">‏כל הנתונים שאוחסנו על-ידי <ph name="SITE" /> יימחקו, מלבד קובצי ה-Cookie.</translation>
 <translation id="237058345584060620">צריך להתאים את המפתח למכשיר זה כדי שניתן יהיה להשתמש בו לכניסה לחשבון</translation>
 <translation id="2371076942591664043">פתח &amp;בסיום</translation>
-<translation id="2376559921867170420">‏אחרי הגדרת ה-Chromebook, כדי לקבל עזרה מה-Assistant אפשר ללחוץ על לחצן ה-Assistant או לומר "OK Google".</translation>
 <translation id="2377319039870049694">מעבר לתצוגת רשימה</translation>
 <translation id="2377667304966270281">שגיאות חמורות</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> קבצים נבחרו</translation>
@@ -1876,6 +1874,7 @@
 <translation id="381202950560906753">להמשך הוספה</translation>
 <translation id="3812525830114410218">אישור פגום</translation>
 <translation id="3813296892522778813">‏אם אתה לא מוצא את מה שחיפשת, עבור אל <ph name="BEGIN_LINK_CHROMIUM" />מרכז העזרה של Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">לא צוין</translation>
 <translation id="3819752733757735746">גישה באמצעות מתג (שלוט במחשב בעזרת מתג אחד או שניים בלבד)</translation>
 <translation id="3819800052061700452">&amp;מסך מלא</translation>
@@ -2046,7 +2045,6 @@
 <translation id="4068776064906523561">טביעות אצבע שמורות</translation>
 <translation id="407173827865827707">בזמן לחיצה</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: כניסה שגויה</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">אישור חותם אימייל</translation>
 <translation id="407520071244661467">שנה קנה מידה</translation>
 <translation id="4075639477629295004">לא ניתן להעביר את <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index 5f1c330..50c22061 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> の <ph name="PEPPER_PLUGIN_NAME" /> プラグインから、パソコンへのアクセス許可を求められています</translation>
 <translation id="2178614541317717477">認証局が侵害された</translation>
 <translation id="218070003709087997">印刷部数を数値(1~999)で指定してください。</translation>
-<translation id="2183558561014688873">端末のスリープとロックが解除されている状態で「OK Google」と話すと、いつでもアシスタントにアクセスできます。</translation>
 <translation id="2187895286714876935">サーバー証明書インポート エラー</translation>
 <translation id="2187906491731510095">拡張機能が更新されました</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> を開く</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252"><ph name="SITE" /> により保存された、Cookie 以外の全データが削除されます。</translation>
 <translation id="237058345584060620">アカウントへのログインに使用できるように、キーをこの端末とペア設定します</translation>
 <translation id="2371076942591664043">ダウンロードしたら開く(&amp;D)</translation>
-<translation id="2376559921867170420">Chromebook を設定したら、いつでもアシスタント ボタンを押すか「OK Google」と話しかけてアシスタントを呼び出すことができます。</translation>
 <translation id="2377319039870049694">リスト表示に切り替え</translation>
 <translation id="2377667304966270281">ハードの障害数</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> 個のファイルを選択</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">別の指紋を登録</translation>
 <translation id="3812525830114410218">不適切な証明書</translation>
 <translation id="3813296892522778813">探しているものが見つからない場合は、<ph name="BEGIN_LINK_CHROMIUM" />Google Chrome のヘルプ<ph name="END_LINK_CHROMIUM" />をご覧ください。</translation>
+<translation id="3813984289128269159">OK Google</translation>
 <translation id="3817579325494460411">指定されていません</translation>
 <translation id="3819752733757735746">スイッチ アクセス(スイッチ 1 つまたは 2 つでパソコンを制御)</translation>
 <translation id="3819800052061700452">全画面表示(&amp;F)</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">保存した指紋</translation>
 <translation id="407173827865827707">クリックされた場合のみ</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: ログインエラー</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">メール署名者の証明書</translation>
 <translation id="407520071244661467">倍率</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> をキャストできません。</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index 7cda3d3..7994577 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> ನಲ್ಲಿ ಇರುವ <ph name="PEPPER_PLUGIN_DOMAIN" />, ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್‌ಗೆ ಪ್ರವೇಶಿಸಲು ಬಯಸುತ್ತದೆ</translation>
 <translation id="2178614541317717477">CA ಹೊಂದಾಣಿಕೆ</translation>
 <translation id="218070003709087997">ಎಷ್ಟು ಪ್ರತಿಗಳನ್ನು ಮುದ್ರಿಸಬೇಕೆಂದು (1 ರಿಂದ 999) ಸೂಚಿಸಲು ಸಂಖ್ಯೆಯನ್ನು ಬಳಸಿ.</translation>
-<translation id="2183558561014688873">ನಿಮ್ಮ ಸಾಧನವು ಆನ್ ಮತ್ತು ಅನ್‌ಲಾಕ್ ಆಗಿರುವಾಗ, ಯಾವಾಗ ಬೇಕಾದರೂ "ಓಕೆ Google" ಎಂದು ಹೇಳಿ ನಿಮ್ಮ ಅಸಿಸ್ಟೆಂಟ್‌ಗೆ ಪ್ರವೇಶ ಪಡೆಯಿರಿ.</translation>
 <translation id="2187895286714876935">ಸರ್ವರ್ ಪ್ರಮಾಣಪತ್ರದ ಆಮದು ದೋಷ</translation>
 <translation id="2187906491731510095">ವಿಸ್ತರಣೆಗಳನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> ತೆರೆಯಿರಿ</translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">ಕುಕೀಗಳನ್ನು ಹೊರತುಪಡಿಸಿ, <ph name="SITE" /> ಸಂಗ್ರಹಣೆ ಮಾಡಿರುವ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುವುದು.</translation>
 <translation id="237058345584060620">ನಿಮ್ಮ ಕೀಯನ್ನು ಈ ಸಾಧನಕ್ಕೆ ಜೋಡಿಸುವುದರಿಂದ, ಅದನ್ನು ನಿಮ್ಮ ಖಾತೆಗೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಬಳಸಬಹುದು</translation>
 <translation id="2371076942591664043">&amp;ಮುಗಿಸಿದಾಗ ತೆರೆಯಿರಿ</translation>
-<translation id="2376559921867170420">ನಿಮ್ಮ Chromebook ಅನ್ನು ಹೊಂದಿಸಿದಾಗ, ಅಸಿಸ್ಟೆಂಟ್ ಬಟನ್ ಅನ್ನು ಒತ್ತಿರಿ ಅಥವಾ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ಅಸಿಸ್ಟೆಂಟ್‌‌ನಿಂದ ಸಹಾಯ ಪಡೆಯಲು "ಓಕೆ Google" ಎಂದು ಹೇಳಿ.</translation>
 <translation id="2377319039870049694">ಪಟ್ಟಿ ವೀಕ್ಷಣೆಗೆ ಬದಲಾಯಿಸಿ</translation>
 <translation id="2377667304966270281">ಹಾರ್ಡ್ ಫಾಲ್ಟ್ಸ್</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> ಫೈಲ್‌ಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ</translation>
@@ -1876,6 +1874,7 @@
 <translation id="381202950560906753">ಇನ್ನೊಂದನ್ನು ಸೇರಿಸಿ</translation>
 <translation id="3812525830114410218">ತಪ್ಪು ಪ್ರಮಾಣಪತ್ರ</translation>
 <translation id="3813296892522778813">ನೀವು ಹುಡುಕುತ್ತಿರುವುದು ದೊರೆಯದೇ ಇದ್ದರೆ <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome ಸಹಾಯ<ph name="END_LINK_CHROMIUM" />ಕ್ಕೆ ಹೋಗಿ</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">ಒದಗಿಸಿಲ್ಲ</translation>
 <translation id="3819752733757735746">ಪ್ರವೇಶವನ್ನು ಬದಲಾಯಿಸಿ (ಒಂದು ಅಥವಾ ಎರಡು ಬದಲಾವಣೆಯಲ್ಲಿ ಕಂಪ್ಯೂಟರ್‌ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ)</translation>
 <translation id="3819800052061700452">&amp;ಪೂರ್ಣ-ಪರದೆ</translation>
@@ -2046,7 +2045,6 @@
 <translation id="4068776064906523561">ಉಳಿಸಿದ ಬೆರಳಚ್ಚುಗಳು</translation>
 <translation id="407173827865827707">ಕ್ಲಿಕ್ ಮಾಡಿದಾಗ</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: ಸೈನ್‌ ಇನ್‌ ದೋಷ</translation>
-<translation id="4071828814509176232">ಓಕೆ Google</translation>
 <translation id="4074900173531346617">ಇಮೇಲ್ ಸಹಿ ಮಾಡುವವರ ಪ್ರಮಾಣಪತ್ರ</translation>
 <translation id="407520071244661467">ಮಾಪಕ</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> ಬಿತ್ತರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ.</translation>
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index dfa6131..4e2dc0d0 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" />의 <ph name="PEPPER_PLUGIN_NAME" />에서 내 컴퓨터에 액세스하려고 합니다</translation>
 <translation id="2178614541317717477">CA 손상</translation>
 <translation id="218070003709087997">숫자로 인쇄 부수를 표시하세요(1부터 999까지).</translation>
-<translation id="2183558561014688873">기기가 켜져 있고 잠금 해제되어 있을 때 "OK Google"이라고 말하면 언제든지 어시스턴트를 이용할 수 있습니다.</translation>
 <translation id="2187895286714876935">서버 인증서 가져오기 오류</translation>
 <translation id="2187906491731510095">확장 프로그램 업데이트됨</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> 열기</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252"><ph name="SITE" />에서 저장한 모든 데이터가 삭제됩니다. 쿠키는 삭제되지 않습니다.</translation>
 <translation id="237058345584060620">키를 사용하여 계정에 로그인할 수 있도록 키를 이 기기와 페어링하세요.</translation>
 <translation id="2371076942591664043">완료되면 열기(&amp;D)</translation>
-<translation id="2376559921867170420">Chromebook 설정이 완료되면 언제든지 어시스턴트 버튼을 누르거나 "Ok Google"이라고 말하여 어시스턴트로부터 도움을 받으세요.</translation>
 <translation id="2377319039870049694">목록 보기로 전환</translation>
 <translation id="2377667304966270281">하드 결함</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" />개의 파일이 선택됨</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">다른 지문 추가</translation>
 <translation id="3812525830114410218">잘못된 인증서</translation>
 <translation id="3813296892522778813">원하는 자료를 찾지 못했다면 <ph name="BEGIN_LINK_CHROMIUM" />Chrome 도움말<ph name="END_LINK_CHROMIUM" />을 참조하세요.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">입력하지 않음</translation>
 <translation id="3819752733757735746">스위치 제어(스위치 1~2회 사용으로 컴퓨터 제어)</translation>
 <translation id="3819800052061700452">전체화면(&amp;F)</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">저장된 지문</translation>
 <translation id="407173827865827707">클릭 시</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: 로그인 오류</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">이메일 서명자 인증서</translation>
 <translation id="407520071244661467">배율</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" />을(를) 전송할 수 없습니다.</translation>
diff --git a/chrome/app/resources/generated_resources_lt.xtb b/chrome/app/resources/generated_resources_lt.xtb
index c03470f..0ab5baf 100644
--- a/chrome/app/resources/generated_resources_lt.xtb
+++ b/chrome/app/resources/generated_resources_lt.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Adresu <ph name="PEPPER_PLUGIN_DOMAIN" /> esantis papildinys „<ph name="PEPPER_PLUGIN_NAME" />“ nori pasiekti kompiuterį</translation>
 <translation id="2178614541317717477">CA pažeidimo galimybė</translation>
 <translation id="218070003709087997">Skaičiumi nurodykite, kiek kopijų spausdinti (nuo 1 iki 999).</translation>
-<translation id="2183558561014688873">Pasiekite Padėjėją bet kuriuo metu pasakę „Ok Google“, kai įrenginys veikia ir yra neužrakintas.</translation>
 <translation id="2187895286714876935">Serverio sertifikato importavimo klaida</translation>
 <translation id="2187906491731510095">Plėtiniai atnaujinti</translation>
 <translation id="2188881192257509750">Atidaryti „<ph name="APPLICATION" />“</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Visi <ph name="SITE" /> saugomi duomenys bus ištrinti, išskyrus slapukus.</translation>
 <translation id="237058345584060620">Susiekite raktą su šiuo įrenginiu, kad jį naudodami galėtumėte prisijungti prie paskyros</translation>
 <translation id="2371076942591664043">Baigus &amp;atidaryti</translation>
-<translation id="2376559921867170420">Kai „Chromebook“ nustatytas, norėdami bet kuriuo metu gauti pagalbos iš Padėjėjo, paspauskite Padėjėjo mygtuką arba pasakykite „Ok Google“.</translation>
 <translation id="2377319039870049694">Perjungti į sąrašo rodinį</translation>
 <translation id="2377667304966270281">Sunkūs gedimai</translation>
 <translation id="2378075407703503998">Pasirinkta failų: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Pridėti kitą</translation>
 <translation id="3812525830114410218">Netinkamas sertifikatas</translation>
 <translation id="3813296892522778813">Jei nerandate to, ko ieškote, eikite į <ph name="BEGIN_LINK_CHROMIUM" />„Google Chrome“ pagalbos puslapį<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Nepateikta</translation>
 <translation id="3819752733757735746">Prieiga jungikliu (valdykite kompiuterį tik vienu ar dviem jungikliais)</translation>
 <translation id="3819800052061700452">&amp;Visas ekranas</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Išsaugoti kontroliniai kodai</translation>
 <translation id="407173827865827707">Spustelėjus</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: prisijungimo klaida</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">El. laiškus pasirašančiojo sertifikatas</translation>
 <translation id="407520071244661467">Mastelis</translation>
 <translation id="4075639477629295004">Nepavyko perduoti „<ph name="FILE_NAME" />“.</translation>
diff --git a/chrome/app/resources/generated_resources_lv.xtb b/chrome/app/resources/generated_resources_lv.xtb
index f1fced4..ada68f4a 100644
--- a/chrome/app/resources/generated_resources_lv.xtb
+++ b/chrome/app/resources/generated_resources_lv.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Spraudnim <ph name="PEPPER_PLUGIN_NAME" /> domēnā <ph name="PEPPER_PLUGIN_DOMAIN" /> ir nepieciešama piekļuve jūsu datoram.</translation>
 <translation id="2178614541317717477">CA drošības politikas apdraudējums</translation>
 <translation id="218070003709087997">Izmantojiet skaitli, lai norādītu, cik eksemplāri jādrukā (1–999).</translation>
-<translation id="2183558561014688873">Ja jūsu ierīce ir aktivizēta un atbloķēta, Asistentam varat piekļūt jebkurā laikā, pasakot frāzi “OK Google”.</translation>
 <translation id="2187895286714876935">Servera sertifikāta importēšanas kļūda</translation>
 <translation id="2187906491731510095">Paplašinājumi ir atjaunināti</translation>
 <translation id="2188881192257509750">Atvērt lietojumprogrammu <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Tiks izdzēsti visi vietnes <ph name="SITE" /> saglabātie dati, izņemot sīkfailus.</translation>
 <translation id="237058345584060620">Savienojiet atslēgu pārī ar šo ierīci, lai varētu pierakstīties kontā, izmantojot atslēgu.</translation>
 <translation id="2371076942591664043">Atvērt, kad esat beidzis</translation>
-<translation id="2376559921867170420">Kad Chromebook dators ir iestatīts, nospiediet Asistenta pogu vai sakiet “Ok Google”, lai jebkurā brīdī saņemtu palīdzību no Asistenta.</translation>
 <translation id="2377319039870049694">Pāriet uz saraksta skatījumu</translation>
 <translation id="2377667304966270281">Nopietnas kļūdas</translation>
 <translation id="2378075407703503998">Atlasīti <ph name="SELCTED_FILE_COUNT" /> faili.</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Pievienot citu</translation>
 <translation id="3812525830114410218">Nederīgs sertifikāts</translation>
 <translation id="3813296892522778813">Ja nevarat atrast meklēto saturu, pārejiet uz <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome palīdzību<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Nav norādīts</translation>
 <translation id="3819752733757735746">Slēdžu piekļuve (kontrolējiet datoru ar vienu vai diviem slēdžiem)</translation>
 <translation id="3819800052061700452">&amp;Pilnekrāna režīms</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Saglabātie pirkstu nospiedumi</translation>
 <translation id="407173827865827707">Noklikšķinot</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: pierakstīšanās kļūda</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">E-pasta parakstītāja sertifikāts</translation>
 <translation id="407520071244661467">Mērogs</translation>
 <translation id="4075639477629295004">Nevar apraidīt failu <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb
index 2496f740..85cf83b3 100644
--- a/chrome/app/resources/generated_resources_ml.xtb
+++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724">നിങ്ങളുടെ കമ്പ്യൂട്ടർ ആക്‌സസ് ചെയ്യാൻ <ph name="PEPPER_PLUGIN_DOMAIN" /> എന്നതിലെ <ph name="PEPPER_PLUGIN_NAME" /> ആഗ്രഹിക്കുന്നു</translation>
 <translation id="2178614541317717477">CA കോംപ്രമൈസ്</translation>
 <translation id="218070003709087997">എത്ര പകർപ്പുകൾ പ്രിന്റുചെയ്യണമെന്ന് സൂചിപ്പിക്കാൻ ഒരു നമ്പര്‍ ഉപയോഗിക്കുക (1 മുതൽ 999 വരെ).</translation>
-<translation id="2183558561014688873">നിങ്ങളുടെ ഉപകരണം സജീവമായി, അൺലോക്ക് ചെയ്യുമ്പോൾ "OK Google" എന്നുപറഞ്ഞ് ഏതുസമയത്തും നിങ്ങളുടെ അസിസ്‌റ്റന്റിനെ ആക്‌സസ് ചെയ്യുക.</translation>
 <translation id="2187895286714876935">സെര്‍വര്‍ സാക്‍ഷ്യപത്ര ഇറക്കുമതി പിശക്</translation>
 <translation id="2187906491731510095">വിപുലീകരണങ്ങൾ അപ്‌ഡേറ്റ് ചെയ്‌തു</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> തുറക്കുക</translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">കുക്കികൾ ഒഴികെ, <ph name="SITE" /> സംഭരിച്ച മുഴുവൻ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും.</translation>
 <translation id="237058345584060620">നിങ്ങളുടെ അക്കൗണ്ടിലേക്ക് സൈൻ ഇൻ ചെയ്യാൻ കീ ഉപയോഗിക്കുന്നതിന് ഈ ഉപകരണവുമായി കീ ജോടിയാക്കുക</translation>
 <translation id="2371076942591664043">ചെയ്തുകഴിയുമ്പോള്‍ &amp;തുറക്കുക</translation>
-<translation id="2376559921867170420">നിങ്ങളുടെ Chromebook സജ്ജീകരിക്കുമ്പോൾ, ഏതുസമയത്തും നിങ്ങളുടെ അസിസ്‌റ്റന്റിൽ നിന്ന് സഹായം ലഭിക്കുന്നതിന് അസിസ്റ്റന്റ് ബട്ടൺ അമർത്തുക അല്ലെങ്കിൽ "Ok Google" എന്ന് പറയുക.</translation>
 <translation id="2377319039870049694">ലിസ്റ്റ് കാഴ്‌ചയിലേക്ക് മാറുക</translation>
 <translation id="2377667304966270281">ഹാർഡ് ഫോൾട്ടുകൾ</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> ഫയലുകൾ തിരഞ്ഞെടുത്തു</translation>
@@ -1876,6 +1874,7 @@
 <translation id="381202950560906753">മറ്റൊന്ന് ചേർക്കുക</translation>
 <translation id="3812525830114410218">മോശം സർട്ടിഫിക്കറ്റ്</translation>
 <translation id="3813296892522778813">നിങ്ങൾ തിരയുന്നത് കണ്ടില്ലെങ്കിൽ, <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome സഹായത്തിൽ<ph name="END_LINK_CHROMIUM" /> പോകുക</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">നൽകിയിട്ടില്ല</translation>
 <translation id="3819752733757735746">ആക്‌സസ്സ് മാറുക (ഒന്നോ രണ്ടോ തവണ മാറുന്നതിലൂടെ കമ്പ്യൂട്ടർ നിയന്ത്രിക്കുക)</translation>
 <translation id="3819800052061700452">&amp;പൂര്‍ണ്ണ സ്‌ക്രീന്‍</translation>
@@ -2045,7 +2044,6 @@
 <translation id="4068776064906523561">സംരക്ഷിച്ച വിരലടയാളങ്ങൾ</translation>
 <translation id="407173827865827707">ക്ലിക്കിൽ</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: സൈൻ ഇൻ പിശക്</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">സൈനര്‍‌ സര്‍‌ട്ടിഫിക്കറ്റ് ഇമെയില്‍‌ അയയ്‌ക്കുക</translation>
 <translation id="407520071244661467">സ്കെയിൽ</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> കാസ്‌റ്റുചെയ്യാനാവുന്നില്ല.</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index 0112b31..1069f240 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -794,7 +794,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> वरील <ph name="PEPPER_PLUGIN_NAME" /> ला तुमचा काँप्युटर अ‍ॅक्सेस करायचा आहे</translation>
 <translation id="2178614541317717477">CA तडजोड</translation>
 <translation id="218070003709087997">किती प्रती प्रिंट करायच्या ते सूचित करण्यासाठी संख्या वापरा (1 ते 999).</translation>
-<translation id="2183558561014688873">जेव्हा तुमचे डिव्हाइस सक्रिय आणि अनलॉक केलेले असते तेव्हा तुम्ही कधीही "OK Google" म्हणून तुमचे असिस्टंट अॅक्सेस करा.</translation>
 <translation id="2187895286714876935">सर्व्हर प्रमाणपत्र आयात एरर</translation>
 <translation id="2187906491731510095">विस्तार अपडेट केले</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> उघडा</translation>
@@ -923,7 +922,6 @@
 <translation id="2369536625682139252">कुकी वगळता <ph name="SITE" /> द्वारे स्टोअर केलेला सर्व डेटा हटवला जाईल.</translation>
 <translation id="237058345584060620">या डिव्हाइसला तुमची की जोडा जेणेकरुन तुम्ही ते तुमच्या खात्यामध्ये साइन इन करण्यासाठी वापरू शकता</translation>
 <translation id="2371076942591664043">&amp;पूर्ण झाल्यानंतर उघडा</translation>
-<translation id="2376559921867170420">तुमच्या असिस्टंट कडून कधीही मदत मिळवण्यासाठी तुमचे Chromebook सेट केल्यावर, असिस्टंट बटण दाबा किंवा "OK Google" म्हणा.</translation>
 <translation id="2377319039870049694">सूची व्‍ह्यूवर स्विच करा</translation>
 <translation id="2377667304966270281">हार्ड फॉल्ट</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> फायली निवडल्या</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">दुसरे जोडा</translation>
 <translation id="3812525830114410218">खराब प्रमाणपत्र</translation>
 <translation id="3813296892522778813">आपण जे शोधत आहात ते आपल्याला सापडले नसेल तर <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome मदत<ph name="END_LINK_CHROMIUM" /> वर जा</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">प्रदान केले नाही</translation>
 <translation id="3819752733757735746">प्रवेश स्विच करा (केवळ एक किंवा दोन स्विचसह कॉंप्युटर नियंत्रित करा)</translation>
 <translation id="3819800052061700452">&amp;पूर्ण स्क्रीन</translation>
@@ -2050,7 +2049,6 @@
 <translation id="4068776064906523561">फिंगरप्रिंट सेव्ह केले</translation>
 <translation id="407173827865827707">क्लिकवर</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: साइन इन एरर</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">ईमेल स्वाक्षरीकर्ता प्रमाणपत्र</translation>
 <translation id="407520071244661467">स्केल</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> कास्ट करू शकलो नाही.</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb
index c9e95e8..baa7db6 100644
--- a/chrome/app/resources/generated_resources_ms.xtb
+++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Pemalam <ph name="PEPPER_PLUGIN_NAME" /> di <ph name="PEPPER_PLUGIN_DOMAIN" /> ingin mengakses komputer anda</translation>
 <translation id="2178614541317717477">Tolak ansur CA</translation>
 <translation id="218070003709087997">Gunakan nombor untuk menunjukkan bilangan salinan untuk dicetak (1 hingga 999).</translation>
-<translation id="2183558561014688873">Akses Assistant anda pada bila-bila masa anda menyebut "OK Google" semasa skrin anda hidup dan tidak berkunci.</translation>
 <translation id="2187895286714876935">Ralat Import Sijil Pelayan</translation>
 <translation id="2187906491731510095">Sambungan dikemas kini</translation>
 <translation id="2188881192257509750">Buka <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Semua data yang disimpan oleh <ph name="SITE" /> akan dipadamkan, kecuali kuki.</translation>
 <translation id="237058345584060620">Gandingkan kunci anda dengan peranti ini supaya anda boleh menggunakan kunci itu untuk log masuk ke akaun anda</translation>
 <translation id="2371076942591664043">Buka apabila &amp;selesai</translation>
-<translation id="2376559921867170420">Apabila Chromebook anda selesai disediakan, tekan butang Assistant atau sebut "OK Google" untuk mendapatkan bantuan daripada Assistant anda pada bila-bila masa.</translation>
 <translation id="2377319039870049694">Tukar kepada paparan senarai</translation>
 <translation id="2377667304966270281">Kesalahan Keras</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> fail dipilih</translation>
@@ -1880,6 +1878,7 @@
 <translation id="381202950560906753">Tambahkan yang lain</translation>
 <translation id="3812525830114410218">Sijil tidak sah</translation>
 <translation id="3813296892522778813">Pergi ke <ph name="BEGIN_LINK_CHROMIUM" />bantuan Google Chrome<ph name="END_LINK_CHROMIUM" /> jika anda tidak menemui perkara yang dicari</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Tidak diberikan</translation>
 <translation id="3819752733757735746">Akses suis (kawal komputer dengan satu atau dua suis sahaja)</translation>
 <translation id="3819800052061700452">&amp;Skrin penuh</translation>
@@ -2050,7 +2049,6 @@
 <translation id="4068776064906523561">Cap jari disimpan</translation>
 <translation id="407173827865827707">Apabila diklik</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" /> : ralat log masuk</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">Sijil Penandatangan E-mel</translation>
 <translation id="407520071244661467">Skala</translation>
 <translation id="4075639477629295004">Tidak dapat menghantar <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb
index 5243b75c..f04d5c11 100644
--- a/chrome/app/resources/generated_resources_nl.xtb
+++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> op <ph name="PEPPER_PLUGIN_DOMAIN" /> vraagt om toegang tot je computer</translation>
 <translation id="2178614541317717477">Inbreuk op CA</translation>
 <translation id="218070003709087997">Gebruik een cijfer om aan te geven hoeveel exemplaren er moeten worden afgedrukt (1-999).</translation>
-<translation id="2183558561014688873">Wanneer je apparaat is ingeschakeld en ontgrendeld, kun je de Assistent openen door 'Oké Google' te zeggen.</translation>
 <translation id="2187895286714876935">Fout bij importeren van servercertificaat</translation>
 <translation id="2187906491731510095">Extensies geüpdatet</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> openen</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Alle gegevens die zijn opgeslagen door <ph name="SITE" /> worden verwijderd, behalve cookies.</translation>
 <translation id="237058345584060620">Koppel je sleutel met dit apparaat zodat je de sleutel kunt gebruiken om in te loggen op je account</translation>
 <translation id="2371076942591664043">Openen wanneer geree&amp;d</translation>
-<translation id="2376559921867170420">Wanneer je Chrome is ingesteld, kun je op elk gewenst moment op de Assistent-knop drukken of 'Oké Google' zeggen om hulp van de Assistent te krijgen.</translation>
 <translation id="2377319039870049694">Overschakelen naar lijstweergave</translation>
 <translation id="2377667304966270281">Harde fouten</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> bestanden geselecteerd</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Nog een toevoegen</translation>
 <translation id="3812525830114410218">Verkeerd certificaat</translation>
 <translation id="3813296892522778813">Ga naar de <ph name="BEGIN_LINK_CHROMIUM" />Help van Google Chrome<ph name="END_LINK_CHROMIUM" /> als je niet kunt vinden wat je zoekt</translation>
+<translation id="3813984289128269159">Oké Google</translation>
 <translation id="3817579325494460411">Niet opgegeven</translation>
 <translation id="3819752733757735746">Toegang via schakelaar (de computer bedienen met slechts één of twee schakelaars)</translation>
 <translation id="3819800052061700452">&amp;Volledig scherm</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Opgeslagen vingerafdrukken</translation>
 <translation id="407173827865827707">Bij klik</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: inlogfout</translation>
-<translation id="4071828814509176232">Oké Google</translation>
 <translation id="4074900173531346617">Certificaat van ondertekenaar van e-mail</translation>
 <translation id="407520071244661467">Schaal</translation>
 <translation id="4075639477629295004">Kan <ph name="FILE_NAME" /> niet casten.</translation>
diff --git a/chrome/app/resources/generated_resources_no.xtb b/chrome/app/resources/generated_resources_no.xtb
index 18dccfb..5197e23 100644
--- a/chrome/app/resources/generated_resources_no.xtb
+++ b/chrome/app/resources/generated_resources_no.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> på <ph name="PEPPER_PLUGIN_DOMAIN" /> ber om tilgang til datamaskinen din</translation>
 <translation id="2178614541317717477">Sertifiseringsinstans-kompromiss</translation>
 <translation id="218070003709087997">Bruk et tall for å angi hvor mange eksemplarer som skal skrives ut (1–999).</translation>
-<translation id="2183558561014688873">Få tilgang til assistenten din når som helst ved å si "Ok Google" når enheten er på og ulåst.</translation>
 <translation id="2187895286714876935">Feil ved import av tjenersertifikat</translation>
 <translation id="2187906491731510095">Utvidelser er oppdatert</translation>
 <translation id="2188881192257509750">Åpne <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">Alle data som lagres av <ph name="SITE" />, blir slettet, med unntak av informasjonskapsler.</translation>
 <translation id="237058345584060620">Koble nøkkelen din til denne enheten, slik at du kan bruke den til å logge på kontoen din</translation>
 <translation id="2371076942591664043">Åpne når ne&amp;dlastingen er ferdig</translation>
-<translation id="2376559921867170420">Når Chromebooken er konfigurert, trykker du på Assistent-knappen eller sier «Ok Google» for å snakke med assistenten når som helst.</translation>
 <translation id="2377319039870049694">Bytt til listevisning</translation>
 <translation id="2377667304966270281">Harde feil</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> filer valgt</translation>
@@ -1874,6 +1872,7 @@
 <translation id="381202950560906753">Legg til ett til</translation>
 <translation id="3812525830114410218">Ugyldig sertifikat</translation>
 <translation id="3813296892522778813">Gå til <ph name="BEGIN_LINK_CHROMIUM" />brukerstøtten for Google Chrome<ph name="END_LINK_CHROMIUM" /> hvis du ikke finner det du ser etter</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Ikke angitt</translation>
 <translation id="3819752733757735746">Brytertilgang (kontrollér datamaskinen med bare én eller to brytere)</translation>
 <translation id="3819800052061700452">&amp;Full skjerm</translation>
@@ -2042,7 +2041,6 @@
 <translation id="4068776064906523561">Lagrede fingeravtrykk</translation>
 <translation id="407173827865827707">Ved klikk</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: påloggingsfeil</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Sertifikat for signering av e-poster</translation>
 <translation id="407520071244661467">Skalér</translation>
 <translation id="4075639477629295004">Kunne ikke caste <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb
index 23ded9f..8a94eaca 100644
--- a/chrome/app/resources/generated_resources_pl.xtb
+++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Wtyczka <ph name="PEPPER_PLUGIN_NAME" /> na <ph name="PEPPER_PLUGIN_DOMAIN" /> chce mieć dostęp do Twojego komputera</translation>
 <translation id="2178614541317717477">Naruszenie bezpieczeństwa urzędu certyfikacji</translation>
 <translation id="218070003709087997">Wpisz wartość numeryczną, by określić liczbę kopii do wydrukowania (od 1 do 999).</translation>
-<translation id="2183558561014688873">Uruchamiaj Asystenta, mówiąc „OK Google”, gdy urządzenie jest odblokowane i nieuśpione.</translation>
 <translation id="2187895286714876935">Błąd importowania certyfikatu serwera</translation>
 <translation id="2187906491731510095">Rozszerzenia zaktualizowane</translation>
 <translation id="2188881192257509750">Otwórz <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Zostaną usunięte wszystkie dane zapisane przez witrynę <ph name="SITE" /> (oprócz plików cookie).</translation>
 <translation id="237058345584060620">Sparuj klucz z tym urządzeniem, by używać go do logowania się na konto</translation>
 <translation id="2371076942591664043">Otwórz po &amp;zakończeniu</translation>
-<translation id="2376559921867170420">Gdy skonfigurujesz Chromebooka, powiedz „OK Google” lub naciśnij przycisk Asystenta, by z niego korzystać.</translation>
 <translation id="2377319039870049694">Przełącz na widok listy</translation>
 <translation id="2377667304966270281">Poważne błędy</translation>
 <translation id="2378075407703503998">Wybrano <ph name="SELCTED_FILE_COUNT" /> pliki(ów)</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Dodaj kolejny</translation>
 <translation id="3812525830114410218">Zły certyfikat</translation>
 <translation id="3813296892522778813">Jeśli nie możesz znaleźć potrzebnych informacji, otwórz <ph name="BEGIN_LINK_CHROMIUM" />pomoc dotyczącą Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">OK Google</translation>
 <translation id="3817579325494460411">Brak danych</translation>
 <translation id="3819752733757735746">Switch Access (sterowanie komputerem za pomocą jednego lub dwóch przełączników).</translation>
 <translation id="3819800052061700452">&amp;Pełny ekran</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Zapisane odciski palców</translation>
 <translation id="407173827865827707">Po kliknięciu</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: błąd logowania</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">Certyfikat podmiotu podpisującego pocztę e-mail</translation>
 <translation id="407520071244661467">Skala</translation>
 <translation id="4075639477629295004">Nie udało się przesłać pliku <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index 9e4660da..0ce80cc 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">O plug-in <ph name="PEPPER_PLUGIN_NAME" /> do domínio <ph name="PEPPER_PLUGIN_DOMAIN" /> quer acessar seu computador</translation>
 <translation id="2178614541317717477">Compromisso da autoridade de certificação</translation>
 <translation id="218070003709087997">Use um número para indicar o número de cópias a serem impressas (1 a 999).</translation>
-<translation id="2183558561014688873">Acesse seu Assistente sempre que disser "Ok Google" quando seu dispositivo estiver ativado e desbloqueado.</translation>
 <translation id="2187895286714876935">Erro de importação do certificado de servidor</translation>
 <translation id="2187906491731510095">Extensões atualizadas</translation>
 <translation id="2188881192257509750">Abrir <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Os dados armazenados pelo <ph name="SITE" /> serão excluídos, exceto os cookies.</translation>
 <translation id="237058345584060620">Pareie sua chave com este dispositivo para fazer login na sua conta</translation>
 <translation id="2371076942591664043">Abrir quando estiver &amp;concluído</translation>
-<translation id="2376559921867170420">Quando o Chromebook estiver configurado, pressione o botão do Assistente ou diga "Ok Google" para receber ajuda do Assistente a qualquer momento.</translation>
 <translation id="2377319039870049694">Alternar para a visualização de lista</translation>
 <translation id="2377667304966270281">Falhas graves</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> arquivos selecionados</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Adicionar outra</translation>
 <translation id="3812525830114410218">Certificado inválido</translation>
 <translation id="3813296892522778813">Se você não encontrar o que está procurando, acesse a <ph name="BEGIN_LINK_CHROMIUM" />Ajuda do Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Não fornecido</translation>
 <translation id="3819752733757735746">Acesso com interruptor (controlar o computador com apenas um ou dois interruptores)</translation>
 <translation id="3819800052061700452">&amp;Tela cheia</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Impressões digitais salvas</translation>
 <translation id="407173827865827707">Ao clicar</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: erro de login</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certificado do signatário do e-mail</translation>
 <translation id="407520071244661467">Escala</translation>
 <translation id="4075639477629295004">Não foi possível transmitir o arquivo <ph name="FILE_NAME" /></translation>
diff --git a/chrome/app/resources/generated_resources_pt-PT.xtb b/chrome/app/resources/generated_resources_pt-PT.xtb
index c8c9403..b3b9f7aa 100644
--- a/chrome/app/resources/generated_resources_pt-PT.xtb
+++ b/chrome/app/resources/generated_resources_pt-PT.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">O <ph name="PEPPER_PLUGIN_NAME" /> em <ph name="PEPPER_PLUGIN_DOMAIN" /> pretende aceder ao seu computador.</translation>
 <translation id="2178614541317717477">AC comprometida</translation>
 <translation id="218070003709087997">Utilize um número para indicar as cópias a imprimir (1 a 999).</translation>
-<translation id="2183558561014688873">Aceda ao Assistente sempre que disser "Ok Google" quando o dispositivo estiver ativado e desbloqueado.</translation>
 <translation id="2187895286714876935">Erro na importação do certificado do servidor</translation>
 <translation id="2187906491731510095">Extensões atualizadas.</translation>
 <translation id="2188881192257509750">Abrir <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Todos os dados armazenados pelo site <ph name="SITE" /> serão eliminados, exceto os cookies.</translation>
 <translation id="237058345584060620">Sincronize a sua chave com este dispositivo para a poder utilizar ao iniciar sessão na sua conta.</translation>
 <translation id="2371076942591664043">Abrir quando estiver concluí&amp;do</translation>
-<translation id="2376559921867170420">Quando o Chromebook estiver configurado, prima o botão do Assistente ou diga "Ok Google" para obter ajuda do Assistente a qualquer momento.</translation>
 <translation id="2377319039870049694">Mudar para a vista de lista</translation>
 <translation id="2377667304966270281">Falhas de hardware</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> ficheiros selecionados</translation>
@@ -1880,6 +1878,7 @@
 <translation id="381202950560906753">Adicionar outra</translation>
 <translation id="3812525830114410218">Certificado incorreto</translation>
 <translation id="3813296892522778813">Aceda à <ph name="BEGIN_LINK_CHROMIUM" />ajuda do Google Chrome<ph name="END_LINK_CHROMIUM" /> se não conseguir encontrar aquilo que procura.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Não fornecido</translation>
 <translation id="3819752733757735746">Acesso por comutador (controlar o computador com apenas um ou dois comutadores)</translation>
 <translation id="3819800052061700452">&amp;Ecrã inteiro</translation>
@@ -2050,7 +2049,6 @@
 <translation id="4068776064906523561">Impressões digitais guardadas</translation>
 <translation id="407173827865827707">Ao clicar</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: erro de início de sessão</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certificado do signatário do email</translation>
 <translation id="407520071244661467">Escala</translation>
 <translation id="4075639477629295004">Não é possível transmitir <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index 71e9731..4ab6c0e 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Pluginul <ph name="PEPPER_PLUGIN_NAME" /> de pe <ph name="PEPPER_PLUGIN_DOMAIN" /> dorește să acceseze computerul</translation>
 <translation id="2178614541317717477">Compromitere CA</translation>
 <translation id="218070003709087997">Precizează un număr de exemplare pentru printare (de la 1 la 999).</translation>
-<translation id="2183558561014688873">Accesează Asistentul ori de câte ori rostești „Ok Google” când dispozitivul este activ și deblocat.</translation>
 <translation id="2187895286714876935">Eroare de import a certificatului serverului</translation>
 <translation id="2187906491731510095">Extensiile au fost actualizate</translation>
 <translation id="2188881192257509750">Deschide <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Toate datele stocate de <ph name="SITE" /> vor fi șterse, cu excepția cookie-urilor.</translation>
 <translation id="237058345584060620">Asociază-ți cheia la acest dispozitiv, astfel încât să o poți folosi pentru a te conecta la cont.</translation>
 <translation id="2371076942591664043">Deschide când s-a &amp;descărcat</translation>
-<translation id="2376559921867170420">După configurarea Chromebookului, apasă butonul Asistentului sau rostește „Ok Google” pentru a obține oricând ajutor de la Asistent.</translation>
 <translation id="2377319039870049694">Comută la afișarea listă</translation>
 <translation id="2377667304966270281">Erori de hardware</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> fișiere selectate</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Adaugă alta</translation>
 <translation id="3812525830114410218">Certificat nevalid</translation>
 <translation id="3813296892522778813">Accesează <ph name="BEGIN_LINK_CHROMIUM" />Ajutor Google Chrome<ph name="END_LINK_CHROMIUM" /> dacă nu găsești ceea ce cauți</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Nu s-a specificat</translation>
 <translation id="3819752733757735746">Accesul prin comutare (controlează computerul cu numai un comutator sau două)</translation>
 <translation id="3819800052061700452">&amp;Ecran complet</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Amprentele salvate</translation>
 <translation id="407173827865827707">Când se dă clic</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: eroare la conectare</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certificat semnatar pentru e-mail</translation>
 <translation id="407520071244661467">Redimensionează</translation>
 <translation id="4075639477629295004">Nu se poate proiecta <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb
index 198fc07..56d8036 100644
--- a/chrome/app/resources/generated_resources_ru.xtb
+++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -794,7 +794,6 @@
 <translation id="2178098616815594724">Плагин <ph name="PEPPER_PLUGIN_NAME" /> в домене <ph name="PEPPER_PLUGIN_DOMAIN" /> пытается получить доступ к вашему компьютеру.</translation>
 <translation id="2178614541317717477">Скомпрометированный ЦС</translation>
 <translation id="218070003709087997">Укажите цифрами число копий для печати (от 1 до 999).</translation>
-<translation id="2183558561014688873">Чтобы обратиться к Ассистенту, включите и разблокируйте устройство, а затем скажите "Окей, Google".</translation>
 <translation id="2187895286714876935">Ошибка при импорте сертификата сервера</translation>
 <translation id="2187906491731510095">Расширения обновлены</translation>
 <translation id="2188881192257509750">Открыть приложение "<ph name="APPLICATION" />"</translation>
@@ -923,7 +922,6 @@
 <translation id="2369536625682139252">Все данные, сохраненные сайтом <ph name="SITE" />, будут удалены (за исключением файлов cookie).</translation>
 <translation id="237058345584060620">Свяжите ключ с устройством, чтобы использовать его для входа в аккаунт.</translation>
 <translation id="2371076942591664043">Открыть по &amp;завершении</translation>
-<translation id="2376559921867170420">Завершив настройку Chromebook, вы сможете обращаться к Ассистенту в любое время. Для этого нажмите кнопку Ассистента или скажите "Окей, Google".</translation>
 <translation id="2377319039870049694">Показать в виде списка</translation>
 <translation id="2377667304966270281">Ошибки отсутствия страницы в памяти</translation>
 <translation id="2378075407703503998">Выбрано файлов: <ph name="SELCTED_FILE_COUNT" />.</translation>
@@ -1880,6 +1878,7 @@
 <translation id="381202950560906753">Добавить ещё</translation>
 <translation id="3812525830114410218">Недопустимый сертификат</translation>
 <translation id="3813296892522778813">Поиск не дал результатов? Перейдите в <ph name="BEGIN_LINK_CHROMIUM" />Справочный центр Google Chrome<ph name="END_LINK_CHROMIUM" />.</translation>
+<translation id="3813984289128269159">Поиск по команде "Окей, Google"</translation>
 <translation id="3817579325494460411">Не указано</translation>
 <translation id="3819752733757735746">Включить Switch Access (позволяет управлять компьютером с помощью переключателей)</translation>
 <translation id="3819800052061700452">Полно&amp;экранный режим</translation>
@@ -2050,7 +2049,6 @@
 <translation id="4068776064906523561">Сохраненные отпечатки пальцев</translation>
 <translation id="407173827865827707">При нажатии</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: ошибка входа</translation>
-<translation id="4071828814509176232">Окей, Google</translation>
 <translation id="4074900173531346617">Сертификат для подписи электронной почты</translation>
 <translation id="407520071244661467">Масштаб</translation>
 <translation id="4075639477629295004">Невозможно транслировать файл "<ph name="FILE_NAME" />"</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb
index fc0b675f..b2879d7 100644
--- a/chrome/app/resources/generated_resources_sk.xtb
+++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -796,7 +796,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> na webe <ph name="PEPPER_PLUGIN_DOMAIN" /> chce získať prístup k vášmu počítaču</translation>
 <translation id="2178614541317717477">Ohrozenie zabezpečenia CA</translation>
 <translation id="218070003709087997">Zadanie počtu kópií, ktoré chcete vytlačiť, treba zadať číslovkou (1 až 999).</translation>
-<translation id="2183558561014688873">Keď je zariadenie aktívne a odomknuté, Asistenta môžete kedykoľvek aktivovať vyslovením výrazu „Ok Google“.</translation>
 <translation id="2187895286714876935">Chyba importovania certifikátu servera</translation>
 <translation id="2187906491731510095">Rozšírenia boli aktualizované</translation>
 <translation id="2188881192257509750">Otvoriť <ph name="APPLICATION" /></translation>
@@ -925,7 +924,6 @@
 <translation id="2369536625682139252">Všetky dáta uložené webom <ph name="SITE" /> budú s výnimkou súborov cookie odstránené.</translation>
 <translation id="237058345584060620">Spárujte kľúč s týmto zariadením, aby ste sa mohli pomocou neho prihlasovať do účtu</translation>
 <translation id="2371076942591664043">Po stiahnutí otvoriť</translation>
-<translation id="2376559921867170420">Po nastavení Chromebooku môžete kedykoľvek získať pomoc od Asistenta tak, že stlačíte tlačidlo Asistent a poviete „OK Google“.</translation>
 <translation id="2377319039870049694">Prepnúť na zobrazenie zoznamu</translation>
 <translation id="2377667304966270281">Závažné chyby</translation>
 <translation id="2378075407703503998">Počet vybratých súborov: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Pridať ďalší</translation>
 <translation id="3812525830114410218">Nesprávny certifikát</translation>
 <translation id="3813296892522778813">Ak neviete nájsť požadovaný obsah, prejdite do <ph name="BEGIN_LINK_CHROMIUM" />pomocníka Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Neznáma</translation>
 <translation id="3819752733757735746">Prístup s prepínačmi (ovládajte počítač len jedným či dvoma prepínačmi)</translation>
 <translation id="3819800052061700452">&amp;Celá obrazovka</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Uložené odtlačky prstov</translation>
 <translation id="407173827865827707">Po kliknutí</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: chyba prihlásenia</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certifikát podpisovateľa e-mailu</translation>
 <translation id="407520071244661467">Prispôsobiť veľkosť</translation>
 <translation id="4075639477629295004">Nie je možné prenášať súbor <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb
index afeba84b..24b5ccb 100644
--- a/chrome/app/resources/generated_resources_sl.xtb
+++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Vtičnik <ph name="PEPPER_PLUGIN_NAME" /> v domeni <ph name="PEPPER_PLUGIN_DOMAIN" /> želi dostopati do vašega računalnika</translation>
 <translation id="2178614541317717477">Overitelj potrdil ni več varen</translation>
 <translation id="218070003709087997">Vnesite število izvodov, ki jih želite natisniti (od 1 do 999).</translation>
-<translation id="2183558561014688873">Do Pomočnika lahko dostopate, kadar koli izgovorite »OK Google«, ko je zaslon vklopljen in odklenjen.</translation>
 <translation id="2187895286714876935">Napaka pri uvozu strežniškega potrdila</translation>
 <translation id="2187906491731510095">Razširitve posodobljene</translation>
 <translation id="2188881192257509750">Odpri aplikacijo <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Izbrisani bodo vsi podatki, ki jih je shranilo spletno mesto <ph name="SITE" />, razen piškotkov.</translation>
 <translation id="237058345584060620">Ključ seznanite s to napravo, če ga želite uporabiti za prijavo v račun</translation>
 <translation id="2371076942591664043">Odpri, ko je &amp;dokončano</translation>
-<translation id="2376559921867170420">Ko je Chromebook nastavljen, pritisnite gumb za Pomočnika ali izgovorite »Ok Google«, če želite, da vam Pomočnik kadar koli pomaga.</translation>
 <translation id="2377319039870049694">Preklop na pogled seznama</translation>
 <translation id="2377667304966270281">Težke napake</translation>
 <translation id="2378075407703503998">Št. izbranih datotek: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Dodaj še enega</translation>
 <translation id="3812525830114410218">Poškodovano potrdilo</translation>
 <translation id="3813296892522778813">Odprite <ph name="BEGIN_LINK_CHROMIUM" />pomoč za Google Chrome<ph name="END_LINK_CHROMIUM" />, če ne najdete tega, kar iščete</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Ni navedeno</translation>
 <translation id="3819752733757735746">Preklop dostopa (upravljanje računalnika z enim ali dvema stikaloma)</translation>
 <translation id="3819800052061700452">&amp;Celozaslonsko</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Shranjeni prstni odtisi</translation>
 <translation id="407173827865827707">Ob kliku</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: napaka pri prijavi</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Potrdilo podpisnika e-pošte</translation>
 <translation id="407520071244661467">Prilagajanje velikosti</translation>
 <translation id="4075639477629295004">Ni mogoče predvajati <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sr.xtb b/chrome/app/resources/generated_resources_sr.xtb
index 7a3942c..3b11730 100644
--- a/chrome/app/resources/generated_resources_sr.xtb
+++ b/chrome/app/resources/generated_resources_sr.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724">Додатна компонента <ph name="PEPPER_PLUGIN_NAME" /> на домену <ph name="PEPPER_PLUGIN_DOMAIN" /> жели да приступи рачунару</translation>
 <translation id="2178614541317717477">CA је компромитован</translation>
 <translation id="218070003709087997">Наведите број примерака за штампање (1 до 999).</translation>
-<translation id="2183558561014688873">Приступајте Помоћнику сваки пут када изговорите „Ок Google“ док је уређај ван стања спавања и откључан.</translation>
 <translation id="2187895286714876935">Грешка при увозу серверског сертификата</translation>
 <translation id="2187906491731510095">Додаци су ажурирани</translation>
 <translation id="2188881192257509750">Отвори <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">Сви подаци које <ph name="SITE" /> сачува биће избрисани осим колачића.</translation>
 <translation id="237058345584060620">Упарите кључ са овим уређајем да бисте га користили за пријављивање на налог</translation>
 <translation id="2371076942591664043">Отвори кад буде &amp;довршено</translation>
-<translation id="2376559921867170420">Када подесите Chromebook, притисните дугме Помоћник или реците „Ок Google“ да бисте затражили помоћ од Помоћника у било ком тренутку.</translation>
 <translation id="2377319039870049694">Пређи на приказ листе</translation>
 <translation id="2377667304966270281">Грешке у вези са хард-диском</translation>
 <translation id="2378075407703503998">Изабраних датотека: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1875,6 +1873,7 @@
 <translation id="381202950560906753">Додај други</translation>
 <translation id="3812525830114410218">Неисправан сертификат</translation>
 <translation id="3813296892522778813">Идите на <ph name="BEGIN_LINK_CHROMIUM" />страницу помоћи за Google Chrome<ph name="END_LINK_CHROMIUM" /> ако не можете да пронађете оно што тражите</translation>
+<translation id="3813984289128269159">Ок Google</translation>
 <translation id="3817579325494460411">Није наведено</translation>
 <translation id="3819752733757735746">Приступ помоћу прекидача (контролишите рачунар помоћу само једног или два прекидача)</translation>
 <translation id="3819800052061700452">&amp;Пун екран</translation>
@@ -2045,7 +2044,6 @@
 <translation id="4068776064906523561">Сачувани отисци прстију</translation>
 <translation id="407173827865827707">При клику</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: грешка при пријављивању</translation>
-<translation id="4071828814509176232">Ок Google</translation>
 <translation id="4074900173531346617">Сертификат потписника е-поште</translation>
 <translation id="407520071244661467">Размера</translation>
 <translation id="4075639477629295004">Није успело пребацивање за <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index 8a7b4ca..a501c1d3 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -794,7 +794,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> på <ph name="PEPPER_PLUGIN_DOMAIN" /> vill ha åtkomst till datorn</translation>
 <translation id="2178614541317717477">CA-kompromiss</translation>
 <translation id="218070003709087997">Använd ett nummer som anger hur många kopior som ska skrivas ut (1 till 999).</translation>
-<translation id="2183558561014688873">Få tillgång till assistenten när du säger ”Ok Google” och enheten är aktiv och olåst.</translation>
 <translation id="2187895286714876935">Fel vid import av servercertifikat</translation>
 <translation id="2187906491731510095">Tillägg har uppdaterats</translation>
 <translation id="2188881192257509750">Öppna <ph name="APPLICATION" /></translation>
@@ -923,7 +922,6 @@
 <translation id="2369536625682139252">All data som sparats av <ph name="SITE" /> tas bort utom cookies.</translation>
 <translation id="237058345584060620">Parkoppla nyckeln till den här enheten så att du kan logga in på ditt konto med den</translation>
 <translation id="2371076942591664043">Öppna när nedladdning är &amp;klar</translation>
-<translation id="2376559921867170420">När konfigureringen av Chromebook är klar kan du trycka på assistentknappen eller säga ”Ok Google” när som helst när du vill få hjälp av assistenten.</translation>
 <translation id="2377319039870049694">Byt till listvy</translation>
 <translation id="2377667304966270281">Sidfel</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> filer har valts</translation>
@@ -1878,6 +1876,7 @@
 <translation id="381202950560906753">Lägg till ett till</translation>
 <translation id="3812525830114410218">Dåligt certifikat</translation>
 <translation id="3813296892522778813">Öppna <ph name="BEGIN_LINK_CHROMIUM" />Hjälp för Google Chrome<ph name="END_LINK_CHROMIUM" /> om du inte hittar vad du letar efter.</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Inte angivet</translation>
 <translation id="3819752733757735746">Brytarstyrning (styr datorn med bara en eller två knappar)</translation>
 <translation id="3819800052061700452">&amp;Helskärm</translation>
@@ -2048,7 +2047,6 @@
 <translation id="4068776064906523561">Sparade fingeravtryck</translation>
 <translation id="407173827865827707">Vid klick</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: inloggningsfel</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Certifikat för e-postsignering</translation>
 <translation id="407520071244661467">Skaländra</translation>
 <translation id="4075639477629295004">Det gick inte att casta <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index fe878b9..6fdee5a9 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -792,7 +792,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> iliyo kwenye <ph name="PEPPER_PLUGIN_DOMAIN" /> inataka kufikia kompyuta yako</translation>
 <translation id="2178614541317717477">Kuvurugwa kwa Mamlaka ya Cheti</translation>
 <translation id="218070003709087997">Tumia nambari kuonyesha idadi ya nakala za kuchapa (1 hadi 999).</translation>
-<translation id="2183558561014688873">Fikia programu yako ya Mratibu wakati wowote unaposema "OK Google" ikiwa kifaa chako kimewashwa na hakijafungwa.</translation>
 <translation id="2187895286714876935">Hitilafu ya Kuleta Cheti cha Seva</translation>
 <translation id="2187906491731510095">Imesasisha viendelezi</translation>
 <translation id="2188881192257509750">Fungua <ph name="APPLICATION" /></translation>
@@ -921,7 +920,6 @@
 <translation id="2369536625682139252">Data yote iliyohifadhiwa na <ph name="SITE" /> itafutwa, isipokuwa vidakuzi.</translation>
 <translation id="237058345584060620">Oanisha ufunguo wako na kifaa hiki ili uweze kuutumia kuingia katika akaunti yako</translation>
 <translation id="2371076942591664043">Fungua baada ya &amp;kumaliza</translation>
-<translation id="2376559921867170420">Wakati umeweka mipangilio ya Chromebook, bonyeza kitufe cha programu ya Mratibu au useme "OK Google" ili upate usaidizi kutoka kwa programu ya Mratibu wakati wowote.</translation>
 <translation id="2377319039870049694">Tumia mwonekano wa orodha</translation>
 <translation id="2377667304966270281">Mabadilko ya Hifadhi</translation>
 <translation id="2378075407703503998">Faili <ph name="SELCTED_FILE_COUNT" /> zimezochaguliwa</translation>
@@ -1872,6 +1870,7 @@
 <translation id="381202950560906753">Ongeza kingine</translation>
 <translation id="3812525830114410218">Cheti kina tatizo</translation>
 <translation id="3813296892522778813">Nenda kwenye <ph name="BEGIN_LINK_CHROMIUM" />Usaidizi wa Google Chrome<ph name="END_LINK_CHROMIUM" /> ikiwa hupati unachotafuta</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Haijatolewa</translation>
 <translation id="3819752733757735746">Fikia kupitia swichi (dhibiti kompyuta kwa kutumia swichi moja au mbili pekee)</translation>
 <translation id="3819800052061700452">&amp;Skrini kamili</translation>
@@ -2042,7 +2041,6 @@
 <translation id="4068776064906523561">Alama za vidole zilizohifadhiwa</translation>
 <translation id="407173827865827707">Unapobofya</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: hitilafu ya kuingia katika akaunti</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Cheti cha Anayetia Vyeti Sahihi</translation>
 <translation id="407520071244661467">Kipimo</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> haijatumwa.</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb
index 03034db..4855c51 100644
--- a/chrome/app/resources/generated_resources_ta.xtb
+++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> இல் உள்ள <ph name="PEPPER_PLUGIN_NAME" /> உங்கள் கணினியை அணுக விரும்புகிறது</translation>
 <translation id="2178614541317717477">CA இணக்கம்</translation>
 <translation id="218070003709087997">எத்தனை நகல்கள் அச்சிடப்பட வேண்டும் என்பதைக் குறிக்க, எண்ணைப் (1 - 999) பயன்படுத்தவும்.</translation>
-<translation id="2183558561014688873">சாதனம் பூட்டப்படாமல் இயங்கிக் கொண்டிருக்கும்போது, "OK Google" என்று சொல்லி எந்த நேரத்திலும் அசிஸ்டண்ட்டை அணுகலாம்.</translation>
 <translation id="2187895286714876935">சேவையக சான்றிதழ் இறக்குமதி பிழை</translation>
 <translation id="2187906491731510095">நீட்டிப்புகள் புதுப்பிக்கப்பட்டன</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" />ஐத் திற</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">குக்கீகள் தவிர, <ph name="SITE" /> சேமித்த எல்லாத் தரவும் நீக்கப்படும்.</translation>
 <translation id="237058345584060620">இந்தச் சாதனத்துடன் விசையை இணைப்பதன் மூலம், உங்கள் கணக்கில் உள்நுழைய அதைப் பயன்படுத்தலாம்</translation>
 <translation id="2371076942591664043">&amp;முடிந்ததும் திற</translation>
-<translation id="2376559921867170420">Chromebook அமைக்கப்படும்போது, அசிஸ்டண்ட்டிடமிருந்து எந்த நேரத்திலும் உதவி பெற, அசிஸ்டண்ட் பட்டனை அழுத்தவும் அல்லது "OK Google" என்று சொல்லவும்.</translation>
 <translation id="2377319039870049694">பட்டியல் காட்சிக்கு மாறு</translation>
 <translation id="2377667304966270281">ஹார்டு ஃபால்ட்கள்</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> கோப்புகள் தேர்ந்தெடுக்கப்பட்டன</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">மற்றொன்றைச் சேர்</translation>
 <translation id="3812525830114410218">தவறான சான்றிதழ்</translation>
 <translation id="3813296892522778813">தேடுவது கிடைக்கவில்லை எனில், <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome உதவி<ph name="END_LINK_CHROMIUM" /> எனும் இணைப்பிற்குச் செல்லவும்</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">வழங்கப்படவில்லை</translation>
 <translation id="3819752733757735746">சுவிட்ச் அணுகல் (ஒன்று அல்லது இரண்டு சுவிட்ச்கள் மூலம் கணினியைக் கட்டுப்படுத்துதல்)</translation>
 <translation id="3819800052061700452">&amp;முழுத்திரை</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">சேமித்த கைரேகைகள்</translation>
 <translation id="407173827865827707">கிளிக் செய்யும் போது</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: உள்நுழைவு பிழை</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">மின்னஞ்சல் கையொப்பமிடுநர் சான்றிதழ்</translation>
 <translation id="407520071244661467">அளவு</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" />ஐ அனுப்ப முடியவில்லை.</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index 067158d..933df79 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -401,6 +401,7 @@
 <translation id="1589055389569595240">అక్షరక్రమం మరియు వ్యాకరణం చూపించు</translation>
 <translation id="1593594475886691512">ఆకృతీకరిస్తోంది...</translation>
 <translation id="159359590073980872">చిత్రం క్యాష్</translation>
+<translation id="1593926297800505364">చెల్లింపు పద్దతిని సేవ్ చేయండి</translation>
 <translation id="1598233202702788831">నవీకరణలను మీ నిర్వాహకులు నిలిపివేసారు.</translation>
 <translation id="1600857548979126453">పేజీ డీబగ్గర్ బ్యాకెండ్‌ను ప్రాప్యత చేయండి</translation>
 <translation id="1601560923496285236">వర్తించు</translation>
@@ -419,7 +420,7 @@
 <translation id="1618268899808219593">స&amp;హాయ కేంద్రం</translation>
 <translation id="162035744160882748">సమకాలీకరణ, వ్యక్తిగతీకరణ మరియు ఇతర Google సేవలను ఆన్ చేయండి</translation>
 <translation id="1620510694547887537">కెమెరా</translation>
-<translation id="1623132449929929218">చిత్రాలు ప్రస్తుతం అందుబాటులో లేవు. వాల్‌పేపప్ సేకరణలను చూడటానికి, దయచేసి ఇంటర్నెట్‌కు మళ్లీ కనెక్ట్ చేయండి.</translation>
+<translation id="1623132449929929218">చిత్రాలు ప్రస్తుతం అందుబాటులో లేవు. వాల్‌పేపర్ సేకరణలను చూడటానికి, దయచేసి ఇంటర్నెట్‌కు మళ్లీ కనెక్ట్ చేయండి.</translation>
 <translation id="1624026626836496796">ఇది ఒకసారి మాత్రమే జరుగుతుంది మరియు మీ ఆధారాలు నిల్వ చేయబడవు.</translation>
 <translation id="1627276047960621195">ఫైల్ వివరణలు</translation>
 <translation id="1627408615528139100">ఇప్పటికే డౌన్‌లోడ్ చేయబడింది</translation>
@@ -466,7 +467,7 @@
 <translation id="1673137583248014546"><ph name="URL" /> మీ భద్రతా కీ యొక్క తయారీదారు బ్రాండ్ పేరు మరియు మోడల్‌ని చూడాలనుకుంటోంది</translation>
 <translation id="167832068858235403">వాల్యూ. తగ్గించు</translation>
 <translation id="1679068421605151609">డెవలపర్ సాధనాలు</translation>
-<translation id="1680849702532889074">మీ Linux అప్లికేషన్ ఇన్‌స్టాలేషన్ సమయంలో ఎర్రర్ సంభవించింది.</translation>
+<translation id="1680849702532889074">మీ Linux అప్లికేషన్ ఇన్‌స్టాలేషన్ సమయంలో ఎర్రర్ ఏర్పడింది.</translation>
 <translation id="16815041330799488">క్లిప్‌బోర్డ్‌కు కాపీ చేసిన వచనం మరియు చిత్రాలను చూడటానికి సైట్‌లను అనుమతించవద్దు</translation>
 <translation id="1682548588986054654">క్రొత్త అజ్ఞాత విండో</translation>
 <translation id="168715261339224929">మీ బుక్‌మార్క్‌లను మీ అన్ని పరికరాలలోనూ పొందాలంటే, సమకాలీకరణను ఆన్ చేయండి.</translation>
@@ -511,6 +512,7 @@
 <translation id="1744060673522309905">పరికరాన్ని డొమైన్‌కు చేర్చడం సాధ్యపడలేదు. మీరు జోడించగల పరికరాల గరిష్ట సంఖ్యను మించిపోలేదని నిర్ధారించుకోండి.</translation>
 <translation id="1744108098763830590">నేపథ్య పేజీ</translation>
 <translation id="1745520510852184940">ఎల్లప్పుడూ దీన్ని చేయి</translation>
+<translation id="1746417874336251387">Chromebookకు మీ ఫోన్ కనెక్షన్‌ను ఉపయోగించే కొత్త ఫీచర్‌లను అందించండి</translation>
 <translation id="174937106936716857">మొత్తం ఫైల్‌ల సంఖ్య</translation>
 <translation id="175196451752279553">మూసిన టాబ్ ని మళ్ళి&amp;తెరువు</translation>
 <translation id="1753905327828125965">అధికంగా సందర్శించేది</translation>
@@ -641,8 +643,10 @@
 <translation id="1932098463447129402">ముందు కాదు</translation>
 <translation id="1933809209549026293">దయచేసి మౌస్ లేదా కీబోర్డ్‌ను కనెక్ట్ చేయండి. మీరు బ్లూటూత్ పరికరాన్ని ఉపయోగిస్తుంటే, అది జత చేయడానికి సిద్ధంగా ఉందని నిర్ధారించుకోండి.</translation>
 <translation id="1936157145127842922">ఫోల్డర్‌లో చూపించు</translation>
+<translation id="1938351510777341717">బాహ్య ఆదేశం</translation>
 <translation id="1940546824932169984">కనెక్ట్ చేయబడిన పరికరాలు</translation>
 <translation id="1942765061641586207">చిత్ర రిజల్యూషన్</translation>
+<translation id="1943097386230153518">కొత్త సేవలను ఇన్‌స్టాల్ చేయి</translation>
 <translation id="1944921356641260203">నవీకరణ కనుగొనబడింది</translation>
 <translation id="1951615167417147110">ఒక పేజీ పైకి స్క్రోల్ చెయ్యండి</translation>
 <translation id="1954813140452229842">షేర్‌ను మౌంట్ చేయడంలో ఎర్రర్ ఏర్పడింది. దయచేసి మీ ఆధారాలను సరిచూసుకుని, మళ్లీ ప్రయత్నించండి.</translation>
@@ -791,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" />లోని <ph name="PEPPER_PLUGIN_NAME" /> మీ కంప్యూటర్‌ని యాక్సెస్ చేయాలనుకుంటోంది</translation>
 <translation id="2178614541317717477">CA రాజీ</translation>
 <translation id="218070003709087997">ఎన్ని కాపీలను ముద్రించాలో (1 నుండి 999) సంఖ్యతో సూచించండి.</translation>
-<translation id="2183558561014688873">మీ పరికరం యాక్టివ్ అయ్యి, అన్‌లాక్ చేయబడినప్పుడు మీరు ఎప్పుడైనా "OK Google" అని చెప్పి, అసిస్టెంట్‌ను యాక్సెస్ చేయవచ్చు.</translation>
 <translation id="2187895286714876935">సర్వర్  ప్రమాణపత్రం  దిగుమతి లోపం</translation>
 <translation id="2187906491731510095">పొడిగింపులు నవీకరించబడ్డాయి</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" />ని తెరువు</translation>
@@ -918,9 +921,8 @@
 <translation id="2367199180085172140">ఫైల్ షేర్‌ని జోడించండి</translation>
 <translation id="2367972762794486313">అనువర్తనాలను చూపు</translation>
 <translation id="2369536625682139252">కుక్కీలు మినహా <ph name="SITE" /> నిల్వ చేసిన మొత్తం డేటా తొలగించబడుతుంది.</translation>
-<translation id="237058345584060620">మీ కీని ఈ పరికరానికి జత చేస్తే, తద్వారా మీరు మీ ఖాతాకు సైన్ ఇన్ చేయడానికి దాన్ని ఉపయోగించవచ్చు</translation>
+<translation id="237058345584060620">మీ కీని ఈ పరికరానికి జత చేయండి, తద్వారా మీరు మీ ఖాతాకు సైన్ ఇన్ చేయడానికి దాన్ని ఉపయోగించవచ్చు</translation>
 <translation id="2371076942591664043">&amp;పూర్తవగానే తెరువు</translation>
-<translation id="2376559921867170420">మీ Chromebook సెటప్ చేసిన తర్వాత, ఏ సమయంలోనైనా మీ అసిస్టెంట్‌ నుండి సహాయాన్ని పొందడానికి Assistant బటన్‌ను నొక్కండి లేదా "Ok Google" అని చెప్పండి.</translation>
 <translation id="2377319039870049694">జాబితా వీక్షణకు మార్చు</translation>
 <translation id="2377667304966270281">Hard Faultలు</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> ఫైల్‌లు ఎంచుకోబడ్డాయి</translation>
@@ -1015,7 +1017,7 @@
 <translation id="2520644704042891903">అందుబాటులో ఉన్న సాకెట్ కోసం వేచి ఉంది...</translation>
 <translation id="252219247728877310">అంశం నవీకరించబడలేదు</translation>
 <translation id="2522791476825452208">చాలా దగ్గరగా ఉండాలి</translation>
-<translation id="2523184218357549926">మీరు సందర్శించే పేజీల URLను Googleకి పంపుతుంది</translation>
+<translation id="2523184218357549926">మీరు సందర్శించే పేజీల URLలను Googleకి పంపుతుంది</translation>
 <translation id="2525250408503682495">క్రిప్టోనైట్! కియోస్క్ అనువర్తనం కోసం క్రిప్టోహోమ్ మౌంట్ చేయబడలేదు.</translation>
 <translation id="2526277209479171883">ఇన్‌స్టాల్ చేసి, కొనసాగించండి</translation>
 <translation id="2526590354069164005">డెస్క్‌టాప్</translation>
@@ -1108,6 +1110,7 @@
 <translation id="2653659639078652383">సమర్పించు</translation>
 <translation id="265390580714150011">ఫీల్డ్ విలువ</translation>
 <translation id="2654166010170466751">చెల్లింపు హ్యాండ్లర్‌లను ఇన్‌స్టాల్ చేయడానికి సైట్‌లను అనుమతించండి</translation>
+<translation id="2659381484350128933"><ph name="FOOTNOTE_POINTER" />పరికరాన్ని బట్టి ఫీచర్‌లు మారతాయి</translation>
 <translation id="2660779039299703961">ఈవెంట్</translation>
 <translation id="266079277508604648">ప్రింటర్‌కి కనెక్ట్ చేయడం సాధ్యం కాదు. ప్రింటర్‌ని ఆన్ చేసినట్లు, దానిని Wi-Fi లేదా USB ద్వారా మీ Chromebookకి కనెక్ట్ చేసినట్లు నిర్ధారించుకోండి.</translation>
 <translation id="2661146741306740526">16x9</translation>
@@ -1214,6 +1217,7 @@
 <translation id="2803375539583399270">PINను నమోదు చేయండి</translation>
 <translation id="2805646850212350655">Microsoft Encrypting File System</translation>
 <translation id="2805756323405976993">యాప్స్</translation>
+<translation id="2806891468525657116">షార్ట్‌కట్ ఇప్పటికే ఉంది</translation>
 <translation id="2807517655263062534">మీరు డౌన్‌లోడ్ చేసిన ఫైల్‌లు ఇక్కడ కనిపిస్తాయి</translation>
 <translation id="2809586584051668049">ఇంకా మరో <ph name="NUMBER_ADDITIONAL_DISABLED" /></translation>
 <translation id="281133045296806353">ఇప్పటికే ఉన్న బ్రౌజర్ సెషన్లో క్రొత్త విండో సృష్టించబడింది.</translation>
@@ -1600,6 +1604,7 @@
 <translation id="3428419049384081277">మీరు సైన్ ఇన్ చేసారు!</translation>
 <translation id="3429275422858276529">ఈ పేజీని తర్వాత సులభంగా కనుగొనడానికి దీనిని బుక్‌మార్క్ చేయండి</translation>
 <translation id="3429599832623003132">$1 అంశాలు</translation>
+<translation id="3430342160185525240">మీకు నోటిఫికేషన్‌లను చూపించడానికి అసిస్టెంట్‌ను ప్రారంభిస్తుంది.</translation>
 <translation id="3432227430032737297">చూపుతున్నవన్నీ తీసివేయి</translation>
 <translation id="3432757130254800023">స్థానిక నెట్‌వర్క్‌లో డిస్‌ప్లేలకు ఆడియో మరియు వీడియోను పంపడం</translation>
 <translation id="3432762828853624962">షేర్డ్ వర్కర్స్</translation>
@@ -1872,6 +1877,7 @@
 <translation id="381202950560906753">మరొక దాన్ని జోడించు</translation>
 <translation id="3812525830114410218">ప్రమాణపత్రం చెల్లదు</translation>
 <translation id="3813296892522778813">మీరు వెతుకుతున్నది మీకు కనిపించకపోతే <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome సహాయం<ph name="END_LINK_CHROMIUM" />కి వెళ్లండి</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">అందించబడలేదు</translation>
 <translation id="3819752733757735746">స్విచ్ ప్రాప్యత (కేవలం ఒకటి లేదా రెండు స్విచ్‌లతో కంప్యూటర్‌ను నియంత్రించండి)</translation>
 <translation id="3819800052061700452">&amp;పూర్తి స్క్రీన్</translation>
@@ -1964,6 +1970,7 @@
    <ph name="CONTROL_PANEL_APPLET_NAME" />ను ఉపయోగించి అన్‌ఇన్‌స్టాల్ చేయాలి.
 
   మీరు <ph name="CONTROL_PANEL_APPLET_NAME" />ను ప్రారంభించాలనుకుంటున్నారా?</translation>
+<translation id="394183848452296464">షార్ట్‌కట్‌ను సృష్టించడం సాధ్యపడదు</translation>
 <translation id="3943582379552582368">&amp;వెనుకకు</translation>
 <translation id="3943857333388298514">అతికించు</translation>
 <translation id="3948116654032448504">చిత్రం కోసం <ph name="SEARCH_ENGINE" />లో &amp;శోధించండి</translation>
@@ -2041,7 +2048,6 @@
 <translation id="4068776064906523561">సేవ్ చేయబడిన వేలిముద్రలు</translation>
 <translation id="407173827865827707">క్లిక్ చేసినప్పుడు</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: సైన్ ఇన్ లోపం</translation>
-<translation id="4071828814509176232">OK Google</translation>
 <translation id="4074900173531346617">ఇమెయిల్ సైన్ చేసినవారి సర్టిఫికెట్</translation>
 <translation id="407520071244661467">ప్రమాణం</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" />ని ప్రసారం చేయడం సాధ్యపడలేదు.</translation>
@@ -2271,6 +2277,7 @@
 <translation id="4481530544597605423">జతను తీసివేసిన పరికరాలు</translation>
 <translation id="4482194545587547824">శోధన మరియు ఇతర Google సేవలను వ్యక్తిగతీకరించడానికి Google మీ బ్రౌజింగ్ చరిత్రను ఉపయోగించవచ్చు</translation>
 <translation id="4495419450179050807">ఈ పేజీని చూపవద్దు</translation>
+<translation id="4499718683476608392">ఒకే క్లిక్‌తో ఫారమ్‌లను పూరించడానికి క్రెడిట్ కార్డ్ స్వీయ పూరింపును ప్రారంభిస్తుంది</translation>
 <translation id="4500114933761911433"><ph name="PLUGIN_NAME" /> క్రాష్ అయింది</translation>
 <translation id="450099669180426158">ఆశ్చర్యార్థక గుర్తు చిహ్నం</translation>
 <translation id="4501530680793980440">తీసివేతను నిర్ధారించండి</translation>
@@ -2794,7 +2801,7 @@
 <translation id="5288678174502918605">మూసిన టాబ్‌ను మళ్ళీ &amp;తెరువు</translation>
 <translation id="52912272896845572">వ్యక్తిగతమైన కీ ఫైల్ చెల్లదు.</translation>
 <translation id="529175790091471945">ఈ పరికరాన్ని ఫార్మాట్ చేయి</translation>
-<translation id="5292195676005197571">ఎక్కువ కీలను ఉపయోగించడానికి, బటన్‌ని నొక్కండి</translation>
+<translation id="5292195676005197571">దాదాపు అన్ని కీల వినియోగానికి, ఆ బటన్‌ని నొక్కండి చాలు</translation>
 <translation id="5293170712604732402">సెట్టింగ్‌లను వాటి అసలు డిఫాల్ట్ విలువలకు పునరుద్ధరించండి</translation>
 <translation id="5297082477358294722">పాస్‌వర్డ్ సేవ్ చేయబడింది. మీ <ph name="SAVED_PASSWORDS_STORE" />లో సేవ్ చేసిన పాస్‌వర్డ్‌లను చూడండి మరియు నిర్వహించండి.</translation>
 <translation id="5298219193514155779">థీమ్ వీరిచే సృష్టించబడింది</translation>
@@ -3114,6 +3121,7 @@
 <translation id="5752453871435543420">Chrome OS Cloud బ్యాకప్</translation>
 <translation id="5756163054456765343">స&amp;హాయ కేంద్రం</translation>
 <translation id="5759728514498647443">మీరు <ph name="APP_NAME" /> ద్వారా ముద్రించడానికి పంపే పత్రాలు <ph name="APP_NAME" /> ద్వారా చదవబడతాయి.</translation>
+<translation id="5762172915276660232">క్రెడిట్ కార్డ్ సెట్టింగ్‌లు</translation>
 <translation id="5763751966069581670">USB పరికరాలు కనుగొనబడలేదు</translation>
 <translation id="5764483294734785780">ఆడియోని ఇలా సే&amp;వ్ చెయ్యి...</translation>
 <translation id="57646104491463491">తేదీ సవరించబడింది</translation>
@@ -3185,6 +3193,7 @@
 <translation id="5855773610748894548">అయ్యో, సురక్షిత మాడ్యూల్ ఎర్రర్ ఏర్పడింది.</translation>
 <translation id="5856721540245522153">డీబగ్గింగ్ లక్షణాలను ప్రారంభించండి</translation>
 <translation id="5857090052475505287">క్రొత్త ఫోల్డర్</translation>
+<translation id="585979798156957858">బాహ్య మెటా</translation>
 <translation id="5860033963881614850">ఆఫ్ అయ్యింది</translation>
 <translation id="5860209693144823476">ట్యాబ్ 3</translation>
 <translation id="5860491529813859533">ఆన్ చేయండి</translation>
@@ -3215,7 +3224,7 @@
 <translation id="5908769186679515905">Flashని అమలు చేయనీయకుండా సైట్‌లను బ్లాక్ చేయి</translation>
 <translation id="5910363049092958439">చిత్రాన్ని ఇలా సే&amp;వ్ చెయ్యి...</translation>
 <translation id="5911737117543891828">తాత్కాలిక Google డిస్క్ ఆఫ్‌లైన్ ఫైల్‌లు తొలగించబడతాయి. మీరు ఆఫ్‌లైన్‌లో అందుబాటులో ఉంచేట్లుగా సెట్ చేసిన ఫైల్‌లు ఈ పరికరం నుండి తొలగించబడవు.</translation>
-<translation id="5911887972742538906">మీ Linux అప్లికేషన్ యొక్క ఇన్‌స్టాలేషన్ సమయంలో ఎర్రర్ సంభవించింది.</translation>
+<translation id="5911887972742538906">మీ Linux అప్లికేషన్ యొక్క ఇన్‌స్టాలేషన్ సమయంలో ఎర్రర్ ఏర్పడింది.</translation>
 <translation id="5912378097832178659">శోధన ఇంజిన్‌లను &amp;సవరించు...</translation>
 <translation id="5914724413750400082">మధ్యగుణకము (<ph name="MODULUS_NUM_BITS" /> బిట్‌లు):
   <ph name="MODULUS_HEX_DUMP" />
@@ -3494,6 +3503,7 @@
 <translation id="6327785803543103246">వెబ్ ప్రాక్సీ స్వీయశోధన</translation>
 <translation id="6333064448949140209">పైల్ డీబగ్గింగ్ కోసం Googleకి పంపబడుతుంది</translation>
 <translation id="6333834492048057036">శోధన చిరునామా పట్టీపై కేంద్రీకరించండి</translation>
+<translation id="6336451774241870485">కొత్త ప్రైవేట్ ట్యాబ్</translation>
 <translation id="6339668969738228384"><ph name="USER_EMAIL_ADDRESS" /> కోసం కొత్త ప్రొఫైల్‌ను సృష్టించు</translation>
 <translation id="6340017061976355871">సర్వర్‌కి కనెక్ట్ చేయడం సాధ్యం కాలేదు. దయచేసి మీ నెట్‌వర్క్ కనెక్షన్‌ని తనిఖీ చేసి, మళ్లీ ప్రయత్నించండి. సమస్య కొనసాగినట్లయితే, మీ Chromebookని పునఃప్రారంభించండి.</translation>
 <translation id="6340071272923955280">ఇంటర్నెట్ ముద్రణ ప్రోటోకాల్ (IPPS)</translation>
@@ -3675,6 +3685,7 @@
 <translation id="6606070663386660533">ట్యాబ్ 8</translation>
 <translation id="6607272825297743757">ఫైల్ సమాచారం</translation>
 <translation id="6607831829715835317">మరిన్ని సాధనా&amp;లు</translation>
+<translation id="6610147964972079463">ప్రైవేట్ ట్యాబ్‌ను మూసివేయి</translation>
 <translation id="6612358246767739896">రక్షిత కంటెంట్</translation>
 <translation id="6613452264606394692">ఈ పేజీని బుక్‌మార్క్ చేయడం ద్వారా ఇక్కడికి క్షణాల్లో తిరిగి రండి</translation>
 <translation id="6614893213975402384">అప్‌డేట్‌లు &amp; యాప్‌లను ఇన్‌స్టాల్ చేయండి. కొనసాగించడం ద్వారా, ఈ పరికరం Google, మీ క్యారియర్ మరియు మీ పరికర తయారీదారు నుండి అప్‌డేట్‌లు మరియు యాప్‌లను ఆటోమేటిక్‌గా కూడా డౌన్‌లోడ్ మరియు ఇన్‌స్టాల్ చేయవచ్చని మీరు అంగీకరిస్తున్నారు, బహుశా సెల్యులార్ డేటా ఉపయోగించబడవచ్చు. ఈ యాప్‌లలో కొన్ని యాప్‌లో కొనుగోళ్లను అందించవచ్చు. మీరు ఏ సమయంలో అయనా ఈ యాప్‌లను తీసివేయవచ్చు. <ph name="BEGIN_LINK1" />మరింత తెలుసుకోండి<ph name="END_LINK1" /></translation>
@@ -3745,6 +3756,7 @@
 <translation id="6710213216561001401">మునుపటి</translation>
 <translation id="6718273304615422081">జిప్ చేస్తోంది...</translation>
 <translation id="671928215901716392">స్క్రీన్‌ను లాక్ చేయి</translation>
+<translation id="6720847671508630642">Androidలోని ఉత్తమ అంశాలను మీ Chromebookతో ఆటోమేటిక్‌గా షేర్ చేసుకోండి. మీ కంప్యూటర్ నుండి సందేశాన్ని పంపించడానికి, మీ ఫోన్ ఇంటర్‌నెట్ కనెక్షన్‌ను షేర్ చేసుకోవడానికి ఇంకా మీ Chromebook స్క్రీన్‌ను అన్‌లాక్ చేయడానికి మీ ఫోన్‌ను కనెక్ట్ చేయండి.<ph name="FOOTNOTE_POINTER" /> <ph name="LINK_BEGIN" />మరింత తెలుసుకోండి<ph name="LINK_END" /></translation>
 <translation id="6721678857435001674">మీ భద్రతా కీ యొక్క తయారీదారు బ్రాండ్ పేరు మరియు మోడల్‌ని చూడండి</translation>
 <translation id="6721972322305477112">&amp;ఫైల్</translation>
 <translation id="672213144943476270">దయచేసి అతిథి వలె బ్రౌజ్ చేయబోయే ముందు మీ ప్రొఫైల్‌ను అన్‌లాక్ చేయండి.</translation>
@@ -3891,6 +3903,7 @@
 <translation id="6970856801391541997">ప్రత్యేకించిన పేజీలను ముద్రించు</translation>
 <translation id="6972180789171089114">ఆడియో/వీడియో</translation>
 <translation id="6973630695168034713">ఫోల్డర్‌లు</translation>
+<translation id="6974609594866392343">ఆఫ్‌లైన్ డెమో మోడ్</translation>
 <translation id="6976108581241006975">జావాస్క్రిప్ట్ కన్సోల్</translation>
 <translation id="6977381486153291903">ఫర్మ్‌వేర్ పునర్విమర్శ</translation>
 <translation id="6978121630131642226">శోధన ఇంజిన్‌లు</translation>
@@ -4004,7 +4017,7 @@
 <translation id="7127980134843952133">డౌన్‌లోడ్ చరిత్ర</translation>
 <translation id="7131040479572660648"><ph name="WEBSITE_1" />, <ph name="WEBSITE_2" /> మరియు <ph name="WEBSITE_3" />లోని మీ డేటాను చదవండి</translation>
 <translation id="713122686776214250">పే&amp;జీని జోడించండి...</translation>
-<translation id="7133578150266914903">మీ నిర్వాహకుడు మీ పరికరాన్ని మళ్లీ ప్రారంభిస్తున్నారు (<ph name="PROGRESS_PERCENT" />)</translation>
+<translation id="7133578150266914903">మీ నిర్వాహకుడు మీ పరికరాన్ని ఉపసంహరిస్తున్నారు (<ph name="PROGRESS_PERCENT" />)</translation>
 <translation id="7134098520442464001">టెక్స్ట్‌ని చిన్నదిగా చెయ్యండి</translation>
 <translation id="7136694880210472378">డిఫాల్ట్‌గా చెయ్యి</translation>
 <translation id="7136984461011502314"><ph name="PRODUCT_NAME" />కు స్వాగతం</translation>
@@ -4484,6 +4497,7 @@
 <translation id="7857949311770343000">మీరు ఆశిస్తున్న కొత్త ట్యాబ్ పేజీ ఇదేనా?</translation>
 <translation id="786073089922909430">సేవ: <ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7861215335140947162">&amp;డౌన్‌లోడ్‌లు</translation>
+<translation id="7864662577698025113">కొత్త సేవను జోడించు</translation>
 <translation id="7868378670806575181">{NUM_COOKIES,plural, =1{1 కుక్కీ}other{# కుక్కీలు}}</translation>
 <translation id="786957569166715433"><ph name="DEVICE_NAME" /> - జత చేయబడింది</translation>
 <translation id="7870730066603611552">సెటప్ చేసిన తర్వాత సమకాలీకరణ ఎంపికలను సమీక్షించండి</translation>
@@ -4888,7 +4902,7 @@
 <translation id="8497219075884839166">Windows వినియోగాలు</translation>
 <translation id="8498214519255567734">కాంతి తక్కువగా ఉన్నప్పుడు మీ స్క్రీన్‌ని చూడటం లేదా చదవడాన్ని సులభతరం చేస్తుంది</translation>
 <translation id="8498395510292172881">Chromeలో చదవడం కొనసాగించండి</translation>
-<translation id="8502536196501630039">Google Play నుండి యాప్‌లను ఉపయోగించడానికి, మీరు మొదట మీ యాప్‌లను పునరుద్ధరించాలి. కొంత డేటాను కోల్పోయే అవకాశం ఉంది.</translation>
+<translation id="8502536196501630039">Google Play నుండి యాప్‌లను ఉపయోగించడానికి, మీరు మొదట మీ యాప్‌లను పునరుద్ధరించాలి. ఆ యాప్‌లు కొంత డేటాను కోల్పోయి ఉండవచ్చు.</translation>
 <translation id="8503813439785031346">యూజర్‌పేరు</translation>
 <translation id="850875081535031620">హానికరమైన సాఫ్ట్‌వేర్ కనుగొనబడలేదు</translation>
 <translation id="8509646642152301857">అక్షరక్రమ తనిఖీ నిఘంటువును డౌన్‌లోడ్ చేయడం విఫలమైంది.</translation>
@@ -4996,6 +5010,7 @@
 <translation id="8666584013686199826">సైట్ USB పరికరాలను యాక్సెస్ చేయాలనుకున్నప్పుడు అడుగు</translation>
 <translation id="8667328578593601900">ఇప్పుడు <ph name="FULLSCREEN_ORIGIN" /> పూర్తి స్క్రీన్‌లో ఉంది మరియు మీ మౌస్ కర్సర్‌ను ఆపివేసింది.</translation>
 <translation id="8669284339312441707">తీక్షణమైనది</translation>
+<translation id="8669919703154928649">అసిస్టెంట్‌ను మీకు నోటిఫికేషన్‌లు చూపించడానికి అనుమతిస్తుంది</translation>
 <translation id="8669949407341943408">తరలించబడుతున్నాయి...</translation>
 <translation id="8671210955687109937">వ్యాఖ్యానించవచ్చు</translation>
 <translation id="8673026256276578048">వెబ్‌లో శోధించండి...</translation>
@@ -5213,7 +5228,7 @@
 <translation id="9009369504041480176">అప్‌లోడ్ అవుతోంది (<ph name="PROGRESS_PERCENT" />%)...</translation>
 <translation id="9011163749350026987">ఎల్లప్పుడూ చిహ్నాన్ని చూపు</translation>
 <translation id="9011178328451474963">చివరి ట్యాబ్</translation>
-<translation id="9013707997379828817">మీ నిర్వాహకుడు ఈ పరికరాన్ని తిరిగి ప్రారంభించారు. దయచేసి ముఖ్యమైన ఫైల్‌లను సేవ్ చేసి, ఆపై మళ్లీ ప్రారంభించండి. పరికరంలో ఉన్న మొత్తం డేటా తొలగించబడుతుంది.</translation>
+<translation id="9013707997379828817">మీ నిర్వాహకుడు ఈ పరికరాన్ని ఉపసంహరించారు. దయచేసి ముఖ్యమైన ఫైల్‌లను సేవ్ చేసి, ఆపై మళ్లీ ప్రారంభించండి. పరికరంలో ఉన్న మొత్తం డేటా తొలగించబడుతుంది.</translation>
 <translation id="9014987600015527693">మరొక ఫోన్‌ను చూపు</translation>
 <translation id="9018218886431812662">ఇన్‌స్టాలేషన్ పూర్తయింది</translation>
 <translation id="901834265349196618">ఇమెయిల్</translation>
@@ -5383,6 +5398,7 @@
 <translation id="964286338916298286">మీ IT నిర్వాహకుడు మీ పరికరానికి Chrome కానుకలను నిలిపివేసారు.</translation>
 <translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{అప్లికేషన్}other{అప్లికేషన్‌లు}}</translation>
 <translation id="967007123645306417">ఇది మిమ్మల్ని మీ google ఖాతా నుండి సైన్ అవుట్ చేస్తుంది. మీ బుక్‌మార్క్‌లు, చరిత్ర, పాస్‌వర్డ్‌లు మరియు ఇతర సెట్టింగ్‌లలోని మార్పులు మీ Google ఖాతాకి ఇకపై సమకాలీకరించబడవు. అయినప్పటికీ, ఇప్పటికే ఉన్న మీ డేటా Google ఖాతాలో నిల్వ చేయబడి ఉంటుంది మరియు దాన్ని <ph name="BEGIN_LINK" />Google డాష్‌బోర్డ్<ph name="END_LINK" />లో నిర్వహించుకోవచ్చు.</translation>
+<translation id="967624055006145463">నిల్వ చేయబడిన డేటా</translation>
 <translation id="968000525894980488">Google Play సేవలను ఆన్ చేయండి.</translation>
 <translation id="968174221497644223">అనువర్తన కాష్</translation>
 <translation id="969096075394517431">భాషలను మార్చండి</translation>
@@ -5399,7 +5415,7 @@
 <translation id="988978206646512040">రహస్య పదబంధం ఖాళీగా ఉంటే అనుమతించబడదు</translation>
 <translation id="992032470292211616">పొడిగింపులు, అనువర్తనాలు మరియు థీమ్‌లు మీ పరికరానికి హాని కలిగించవచ్చు. మీరు ఖచ్చితంగా కొనసాగాలనుకుంటున్నారా?</translation>
 <translation id="992592832486024913">ChromeVox (చదవబడే అభిప్రాయం)ని నిలిపివేయి</translation>
-<translation id="993540765962421562">ఇన్‌స్టాలేషన్ ప్రోగ్రెస్‌లో ఉంది</translation>
+<translation id="993540765962421562">ఇన్‌స్టాలేషన్ జరుగుతోంది</translation>
 <translation id="994289308992179865">&amp;లూప్</translation>
 <translation id="996250603853062861">సురక్షిత కనెక్షన్‌ను ప్రారంభిస్తోంది...</translation>
 <translation id="998747458861718449">ప&amp;ర్యవేక్షించు</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index 52e77f7..255fe18 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> ใน <ph name="PEPPER_PLUGIN_DOMAIN" /> ต้องการเข้าถึงคอมพิวเตอร์ของคุณ</translation>
 <translation id="2178614541317717477">ผู้มีสิทธิ์ออกใบรับรองไม่สมบูรณ์</translation>
 <translation id="218070003709087997">ใช้ตัวเลขเพื่อระบุจำนวนสำเนาที่ต้องการพิมพ์ (1 ถึง 999)</translation>
-<translation id="2183558561014688873">เข้าถึง Assistant ได้ทุกเมื่อเพียงพูดว่า "Ok Google" เมื่อหน้าจอเปิดอยู่และไม่ได้ล็อก</translation>
 <translation id="2187895286714876935">ข้อผิดพลาดในการนำเข้าใบรับรองเซิร์ฟเวอร์</translation>
 <translation id="2187906491731510095">อัปเดตส่วนขยายแล้ว</translation>
 <translation id="2188881192257509750">เปิด <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">ข้อมูลทั้งหมด (ยกเว้นคุกกี้) ที่ <ph name="SITE" /> จัดเก็บไว้จะถูกลบออก</translation>
 <translation id="237058345584060620">จับคู่คีย์กับอุปกรณ์นี้เพื่อให้คุณใช้คีย์ลงชื่อเข้าใช้บัญชีได้</translation>
 <translation id="2371076942591664043">เปิดเมื่อเ&amp;สร็จ</translation>
-<translation id="2376559921867170420">เมื่อตั้งค่า Chromebook แล้ว ก็กดปุ่ม Assistant หรือพูดว่า "Ok Google" เพื่อรับความช่วยเหลือจาก Assistant ได้ทุกเมื่อ</translation>
 <translation id="2377319039870049694">เปลี่ยนเป็นมุมมองรายการ</translation>
 <translation id="2377667304966270281">ฮาร์ดฟอลต์</translation>
 <translation id="2378075407703503998">เลือก <ph name="SELCTED_FILE_COUNT" /> ไฟล์</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">เพิ่มลายนิ้วมืออีก</translation>
 <translation id="3812525830114410218">ใบรับรองมีปัญหา</translation>
 <translation id="3813296892522778813">ไปที่<ph name="BEGIN_LINK_CHROMIUM" />ความช่วยเหลือของ Google Chrome<ph name="END_LINK_CHROMIUM" /> หากคุณไม่พบข้อมูลที่กำลังค้นหา</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">ไม่ได้ระบุ</translation>
 <translation id="3819752733757735746">การเข้าถึงด้วยสวิตช์ (ควบคุมคอมพิวเตอร์ด้วยสวิตช์เพียง 1-2 ตัว)</translation>
 <translation id="3819800052061700452">เ&amp;ต็มหน้าจอ</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">ลายนิ้วมือที่บันทึกไว้</translation>
 <translation id="407173827865827707">เมื่อคลิก</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: เกิดข้อผิดพลาดในการลงชื่อเข้าใช้</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">ใบรับรองผู้เซ็นชื่อในอีเมล</translation>
 <translation id="407520071244661467">ปรับขนาด</translation>
 <translation id="4075639477629295004">ไม่สามารถแคสต์ <ph name="FILE_NAME" /></translation>
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb
index deb708a..134e6bc 100644
--- a/chrome/app/resources/generated_resources_tr.xtb
+++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> alanındaki <ph name="PEPPER_PLUGIN_NAME" /> eklentisi bilgisayarınıza erişmek istiyor</translation>
 <translation id="2178614541317717477">CA Uzlaşması</translation>
 <translation id="218070003709087997">Yazdırılacak kopya sayısını göstermek için rakam kullanın (1 - 999 arası).</translation>
-<translation id="2183558561014688873">Cihazınız uyanık durumdayken "Ok Google" diyerek istediğiniz zaman Asistanınıza erişin.</translation>
 <translation id="2187895286714876935">Sunucu Sertifikası İçe Aktarma Hatası</translation>
 <translation id="2187906491731510095">Uzantılar güncellendi</translation>
 <translation id="2188881192257509750"><ph name="APPLICATION" /> adlı uygulamayı aç</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252"><ph name="SITE" /> web sitesinin depoladığı tüm veriler silinecek</translation>
 <translation id="237058345584060620">Anahtarınızı hesabınızda oturum açarken kullanabilmeniz için bu cihazla eşleyin</translation>
 <translation id="2371076942591664043">İşlem tamamlandığın&amp;da aç</translation>
-<translation id="2376559921867170420">Chromebook'unuzu kurarken istediğiniz zaman Asistanınızdan yardım almak için Asistan düğmesine basın veya "OK Google" deyin.</translation>
 <translation id="2377319039870049694">Liste görünümüne geç</translation>
 <translation id="2377667304966270281">Donanım Hataları</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> dosya seçildi</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Başka ekle</translation>
 <translation id="3812525830114410218">Bozuk sertifika</translation>
 <translation id="3813296892522778813">Aradığınız bilgiyi bulamazsanız <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome yardımına<ph name="END_LINK_CHROMIUM" /> gidin</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Belirtilmedi</translation>
 <translation id="3819752733757735746">Anahtar erişimi (bilgisayarı yalnızca bir veya iki anahtarla kontrol edin)</translation>
 <translation id="3819800052061700452">Tam ek&amp;ran</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Kayıtlı parmak izleri</translation>
 <translation id="407173827865827707">Tıklandığında</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: Oturum açma hatası</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">E-posta İmza Sahibi Sertifikası</translation>
 <translation id="407520071244661467">Ölçek</translation>
 <translation id="4075639477629295004"><ph name="FILE_NAME" /> yayınlanamıyor.</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb
index a00c9d6..28eeb2bb 100644
--- a/chrome/app/resources/generated_resources_uk.xtb
+++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724">Плагін <ph name="PEPPER_PLUGIN_NAME" /> із сайту <ph name="PEPPER_PLUGIN_DOMAIN" /> хоче отримати доступ до вашого комп’ютера</translation>
 <translation id="2178614541317717477">Дискредитація ЦС</translation>
 <translation id="218070003709087997">Використовуйте число, щоб указати кількість копій для друку (від 1 до 999).</translation>
-<translation id="2183558561014688873">Відкривайте Асистент командою "Ok Google", коли пристрій активовано й розблоковано.</translation>
 <translation id="2187895286714876935">Помилка імпортування сертифіката сервера</translation>
 <translation id="2187906491731510095">Розширення оновлено</translation>
 <translation id="2188881192257509750">Відкрити <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Усі дані, збережені сайтом <ph name="SITE" />, буде видалено (окрім файлів cookie).</translation>
 <translation id="237058345584060620">Підключіть ключ до пристрою, щоб входити з нього в обліковий запис</translation>
 <translation id="2371076942591664043">Відкрити коли &amp;виконано</translation>
-<translation id="2376559921867170420">Налаштувавши Chromebook, натисніть кнопку Асистента або скажіть "Ok Google", щоб будь-коли отримати допомогу від Асистента.</translation>
 <translation id="2377319039870049694">Список</translation>
 <translation id="2377667304966270281">Помилка жорсткого диска</translation>
 <translation id="2378075407703503998">Вибрано файлів: <ph name="SELCTED_FILE_COUNT" /></translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Додати ще</translation>
 <translation id="3812525830114410218">Недійсний сертифікат</translation>
 <translation id="3813296892522778813">Якщо не вдається знайти потрібний вміст, перейдіть на сторінку <ph name="BEGIN_LINK_CHROMIUM" />довідки Google Chrome<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Не вказано</translation>
 <translation id="3819752733757735746">Кнопковий доступ (керуйте комп’ютером однією чи двома кнопками)</translation>
 <translation id="3819800052061700452">&amp;На весь екран</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Збережені відбитки пальців</translation>
 <translation id="407173827865827707">Після натискання</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: помилка входу</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Сертифікат підписувача електронної пошти</translation>
 <translation id="407520071244661467">Масштаб</translation>
 <translation id="4075639477629295004">Не вдається транслювати файл <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb
index c84e727..7a6922b 100644
--- a/chrome/app/resources/generated_resources_vi.xtb
+++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_NAME" /> trên <ph name="PEPPER_PLUGIN_DOMAIN" /> muốn truy cập vào máy tính của bạn</translation>
 <translation id="2178614541317717477">Lộ CA</translation>
 <translation id="218070003709087997">Sử dụng một số để cho biết số bản cần in (1 đến 999).</translation>
-<translation id="2183558561014688873">Khi thiết bị đang ở chế độ bật và mở khóa, nói "Ok Google" bất cứ lúc nào để sử dụng Trợ lý.</translation>
 <translation id="2187895286714876935">Lỗi nhập chứng chỉ máy chủ</translation>
 <translation id="2187906491731510095">Đã cập nhật tiện ích</translation>
 <translation id="2188881192257509750">Mở <ph name="APPLICATION" /></translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">Tất cả dữ liệu do <ph name="SITE" /> lưu trữ sẽ bị xóa, ngoại trừ cookie.</translation>
 <translation id="237058345584060620">Ghép nối khóa với thiết bị này để bạn có thể đăng nhập vào tài khoản bằng khóa đó</translation>
 <translation id="2371076942591664043">Mở khi &amp;hoàn tất</translation>
-<translation id="2376559921867170420">Khi thiết lập Chromebook, hãy nhấn nút Trợ lý hoặc nói "OK Google" để nhận trợ giúp từ Trợ lý của bạn bất cứ lúc nào.</translation>
 <translation id="2377319039870049694">Chuyển sang chế độ xem danh sách</translation>
 <translation id="2377667304966270281">Lỗi phần cứng</translation>
 <translation id="2378075407703503998"><ph name="SELCTED_FILE_COUNT" /> tệp được chọn</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">Thêm vân tay khác</translation>
 <translation id="3812525830114410218">Chứng chỉ không hợp lệ</translation>
 <translation id="3813296892522778813">Hãy truy cập <ph name="BEGIN_LINK_CHROMIUM" />Trợ giúp Google Chrome<ph name="END_LINK_CHROMIUM" /> nếu bạn không tìm thấy nội dung mình đang tìm kiếm</translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">Không được cung cấp</translation>
 <translation id="3819752733757735746">Tiếp cận bằng công tắc (điều khiển máy tính chỉ bằng một hoặc hai công tắc)</translation>
 <translation id="3819800052061700452">&amp;Toàn màn hình</translation>
@@ -2049,7 +2048,6 @@
 <translation id="4068776064906523561">Vân tay đã lưu</translation>
 <translation id="407173827865827707">Khi nhấp chuột</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />: lỗi đăng nhập</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">Chứng chỉ Người ký Email</translation>
 <translation id="407520071244661467">Tỷ lệ</translation>
 <translation id="4075639477629295004">Không thể truyền <ph name="FILE_NAME" />.</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb
index 323a032..7a84bf6 100644
--- a/chrome/app/resources/generated_resources_zh-CN.xtb
+++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -398,6 +398,7 @@
 <translation id="1589055389569595240">显示拼写和语法</translation>
 <translation id="1593594475886691512">正在格式化…</translation>
 <translation id="159359590073980872">图片缓存</translation>
+<translation id="1593926297800505364">保存付款方式</translation>
 <translation id="1598233202702788831">您的管理员已停用更新。</translation>
 <translation id="1600857548979126453">访问页面调试程序后端</translation>
 <translation id="1601560923496285236">应用</translation>
@@ -508,6 +509,7 @@
 <translation id="1744060673522309905">无法将此设备加入到该网域中。请确保您未超出可添加的设备数量上限。</translation>
 <translation id="1744108098763830590">背景页</translation>
 <translation id="1745520510852184940">一律进行此翻译</translation>
+<translation id="1746417874336251387">提供将手机与 Chromebook 连接便能使用的新功能</translation>
 <translation id="174937106936716857">文件总数</translation>
 <translation id="175196451752279553">重新打开关闭的标签页(&amp;E)</translation>
 <translation id="1753905327828125965">常去网站</translation>
@@ -638,8 +640,10 @@
 <translation id="1932098463447129402">不早于</translation>
 <translation id="1933809209549026293">请连接鼠标或键盘。如果您使用蓝牙设备,请确保它可进行配对。</translation>
 <translation id="1936157145127842922">在文件夹中显示</translation>
+<translation id="1938351510777341717">外部命令</translation>
 <translation id="1940546824932169984">已连接的设备</translation>
 <translation id="1942765061641586207">图片分辨率</translation>
+<translation id="1943097386230153518">安装新服务</translation>
 <translation id="1944921356641260203">发现更新</translation>
 <translation id="1951615167417147110">向上滚动一个网页</translation>
 <translation id="1954813140452229842">装载共享资源时出错。请检查您的凭据,然后重试。</translation>
@@ -788,7 +792,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> 上的“<ph name="PEPPER_PLUGIN_NAME" />”想访问您的计算机</translation>
 <translation id="2178614541317717477">CA 泄漏</translation>
 <translation id="218070003709087997">用数字表示要打印多少份(1 到 999 份)。</translation>
-<translation id="2183558561014688873">当设备处于唤醒状态且已解锁时,您可以随时访问自己的 Google 助理,只需说“Ok Google”即可。</translation>
 <translation id="2187895286714876935">服务器证书导入错误</translation>
 <translation id="2187906491731510095">扩展程序已更新</translation>
 <translation id="2188881192257509750">打开 <ph name="APPLICATION" /></translation>
@@ -917,7 +920,6 @@
 <translation id="2369536625682139252">即将删除 <ph name="SITE" /> 存储的所有数据(Cookie 除外)。</translation>
 <translation id="237058345584060620">将您的密钥与此设备配对,即可使用该密钥登录您的帐号</translation>
 <translation id="2371076942591664043">完成时打开(&amp;D)</translation>
-<translation id="2376559921867170420">设置完 Chromebook 后,您只需按 Google 助理按钮或说出“Ok Google”,便可随时获得 Google 助理的帮助。</translation>
 <translation id="2377319039870049694">切换到列表视图</translation>
 <translation id="2377667304966270281">硬故障数</translation>
 <translation id="2378075407703503998">已选择 <ph name="SELCTED_FILE_COUNT" /> 个文件</translation>
@@ -1104,6 +1106,7 @@
 <translation id="2653659639078652383">提交</translation>
 <translation id="265390580714150011">字段值</translation>
 <translation id="2654166010170466751">允许网站安装付款处理程序</translation>
+<translation id="2659381484350128933"><ph name="FOOTNOTE_POINTER" />功能因设备而异</translation>
 <translation id="2660779039299703961">事件</translation>
 <translation id="266079277508604648">无法连接到打印机。请确保该打印机已开机且已通过 Wi-Fi 或 USB 连接到您的 Chromebook。</translation>
 <translation id="2661146741306740526">16x9</translation>
@@ -1210,6 +1213,7 @@
 <translation id="2803375539583399270">输入 PIN 码</translation>
 <translation id="2805646850212350655">Microsoft 加密文件系统</translation>
 <translation id="2805756323405976993">应用</translation>
+<translation id="2806891468525657116">快捷方式已存在</translation>
 <translation id="2807517655263062534">您下载的文件会显示在此处</translation>
 <translation id="2809586584051668049">及另外<ph name="NUMBER_ADDITIONAL_DISABLED" />个扩展程序</translation>
 <translation id="281133045296806353">已在现有的浏览器会话中创建新的窗口。</translation>
@@ -1594,6 +1598,7 @@
 <translation id="3428419049384081277">您已登录!</translation>
 <translation id="3429275422858276529">为此网页添加书签,以便日后查找</translation>
 <translation id="3429599832623003132">$1 项</translation>
+<translation id="3430342160185525240">允许 Google 助理向您显示通知。</translation>
 <translation id="3432227430032737297">移除显示的所有 Cookie</translation>
 <translation id="3432757130254800023">向本地网络上的显示屏发送音频和视频</translation>
 <translation id="3432762828853624962">Shared Workers</translation>
@@ -1866,6 +1871,7 @@
 <translation id="381202950560906753">添加其他指纹</translation>
 <translation id="3812525830114410218">证书有误</translation>
 <translation id="3813296892522778813">如果您找不到要查找的内容,请参阅 <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome 帮助<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">未提供</translation>
 <translation id="3819752733757735746">开关控制(只需一两个开关即可控制计算机)</translation>
 <translation id="3819800052061700452">全屏(&amp;F)</translation>
@@ -1957,6 +1963,7 @@
 <translation id="3941565636838060942">要禁止使用此程序,您需要使用控制面板中的“<ph name="CONTROL_PANEL_APPLET_NAME" />”将其卸载。
 
   要启动“<ph name="CONTROL_PANEL_APPLET_NAME" />”吗?</translation>
+<translation id="394183848452296464">无法创建快捷方式</translation>
 <translation id="3943582379552582368">返回(&amp;B)</translation>
 <translation id="3943857333388298514">粘贴</translation>
 <translation id="3948116654032448504">通过<ph name="SEARCH_ENGINE" />搜索图片(&amp;S)</translation>
@@ -2034,7 +2041,6 @@
 <translation id="4068776064906523561">已保存的指纹</translation>
 <translation id="407173827865827707">点击时</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />:登录错误</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">电子邮件签名人证书</translation>
 <translation id="407520071244661467">缩放</translation>
 <translation id="4075639477629295004">无法投射“<ph name="FILE_NAME" />”。</translation>
@@ -2264,6 +2270,7 @@
 <translation id="4481530544597605423">未配对的设备</translation>
 <translation id="4482194545587547824">Google 可能会使用您的浏览记录对 Google 搜索和其他 Google 服务进行个性化设置</translation>
 <translation id="4495419450179050807">不要在本页上显示</translation>
+<translation id="4499718683476608392">启用信用卡自动填充功能后,只需点击一次即可填写多个表单</translation>
 <translation id="4500114933761911433">“<ph name="PLUGIN_NAME" />”崩溃了</translation>
 <translation id="450099669180426158">感叹号图标</translation>
 <translation id="4501530680793980440">确认删除</translation>
@@ -3101,6 +3108,7 @@
 <translation id="5752453871435543420">Chrome 操作系统云端备份</translation>
 <translation id="5756163054456765343">帮助中心(&amp;E)</translation>
 <translation id="5759728514498647443">您通过“<ph name="APP_NAME" />”发送以进行打印的文档可由“<ph name="APP_NAME" />”读取。</translation>
+<translation id="5762172915276660232">信用卡设置</translation>
 <translation id="5763751966069581670">未找到任何 USB 设备</translation>
 <translation id="5764483294734785780">音频另存为(&amp;V)...</translation>
 <translation id="57646104491463491">修改日期</translation>
@@ -3172,6 +3180,7 @@
 <translation id="5855773610748894548">糟糕,安全模块出错了。</translation>
 <translation id="5856721540245522153">启用调试功能</translation>
 <translation id="5857090052475505287">新文件夹</translation>
+<translation id="585979798156957858">外部 Meta 键</translation>
 <translation id="5860033963881614850">关闭</translation>
 <translation id="5860209693144823476">标签页 3</translation>
 <translation id="5860491529813859533">启用</translation>
@@ -3481,6 +3490,7 @@
 <translation id="6327785803543103246">网络代理自动发现</translation>
 <translation id="6333064448949140209">文件将发送到 Google 进行调试</translation>
 <translation id="6333834492048057036">将光标移到地址栏以进行搜索</translation>
+<translation id="6336451774241870485">新私密标签页</translation>
 <translation id="6339668969738228384">为 <ph name="USER_EMAIL_ADDRESS" /> 创建新的个人资料</translation>
 <translation id="6340017061976355871">无法与此服务器建立连接。请检查您的网络连接,然后重试。如果问题仍然存在,请重新启动您的 Chromebook。</translation>
 <translation id="6340071272923955280">互联网打印协议 (IPPS)</translation>
@@ -3661,6 +3671,7 @@
 <translation id="6606070663386660533">标签页 8</translation>
 <translation id="6607272825297743757">文件信息</translation>
 <translation id="6607831829715835317">更多工具(&amp;L)</translation>
+<translation id="6610147964972079463">关闭私密标签页</translation>
 <translation id="6612358246767739896">受保护的内容</translation>
 <translation id="6613452264606394692">只需为此网页添加书签,便可在需要时快速返回到此处</translation>
 <translation id="6614893213975402384">安装更新和应用。继续操作即表示您同意此设备还可从 Google、您的运营商以及您设备的制造商处自动下载及安装更新和应用(可能会使用移动数据网络)。部分应用可能会提供应用内购商品。您可以随时卸载这些应用。<ph name="BEGIN_LINK1" />了解详情<ph name="END_LINK1" /></translation>
@@ -3731,6 +3742,7 @@
 <translation id="6710213216561001401">上一个</translation>
 <translation id="6718273304615422081">正在压缩…</translation>
 <translation id="671928215901716392">锁定屏幕</translation>
+<translation id="6720847671508630642">自动将最佳 Android 功能分享给您的 Chromebook。连接手机后,您便可通过计算机收发短信、共享手机的互联网连接以及解锁 Chromebook 屏幕。<ph name="FOOTNOTE_POINTER" /><ph name="LINK_BEGIN" />了解详情<ph name="LINK_END" /></translation>
 <translation id="6721678857435001674">查看您的安全密钥的品牌和型号</translation>
 <translation id="6721972322305477112">文件(&amp;F)</translation>
 <translation id="672213144943476270">在以访客身份浏览前,请先解锁您的个人资料。</translation>
@@ -3877,6 +3889,7 @@
 <translation id="6970856801391541997">打印特定页面</translation>
 <translation id="6972180789171089114">音频/视频</translation>
 <translation id="6973630695168034713">文件夹</translation>
+<translation id="6974609594866392343">离线演示模式</translation>
 <translation id="6976108581241006975">JavaScript 控制台</translation>
 <translation id="6977381486153291903">固件版本</translation>
 <translation id="6978121630131642226">搜索引擎</translation>
@@ -4469,6 +4482,7 @@
 <translation id="7857949311770343000">这是您想要的新标签页吗?</translation>
 <translation id="786073089922909430">服务:<ph name="ARC_PROCESS_NAME" /></translation>
 <translation id="7861215335140947162">下载内容(&amp;D)</translation>
+<translation id="7864662577698025113">添加新服务</translation>
 <translation id="7868378670806575181">{NUM_COOKIES,plural, =1{1 个 Cookie}other{# 个 Cookie}}</translation>
 <translation id="786957569166715433"><ph name="DEVICE_NAME" /> - 已配对</translation>
 <translation id="7870730066603611552">完成设置后查看同步选项</translation>
@@ -4983,6 +4997,7 @@
 <translation id="8666584013686199826">当网站要访问 USB 设备时询问您</translation>
 <translation id="8667328578593601900"><ph name="FULLSCREEN_ORIGIN" /> 现处于全屏模式并已隐藏鼠标指针。</translation>
 <translation id="8669284339312441707">暖色调</translation>
+<translation id="8669919703154928649">允许 Google 助理向您显示通知</translation>
 <translation id="8669949407341943408">正在移动…</translation>
 <translation id="8671210955687109937">可以评论</translation>
 <translation id="8673026256276578048">搜索网页...</translation>
@@ -5370,6 +5385,7 @@
 <translation id="964286338916298286">您的 IT 管理员已禁止您的设备享用 Chrome 附赠的好礼。</translation>
 <translation id="964439421054175458">{NUM_APLLICATIONS,plural, =1{应用}other{应用}}</translation>
 <translation id="967007123645306417">执行此操作会使您退出 Google 帐号。您对自己的书签、历史记录、密码及其他设置所做的更改将不再同步到您的 Google 帐号。但是,您的现有数据将会继续存储在您的 Google 帐号中并可通过 <ph name="BEGIN_LINK" />Google 信息中心<ph name="END_LINK" />进行管理。</translation>
+<translation id="967624055006145463">已存储的数据</translation>
 <translation id="968000525894980488">开启 Google Play 服务。</translation>
 <translation id="968174221497644223">应用缓存</translation>
 <translation id="969096075394517431">更改语言</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 723b8ac..6340bcf 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -795,7 +795,6 @@
 <translation id="2178098616815594724"><ph name="PEPPER_PLUGIN_DOMAIN" /> 的「<ph name="PEPPER_PLUGIN_NAME" />」要求存取你的電腦</translation>
 <translation id="2178614541317717477">CA 洩露</translation>
 <translation id="218070003709087997">使用數字指定列印份數 (1 至 999)。</translation>
-<translation id="2183558561014688873">在裝置已喚醒並解鎖的狀態下,只要說出「Ok Google」,就能隨時存取 Google 助理。</translation>
 <translation id="2187895286714876935">伺服器憑證匯入錯誤</translation>
 <translation id="2187906491731510095">擴充功能已更新</translation>
 <translation id="2188881192257509750">開啟「<ph name="APPLICATION" />」</translation>
@@ -924,7 +923,6 @@
 <translation id="2369536625682139252">即將刪除 <ph name="SITE" /> 儲存的所有資料 (Cookie 除外)。</translation>
 <translation id="237058345584060620">將你的金鑰與這個裝置配對,即可透過金鑰登入你的帳戶</translation>
 <translation id="2371076942591664043">完成後開啟(&amp;D)</translation>
-<translation id="2376559921867170420">Chromebook 設定完成後,只要按下 Google 助理按鈕或說出「Ok Google」,就能隨時向你的 Google 助理下達指令。</translation>
 <translation id="2377319039870049694">切換為清單檢視</translation>
 <translation id="2377667304966270281">硬性錯誤數</translation>
 <translation id="2378075407703503998">已選取 <ph name="SELCTED_FILE_COUNT" /> 個檔案</translation>
@@ -1879,6 +1877,7 @@
 <translation id="381202950560906753">新增其他指紋</translation>
 <translation id="3812525830114410218">錯誤的憑證</translation>
 <translation id="3813296892522778813">如果你找不到需要的資訊,請參閱 <ph name="BEGIN_LINK_CHROMIUM" />Google Chrome 說明<ph name="END_LINK_CHROMIUM" /></translation>
+<translation id="3813984289128269159">Ok Google</translation>
 <translation id="3817579325494460411">未提供</translation>
 <translation id="3819752733757735746">開關功能 (使用一或兩種切換設定就能操控電腦)</translation>
 <translation id="3819800052061700452">全螢幕(&amp;F)</translation>
@@ -2048,7 +2047,6 @@
 <translation id="4068776064906523561">已儲存的指紋</translation>
 <translation id="407173827865827707">點擊時</translation>
 <translation id="4071770069230198275"><ph name="PROFILE_NAME" />:登入錯誤</translation>
-<translation id="4071828814509176232">Ok Google</translation>
 <translation id="4074900173531346617">電子郵件簽署者憑證</translation>
 <translation id="407520071244661467">縮放比例</translation>
 <translation id="4075639477629295004">無法投放「<ph name="FILE_NAME" />」。</translation>
diff --git a/chrome/app/resources/google_chrome_strings_bn.xtb b/chrome/app/resources/google_chrome_strings_bn.xtb
index c0b5ede..9fd320ac 100644
--- a/chrome/app/resources/google_chrome_strings_bn.xtb
+++ b/chrome/app/resources/google_chrome_strings_bn.xtb
@@ -255,6 +255,7 @@
 <translation id="8179874765710681175">আপনার ফোনে Chrome ইনস্টল করুন। আমরা আপনার ফোন থেকে একটি এসএমএস পাঠাব।</translation>
 <translation id="8183957050892517584">Chrome আপনার ব্যক্তিগত বিবরণ সুরক্ষিত ভাবে সঞ্চয় করবে, তাই আপনার আর টাইপ করার প্রয়োজন হবে না।</translation>
 <translation id="8226081633851087288">{0,plural, =0{Chrome OS এখন রিস্টার্ট হবে}=1{Chrome OS ১ সেকেন্ডের মধ্যে রিস্টার্ট হবে}one{Chrome OS # সেকেন্ডের মধ্যে রিস্টার্ট হবে}other{Chrome OS # সেকেন্ডের মধ্যে রিস্টার্ট হবে}}</translation>
+<translation id="825412236959742607">এই পৃষ্ঠাটি খুব বেশি মেমরি ব্যবহার করছে তাই Chrome কিছু কন্টেন্ট সরিয়ে দিয়েছে।</translation>
 <translation id="8255190535488645436">Google Chrome আপনার ক্যামেরা এবং মাইক্রোফোন ব্যবহার করছে৷</translation>
 <translation id="8286862437124483331">Google Chrome পাসওয়ার্ডগুলি দেখানোর চেষ্টা করছে। এটির অনুমতি দিতে আপনার Windows পাসওয়ার্ড টাইপ করুন।</translation>
 <translation id="8290100596633877290">হোয়া! Google Chrome ক্র্যাশ হয়েছে৷ এখনই পুনঃলঞ্চ করবেন?</translation>
diff --git a/chrome/app/resources/google_chrome_strings_es-419.xtb b/chrome/app/resources/google_chrome_strings_es-419.xtb
index 39e468b5..68e7c6ad 100644
--- a/chrome/app/resources/google_chrome_strings_es-419.xtb
+++ b/chrome/app/resources/google_chrome_strings_es-419.xtb
@@ -251,6 +251,7 @@
 <translation id="8179874765710681175">Instala Chrome en el teléfono. Te enviaremos un SMS a ese dispositivo.</translation>
 <translation id="8183957050892517584">Chromium almacenará de forma segura tus datos personales para que no tengas que volver a escribirlos.</translation>
 <translation id="8226081633851087288">{0,plural, =0{El Sistema operativo Chrome se reiniciará ahora}=1{El Sistema operativo Chrome se reiniciará en 1 segundo}other{El Sistema operativo Chrome se reiniciará en # segundos}}</translation>
+<translation id="825412236959742607">Chrome quitó parte del contenido de esta página porque usa demasiada memoria.</translation>
 <translation id="8255190535488645436">Google Chrome está usando tu cámara y tu micrófono.</translation>
 <translation id="8286862437124483331">Google Chrome está intentando mostrar contraseñas. Para permitirlo, ingresa tu contraseña de Windows.</translation>
 <translation id="8290100596633877290">¡Vaya! Se ha producido un bloqueo en Google Chrome. ¿Quieres reiniciar el navegador ahora?</translation>
diff --git a/chrome/app/resources/google_chrome_strings_te.xtb b/chrome/app/resources/google_chrome_strings_te.xtb
index 720f8b9a..d6c085f 100644
--- a/chrome/app/resources/google_chrome_strings_te.xtb
+++ b/chrome/app/resources/google_chrome_strings_te.xtb
@@ -154,7 +154,7 @@
 <translation id="4990567037958725628">Google Chrome కేనరీ</translation>
 <translation id="5028489144783860647">Google Chrome మీ డేటాను సమకాలీకరించలేకపోయింది. దయచేసి మీ సమకాలీకరణ రహస్య పదబంధాన్ని నవీకరించండి.</translation>
 <translation id="5062123544085870375">Chrome OSను మళ్లీ ప్రారంభించండి</translation>
-<translation id="5090044601776247154">పర్యవేక్షించబడే వినియోగదారు ప్రొఫైల్‌లు Google Chrome 70తో ప్రారంభమయ్యే వాటిల్లో ఇకపై అందుబాటులో ఉండవు.</translation>
+<translation id="5090044601776247154">Google Chrome 70తో మొదలు పెట్టి, తర్వాతి వెర్షన్‌లలో పర్యవేక్షించబడే వినియోగదారు ప్రొఫైల్‌లు ఇకపై అందుబాటులో ఉండవు.</translation>
 <translation id="5132929315877954718">Google Chrome కోసం గొప్ప అనువర్తనాలు, ఆటలు, పొడిగింపులు మరియు థీమ్‌లను కనుగొనండి.</translation>
 <translation id="5166975452760862670">Google Chrome ఈ భాషలో ప్రదర్శించబడుతోంది</translation>
 <translation id="5170938038195470297">మీ ప్రొఫైల్ ఉపయోగించబడదు ఎందుకంటే ఇది ఒక క్రొత్త Google Chrome సంస్కరణ నుండి తీసుకోబడింది. కొన్ని లక్షణాలు అందుబాటులో ఉండకపోవచ్చు. దయచేసి వేరొక ప్రొఫైల్ డైరెక్టరీని పేర్కొనండి లేదా Chrome యొక్క క్రొత్త సంస్కరణను ఉపయోగించండి.</translation>
@@ -165,7 +165,7 @@
 <translation id="5386244825306882791">ఇది మీరు Chromeని ప్రారంభించేటప్పుడు లేదా ఓమ్నిపెట్టె నుండి శోధించేటప్పుడు చూపబడే పేజీని కూడా నియంత్రిస్తుంది.</translation>
 <translation id="5430073640787465221">మీ ప్రాధాన్యతల ఫైల్ పాడైంది లేదా చెల్లదు. Google Chrome మీ సెట్టింగ్‌లను తిరిగి పొందలేకపోయింది.</translation>
 <translation id="5483595757826856374">{0,plural, =0{ఇప్పుడు Chrome తిరిగి ప్రారంభించబడుతుంది}=1{1 సెకనులో Chrome తిరిగి ప్రారంభించబడుతుంది}other{# సెకన్లలో Chrome తిరిగి ప్రారంభించబడుతుంది}}</translation>
-<translation id="5514308096618405748">Linux (బీటా)గా అదనపు <ph name="BEGIN_LINK_CROS_OSS" />ఓపన్ సోర్స్ సాఫ్ట్‌వేర్‌<ph name="END_LINK_CROS_OSS" /> ద్వారా Chrome OS సాధ్యం అవుతుంది.</translation>
+<translation id="5514308096618405748">Linux (బీటా) లాగానే, Chrome OS కూడా అదనపు <ph name="BEGIN_LINK_CROS_OSS" />ఓపెన్ సోర్స్ సాఫ్ట్‌వేర్‌<ph name="END_LINK_CROS_OSS" />పై ఎంతగానో ఆధారపడుతుంది.</translation>
 <translation id="556024056938947818">Google Chrome పాస్‌వర్డ్‌లను చూపడానికి ప్రయత్నిస్తోంది.</translation>
 <translation id="5566025111015594046">Google Chrome (mDNS-In)</translation>
 <translation id="565744775970812598"><ph name="FILE_NAME" /> హానికరం కావచ్చు, కావున Chrome దాన్ని బ్లాక్ చేసింది.</translation>
@@ -251,6 +251,7 @@
 <translation id="8179874765710681175">మీ ఫోన్‌లో Chromeని ఇన్‌స్టాల్ చేయండి. మేము మీ ఫోన్‌కు SMSను పంపుతాము.</translation>
 <translation id="8183957050892517584">Chrome మీ వ్యక్తిగత వివరాలను సురక్షితంగా నిల్వ చేస్తుంది కాబట్టి మీరు వాటిని మళ్లీ టైప్ చేయాల్సిన అవసరం లేదు.</translation>
 <translation id="8226081633851087288">{0,plural, =0{Chrome OS ఇప్పుడు మళ్లీ ప్రారంభించబడుతుంది}=1{Chrome OS 1 సెకనులో మళ్లీ ప్రారంభించబడుతుంది}other{Chrome OS # సెకన్లలో మళ్లీ ప్రారంభించబడుతుంది}}</translation>
+<translation id="825412236959742607">ఈ పేజీ చాలా మెమరీని ఉపయోగిస్తుంది, కాబట్టి Chrome కొంత కంటెంట్‌ను తీసివేసింది.</translation>
 <translation id="8255190535488645436">Google Chrome మీ కెమెరా మరియు మైక్రోఫోన్‌ని ఉపయోగిస్తోంది.</translation>
 <translation id="8286862437124483331">Google Chrome పాస్‌వర్డ్‌లను చూపడానికి ప్రయత్నిస్తోంది. దీన్ని అనుమతించడానికి మీ Windows పాస్‌వర్డ్‌ను టైప్ చేయండి.</translation>
 <translation id="8290100596633877290">ఆపండి! Google Chrome క్రాష్ అయ్యింది. ఇప్పుడు మళ్ళీ ప్రారంభించాల?</translation>
diff --git a/chrome/app/resources/google_chrome_strings_zh-CN.xtb b/chrome/app/resources/google_chrome_strings_zh-CN.xtb
index f0bb4e6e..dcc8af09 100644
--- a/chrome/app/resources/google_chrome_strings_zh-CN.xtb
+++ b/chrome/app/resources/google_chrome_strings_zh-CN.xtb
@@ -252,6 +252,7 @@
 <translation id="8179874765710681175">请在您的手机上安装 Chrome。我们会向您的手机发送一条短信。</translation>
 <translation id="8183957050892517584">Chrome 将妥善存储您的个人详细信息,这样您日后就不必重复输入了。</translation>
 <translation id="8226081633851087288">{0,plural, =0{Chrome 操作系统将会立即重启}=1{Chrome 操作系统将会在 1 秒后重启}other{Chrome 操作系统将会在 # 秒后重启}}</translation>
+<translation id="825412236959742607">此网页占用的内存过多,因此 Chrome 移除了部分内容。</translation>
 <translation id="8255190535488645436">Google Chrome 正在使用您的摄像头和麦克风。</translation>
 <translation id="8286862437124483331">Google Chrome正在尝试显示密码,请输入您的Windows密码以允许此操作。</translation>
 <translation id="8290100596633877290">哎呀!Google Chrome 浏览器崩溃了。是否立即重新启动?</translation>
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 5520177f..adc13b33 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -105,7 +105,6 @@
     "tab_audio_muting_rounded.icon",
     "tab_audio_rounded.icon",
     "tab_bluetooth_connected.icon",
-    "tab_close_button_touch.icon",
     "tab_close_normal.icon",
     "tab_media_capturing.icon",
     "tab_media_capturing_with_arrow.icon",
diff --git a/chrome/app/vector_icons/tab_close_button_touch.icon b/chrome/app/vector_icons/tab_close_button_touch.icon
deleted file mode 100644
index 42461c0f7..0000000
--- a/chrome/app/vector_icons/tab_close_button_touch.icon
+++ /dev/null
@@ -1,18 +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.
-
-CANVAS_DIMENSIONS, 24,
-MOVE_TO, 16.83f, 8.35f,
-LINE_TO, 15.65f, 7.17f,
-LINE_TO, 12, 10.82f,
-LINE_TO, 8.35f, 7.17f,
-LINE_TO, 7.17f, 8.35f,
-LINE_TO, 10.82f, 12,
-LINE_TO, 7.17f, 15.65f,
-LINE_TO, 8.35f, 16.83f,
-LINE_TO, 12, 13.18f,
-LINE_TO, 15.65f, 16.83f,
-LINE_TO, 16.83f, 15.65f,
-LINE_TO, 13.18f, 12,
-CLOSE
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7190013..569af2c 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1742,7 +1742,7 @@
     "//components/mirroring/browser:browser",
     "//components/mirroring/mojom:host",
     "//components/mirroring/mojom:service",
-    "//components/mirroring/service:service",
+    "//components/mirroring/service:mirroring_service",
     "//components/navigation_interception",
     "//components/navigation_metrics",
     "//components/net_log",
@@ -2585,6 +2585,8 @@
       "lifetime/browser_close_manager.h",
       "lifetime/termination_notification.cc",
       "lifetime/termination_notification.h",
+      "media/unified_autoplay_config.cc",
+      "media/unified_autoplay_config.h",
       "media/webrtc/tab_desktop_media_list.cc",
       "media/webrtc/tab_desktop_media_list.h",
       "media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index dc09a32..12e5e71 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2046,10 +2046,6 @@
 #endif  // ENABLE_EXTENSIONS
 #if !defined(OS_ANDROID)
 #if defined(OS_CHROMEOS)
-    {"enable-ash-sidebar", flag_descriptions::kAshSidebarName,
-     flag_descriptions::kAshSidebarDescription, kOsCrOS,
-     ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshSidebarEnabled,
-                               ash::switches::kAshSidebarDisabled)},
     {"enable-system-tray-unified", flag_descriptions::kSystemTrayUnifiedName,
      flag_descriptions::kSystemTrayUnifiedDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kSystemTrayUnified)},
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index ab82acdc..ebbbebc 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -140,17 +140,13 @@
       item->GetLastAccessTime().ToJavaTime(), item->IsDangerous());
 }
 
-static jlong JNI_DownloadManagerService_Init(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& jobj) {
-  Profile* profile = ProfileManager::GetActiveUserProfile();
+static jlong JNI_DownloadManagerService_Init(JNIEnv* env,
+                                             const JavaParamRef<jobject>& jobj,
+                                             jboolean is_full_browser_started) {
   DownloadManagerService* service = DownloadManagerService::GetInstance();
   service->Init(env, jobj);
-  DownloadCoreService* download_core_service =
-      DownloadCoreServiceFactory::GetForBrowserContext(profile);
-  DownloadHistory* history = download_core_service->GetDownloadHistory();
-  if (history)
-    history->AddObserver(service);
+  if (is_full_browser_started)
+    service->OnFullBrowserStarted(env, jobj);
   return reinterpret_cast<intptr_t>(service);
 }
 
@@ -175,9 +171,18 @@
 void DownloadManagerService::Init(
     JNIEnv* env,
     jobject obj) {
+  java_ref_.Reset(env, obj);
+}
+
+void DownloadManagerService::OnFullBrowserStarted(JNIEnv* env, jobject obj) {
   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
                  content::NotificationService::AllSources());
-  java_ref_.Reset(env, obj);
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  DownloadCoreService* download_core_service =
+      DownloadCoreServiceFactory::GetForBrowserContext(profile);
+  DownloadHistory* history = download_core_service->GetDownloadHistory();
+  if (history)
+    history->AddObserver(this);
 }
 
 void DownloadManagerService::Observe(
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h
index 316d8ac..d32a310f 100644
--- a/chrome/browser/android/download/download_manager_service.h
+++ b/chrome/browser/android/download/download_manager_service.h
@@ -58,6 +58,9 @@
   // Called to Initialize this object.
   void Init(JNIEnv* env, jobject obj);
 
+  // Called when full browser process starts.
+  void OnFullBrowserStarted(JNIEnv* env, jobject obj);
+
   // Called to open a given download item.
   void OpenDownload(download::DownloadItem* download, int source);
 
diff --git a/chrome/browser/android/vr/gl_browser_interface.h b/chrome/browser/android/vr/gl_browser_interface.h
index 0e03d914..86a6f000 100644
--- a/chrome/browser/android/vr/gl_browser_interface.h
+++ b/chrome/browser/android/vr/gl_browser_interface.h
@@ -9,6 +9,7 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "chrome/browser/vr/assets_load_status.h"
+#include "chrome/browser/vr/render_loop_browser_interface.h"
 #include "chrome/browser/vr/ui_test_input.h"
 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
@@ -23,9 +24,9 @@
 
 // VrShellGl talks to VrShell through this interface. This could be split up if
 // VrShellGl is refactored into components.
-class GlBrowserInterface {
+class GlBrowserInterface : public RenderLoopBrowserInterface {
  public:
-  virtual ~GlBrowserInterface() = default;
+  ~GlBrowserInterface() override = default;
 
   virtual void ContentSurfaceCreated(jobject surface,
                                      gl::SurfaceTexture* texture) = 0;
@@ -37,10 +38,7 @@
   virtual void DialogSurfaceCreated(jobject surface,
                                     gl::SurfaceTexture* texture) = 0;
   virtual void UpdateGamepadData(device::GvrGamepadData) = 0;
-  virtual void ForceExitVr() = 0;
   virtual void ToggleCardboardGamepad(bool enabled) = 0;
-  virtual void ReportUiActivityResultForTesting(
-      const VrUiTestActivityResult& result) = 0;
 };
 
 }  // namespace vr
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h
index d75c729..858e9c4 100644
--- a/chrome/browser/android/vr/vr_gl_thread.h
+++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -69,8 +69,11 @@
   void DialogSurfaceCreated(jobject surface,
                             gl::SurfaceTexture* texture) override;
   void UpdateGamepadData(device::GvrGamepadData) override;
-  void ForceExitVr() override;
   void ToggleCardboardGamepad(bool enabled) override;
+  // RenderLoopBrowserInterface implementation (RenderLoop calling to VrShell).
+  void ForceExitVr() override;
+  void ReportUiActivityResultForTesting(
+      const VrUiTestActivityResult& result) override;
 
   // PlatformInputHandler
   void ForwardEventToPlatformUi(std::unique_ptr<InputEvent> event) override;
@@ -146,9 +149,6 @@
   void RemoveTab(int id, bool incognito) override;
   void RemoveAllTabs() override;
 
-  void ReportUiActivityResultForTesting(
-      const VrUiTestActivityResult& result) override;
-
  protected:
   void Init() override;
   void CleanUp() override;
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index ebd542c..b80e4e4e 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -533,9 +533,8 @@
 void VrShell::SetSurface(JNIEnv* env,
                          const JavaParamRef<jobject>& obj,
                          const JavaParamRef<jobject>& surface) {
-  CHECK(!reprojected_rendering_);
-  if (surface.is_null())
-    return;
+  DCHECK(!reprojected_rendering_);
+  DCHECK(!surface.is_null());
   gfx::AcceleratedWidget window =
       ANativeWindow_fromSurface(base::android::AttachCurrentThread(), surface);
   surface_window_ = window;
diff --git a/chrome/browser/android/vr/vr_shell_gl.cc b/chrome/browser/android/vr/vr_shell_gl.cc
index e49029b2..2a54400 100644
--- a/chrome/browser/android/vr/vr_shell_gl.cc
+++ b/chrome/browser/android/vr/vr_shell_gl.cc
@@ -4,9 +4,8 @@
 
 #include "chrome/browser/android/vr/vr_shell_gl.h"
 
-#include <algorithm>
 #include <limits>
-#include <utility>
+#include <string>
 
 #include "base/android/android_hardware_buffer_compat.h"
 #include "base/android/jni_android.h"
@@ -195,7 +194,7 @@
 
 }  // namespace
 
-VrShellGl::VrShellGl(GlBrowserInterface* browser_interface,
+VrShellGl::VrShellGl(GlBrowserInterface* browser,
                      std::unique_ptr<UiInterface> ui,
                      gvr_context* gvr_api,
                      bool reprojected_rendering,
@@ -203,7 +202,9 @@
                      bool start_in_web_vr_mode,
                      bool pause_content,
                      bool low_density)
-    : RenderLoop(std::move(ui)),
+    : RenderLoop(std::move(ui), browser, kWebVRSlidingAverageSize),
+      webvr_vsync_align_(
+          base::FeatureList::IsEnabled(features::kWebVrVsyncAlign)),
       low_density_(low_density),
       web_vr_mode_(start_in_web_vr_mode),
       surfaceless_rendering_(reprojected_rendering),
@@ -212,7 +213,7 @@
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       presentation_binding_(this),
       frame_data_binding_(this),
-      browser_(browser_interface),
+      browser_(browser),
       vr_ui_fps_meter_(),
       webvr_fps_meter_(),
       webvr_js_time_(kWebVRSlidingAverageSize),
@@ -220,8 +221,6 @@
       webvr_js_wait_time_(kWebVRSlidingAverageSize),
       webvr_acquire_time_(kWebVRSlidingAverageSize),
       webvr_submit_time_(kWebVRSlidingAverageSize),
-      ui_processing_time_(kWebVRSlidingAverageSize),
-      ui_controller_update_time_(kWebVRSlidingAverageSize),
       weak_ptr_factory_(this) {
   GvrInit(gvr_api);
   controller_delegate_ = std::make_unique<GvrControllerDelegate>(
@@ -230,8 +229,7 @@
 
 VrShellGl::~VrShellGl() {
   ClosePresentationBindings();
-  if (webxr_)
-    webxr_->EndPresentation();
+  webxr_.EndPresentation();
 }
 
 void VrShellGl::Initialize(
@@ -246,11 +244,6 @@
 }
 
 void VrShellGl::InitializeGl(gfx::AcceleratedWidget window) {
-  bool reinitializing = ready_to_draw_;
-
-  // We should only ever re-initialize when our surface is destroyed, which
-  // should only ever happen when drawing to a surface.
-  CHECK(!reinitializing || !surfaceless_rendering_);
   if (gl::GetGLImplementation() == gl::kGLImplementationNone &&
       !gl::init::InitializeGLOneOff()) {
     LOG(ERROR) << "gl::init::InitializeGLOneOff failed";
@@ -258,10 +251,10 @@
     return;
   }
   if (window) {
-    CHECK(!surfaceless_rendering_);
+    DCHECK(!surfaceless_rendering_);
     surface_ = gl::init::CreateViewGLSurface(window);
   } else {
-    CHECK(surfaceless_rendering_);
+    DCHECK(surfaceless_rendering_);
     surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
   }
   if (!surface_.get()) {
@@ -320,39 +313,24 @@
   content_overlay_surface_texture_->SetDefaultBufferSize(
       content_tex_buffer_size_.width(), content_tex_buffer_size_.height());
 
-  webvr_vsync_align_ = base::FeatureList::IsEnabled(features::kWebVrVsyncAlign);
-
   // InitializeRenderer calls GvrDelegateReady which triggers actions such as
   // responding to RequestPresent.
-  if (!reinitializing)
-    InitializeRenderer();
+  InitializeRenderer();
 
   ui_->OnGlInitialized(
       content_texture_id_, UiElementRenderer::kTextureLocationExternal,
       content_overlay_texture_id_, UiElementRenderer::kTextureLocationExternal,
       ui_texture_id);
-
-  webvr_vsync_align_ = base::FeatureList::IsEnabled(features::kWebVrVsyncAlign);
-
-  if (reinitializing && mailbox_bridge_) {
-    mailbox_bridge_ = nullptr;
-    webxr_->set_mailbox_bridge_ready(false);
-    CreateOrResizeWebVRSurface(webvr_surface_size_);
-  }
-
-  ready_to_draw_ = true;
-  if (!paused_ && !reinitializing)
-    OnVSync(base::TimeTicks::Now());
 }
 
 void VrShellGl::OnGpuProcessConnectionReady() {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(1) << __func__;
   CHECK(mailbox_bridge_);
 
-  webxr_->set_mailbox_bridge_ready(true);
+  webxr_.set_mailbox_bridge_ready(true);
   // We might have a deferred submit that was waiting for
   // mailbox_bridge_ready.
-  webxr_->TryDeferredProcessing();
+  webxr_.TryDeferredProcessing();
 
   // See if we can send a VSync.
   WebVrTryStartAnimatingFrame(false);
@@ -360,7 +338,7 @@
 
 void VrShellGl::CreateSurfaceBridge(gl::SurfaceTexture* surface_texture) {
   DCHECK(!mailbox_bridge_);
-  webxr_->set_mailbox_bridge_ready(false);
+  webxr_.set_mailbox_bridge_ready(false);
   mailbox_bridge_ = std::make_unique<MailboxToSurfaceBridge>();
   if (surface_texture) {
     mailbox_bridge_->CreateSurface(surface_texture);
@@ -370,7 +348,7 @@
 }
 
 void VrShellGl::CreateOrResizeWebVRSurface(const gfx::Size& size) {
-  DVLOG(2) << __FUNCTION__ << ": size=" << size.width() << "x" << size.height();
+  DVLOG(2) << __func__ << ": size=" << size.width() << "x" << size.height();
   if (!webvr_surface_texture_) {
     if (webxr_use_shared_buffer_draw_) {
       // We don't have a surface in SharedBuffer mode, just update the size.
@@ -406,7 +384,7 @@
 
 void VrShellGl::WebVrCreateOrResizeSharedBufferImage(WebXrSharedBuffer* buffer,
                                                      const gfx::Size& size) {
-  TRACE_EVENT0("gpu", __FUNCTION__);
+  TRACE_EVENT0("gpu", __func__);
   // Unbind previous image (if any).
   if (buffer->remote_image) {
     DVLOG(2) << ": UnbindSharedBuffer, remote_image=" << buffer->remote_image;
@@ -415,7 +393,7 @@
     buffer->remote_image = 0;
   }
 
-  DVLOG(2) << __FUNCTION__ << ": width=" << size.width()
+  DVLOG(2) << __func__ << ": width=" << size.width()
            << " height=" << size.height();
   // Remove reference to previous image (if any).
   buffer->local_glimage = nullptr;
@@ -423,7 +401,7 @@
   const gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888;
   const gfx::BufferUsage usage = gfx::BufferUsage::SCANOUT;
 
-  gfx::GpuMemoryBufferId kBufferId(webxr_->next_memory_buffer_id++);
+  gfx::GpuMemoryBufferId kBufferId(webxr_.next_memory_buffer_id++);
   buffer->gmb = gpu::GpuMemoryBufferImplAndroidHardwareBuffer::Create(
       kBufferId, size, format, usage,
       gpu::GpuMemoryBufferImpl::DestructionCallback());
@@ -439,7 +417,7 @@
       buffer->gmb->CloneHandle().android_hardware_buffer;
   bool ret = img->Initialize(ahb.get(), false /* preserved */);
   if (!ret) {
-    DLOG(WARNING) << __FUNCTION__ << ": ERROR: failed to initialize image!";
+    DLOG(WARNING) << __func__ << ": ERROR: failed to initialize image!";
     // Exiting VR is a bit drastic, but this error shouldn't occur under normal
     // operation. If it's an issue in practice, look into other recovery
     // options such as shutting down the WebVR/WebXR presentation session.
@@ -452,21 +430,21 @@
 }
 
 void VrShellGl::WebVrPrepareSharedBuffer(const gfx::Size& size) {
-  TRACE_EVENT0("gpu", __FUNCTION__);
+  TRACE_EVENT0("gpu", __func__);
 
-  DVLOG(2) << __FUNCTION__ << ": size=" << size.width() << "x" << size.height();
-  CHECK(webxr_->mailbox_bridge_ready());
-  CHECK(webxr_->HaveAnimatingFrame());
+  DVLOG(2) << __func__ << ": size=" << size.width() << "x" << size.height();
+  CHECK(webxr_.mailbox_bridge_ready());
+  CHECK(webxr_.HaveAnimatingFrame());
 
   WebXrSharedBuffer* buffer;
-  if (webxr_->GetAnimatingFrame()->shared_buffer) {
-    buffer = webxr_->GetAnimatingFrame()->shared_buffer.get();
+  if (webxr_.GetAnimatingFrame()->shared_buffer) {
+    buffer = webxr_.GetAnimatingFrame()->shared_buffer.get();
   } else {
     // Create buffer and do one-time setup for resources that stay valid after
     // size changes.
-    webxr_->GetAnimatingFrame()->shared_buffer =
+    webxr_.GetAnimatingFrame()->shared_buffer =
         std::make_unique<WebXrSharedBuffer>();
-    buffer = webxr_->GetAnimatingFrame()->shared_buffer.get();
+    buffer = webxr_.GetAnimatingFrame()->shared_buffer.get();
 
     // Remote resources
     buffer->mailbox_holder = std::make_unique<gpu::MailboxHolder>();
@@ -496,13 +474,13 @@
 void VrShellGl::OnWebVRTokenSignaled(int16_t frame_index,
                                      std::unique_ptr<gfx::GpuFence> gpu_fence) {
   TRACE_EVENT1("gpu", "VrShellGl::OnWebVRTokenSignaled", "frame", frame_index);
-  DVLOG(2) << __FUNCTION__ << ": frame=" << frame_index;
+  DVLOG(2) << __func__ << ": frame=" << frame_index;
 
   // Ignore if not processing a frame. This can happen on exiting presentation.
-  if (!webxr_->HaveProcessingFrame())
+  if (!webxr_.HaveProcessingFrame())
     return;
 
-  webxr_->GetProcessingFrame()->gvr_handoff_fence =
+  webxr_.GetProcessingFrame()->gvr_handoff_fence =
       gl::GLFence::CreateFromGpuFence(*gpu_fence);
 
   base::TimeTicks now = base::TimeTicks::Now();
@@ -516,13 +494,13 @@
   // OnSubmitFrameTransferred or OnSubmitFrameRendered. Similarly,
   // the animating frame state is cleared when exiting presentation,
   // and we should ignore a leftover queued SubmitFrame.
-  if (!submit_client_.get() || !webxr_->HaveAnimatingFrame())
+  if (!submit_client_.get() || !webxr_.HaveAnimatingFrame())
     return false;
 
-  WebXrFrame* animating_frame = webxr_->GetAnimatingFrame();
+  WebXrFrame* animating_frame = webxr_.GetAnimatingFrame();
 
   if (animating_frame->index != frame_index) {
-    DVLOG(1) << __FUNCTION__ << ": wrong frame index, got " << frame_index
+    DVLOG(1) << __func__ << ": wrong frame index, got " << frame_index
              << ", expected " << animating_frame->index;
     mojo::ReportBadMessage("SubmitFrame called with wrong frame index");
     presentation_binding_.Close();
@@ -544,25 +522,25 @@
   // Renderer didn't submit a frame. Wait for the sync token to ensure
   // that any mailbox_bridge_ operations for the next frame happen after
   // whatever drawing the Renderer may have done before exiting.
-  if (webxr_->mailbox_bridge_ready())
+  if (webxr_.mailbox_bridge_ready())
     mailbox_bridge_->WaitSyncToken(sync_token);
 
-  DVLOG(2) << __FUNCTION__ << ": recycle unused animating frame";
-  DCHECK(webxr_->HaveAnimatingFrame());
-  webxr_->RecycleUnusedAnimatingFrame();
+  DVLOG(2) << __func__ << ": recycle unused animating frame";
+  DCHECK(webxr_.HaveAnimatingFrame());
+  webxr_.RecycleUnusedAnimatingFrame();
 }
 
 bool VrShellGl::SubmitFrameCommon(int16_t frame_index,
                                   base::TimeDelta time_waited) {
   TRACE_EVENT1("gpu", "VrShellGl::SubmitWebVRFrame", "frame", frame_index);
-  DVLOG(2) << __FUNCTION__ << ": frame=" << frame_index;
+  DVLOG(2) << __func__ << ": frame=" << frame_index;
 
   if (!IsSubmitFrameExpected(frame_index))
     return false;
 
   // If we get here, treat as a valid submit.
-  DCHECK(webxr_->HaveAnimatingFrame());
-  WebXrFrame* animating_frame = webxr_->GetAnimatingFrame();
+  DCHECK(webxr_.HaveAnimatingFrame());
+  WebXrFrame* animating_frame = webxr_.GetAnimatingFrame();
 
   animating_frame->time_js_submit = base::TimeTicks::Now();
 
@@ -597,14 +575,14 @@
   if (!SubmitFrameCommon(frame_index, time_waited))
     return;
 
-  webxr_->ProcessOrDefer(base::BindOnce(&VrShellGl::ProcessWebVrFrameFromGMB,
-                                        weak_ptr_factory_.GetWeakPtr(),
-                                        frame_index, sync_token));
+  webxr_.ProcessOrDefer(base::BindOnce(&VrShellGl::ProcessWebVrFrameFromGMB,
+                                       weak_ptr_factory_.GetWeakPtr(),
+                                       frame_index, sync_token));
 }
 
 void VrShellGl::ProcessWebVrFrameFromGMB(int16_t frame_index,
                                          const gpu::SyncToken& sync_token) {
-  TRACE_EVENT0("gpu", __FUNCTION__);
+  TRACE_EVENT0("gpu", __func__);
 
   mailbox_bridge_->CreateGpuFence(
       sync_token, base::BindOnce(&VrShellGl::OnWebVRTokenSignaled,
@@ -621,15 +599,15 @@
   if (!SubmitFrameCommon(frame_index, time_waited))
     return;
 
-  webxr_->ProcessOrDefer(
-      base::BindOnce(&VrShellGl::ProcessWebVrFrameFromMailbox,
-                     weak_ptr_factory_.GetWeakPtr(), frame_index, mailbox));
+  webxr_.ProcessOrDefer(base::BindOnce(&VrShellGl::ProcessWebVrFrameFromMailbox,
+                                       weak_ptr_factory_.GetWeakPtr(),
+                                       frame_index, mailbox));
 }
 
 void VrShellGl::ProcessWebVrFrameFromMailbox(
     int16_t frame_index,
     const gpu::MailboxHolder& mailbox) {
-  TRACE_EVENT0("gpu", __FUNCTION__);
+  TRACE_EVENT0("gpu", __func__);
 
   // LIFECYCLE: pending_frames_ should be empty when there's no processing
   // frame. It gets one element here, and then is emptied again before leaving
@@ -639,12 +617,12 @@
   DCHECK(pending_frames_.empty());
 
   // LIFECYCLE: We shouldn't have gotten here unless mailbox_bridge_ is ready.
-  DCHECK(webxr_->mailbox_bridge_ready());
+  DCHECK(webxr_.mailbox_bridge_ready());
 
   // Don't allow any state changes for this processing frame until it
   // arrives on the Surface. See OnWebVRFrameAvailable.
-  DCHECK(webxr_->HaveProcessingFrame());
-  webxr_->GetProcessingFrame()->state_locked = true;
+  DCHECK(webxr_.HaveProcessingFrame());
+  webxr_.GetProcessingFrame()->state_locked = true;
 
   bool swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox);
   DCHECK(swapped);
@@ -683,8 +661,8 @@
   gfx::Size webvr_size(
       display_info->leftEye->renderWidth + display_info->rightEye->renderWidth,
       display_info->leftEye->renderHeight);
-  DVLOG(1) << __FUNCTION__ << ": resize initial to " << webvr_size.width()
-           << "x" << webvr_size.height();
+  DVLOG(1) << __func__ << ": resize initial to " << webvr_size.width() << "x"
+           << webvr_size.height();
 
   // Decide which transport mechanism we want to use. This sets
   // the webxr_use_* options as a side effect.
@@ -795,7 +773,6 @@
   if (content_paused_)
     return;
   content_surface_texture_->UpdateTexImage();
-  content_frame_available_ = true;
 }
 
 void VrShellGl::OnContentOverlayFrameAvailable() {
@@ -833,8 +810,8 @@
       &webvr_surface_texture_uv_transform_[0]);
 
   // LIFECYCLE: we should be in processing state.
-  DCHECK(webxr_->HaveProcessingFrame());
-  WebXrFrame* processing_frame = webxr_->GetProcessingFrame();
+  DCHECK(webxr_.HaveProcessingFrame());
+  WebXrFrame* processing_frame = webxr_.GetProcessingFrame();
 
   // Frame should be locked. Unlock it.
   DCHECK(processing_frame->state_locked);
@@ -847,11 +824,11 @@
     // Silently consume a frame if we don't want to draw it. This can happen
     // due to an active exclusive UI such as a permission prompt, or after
     // exiting a presentation session when a pending frame arrives late.
-    DVLOG(1) << __FUNCTION__ << ": discarding frame, "
+    DVLOG(1) << __func__ << ": discarding frame, "
              << (web_vr_mode_ ? "UI is active" : "not presenting");
     WebVrCancelProcessingFrameAfterTransfer();
     // We're no longer in processing state, unblock pending processing frames.
-    webxr_->TryDeferredProcessing();
+    webxr_.TryDeferredProcessing();
   }
 }
 
@@ -916,7 +893,7 @@
 device::mojom::XRPresentationTransportOptionsPtr
 VrShellGl::GetWebVrFrameTransportOptions(
     const device::mojom::XRRuntimeSessionOptionsPtr& options) {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(1) << __func__;
 
   MetricsUtilAndroid::XRRenderPath render_path =
       MetricsUtilAndroid::XRRenderPath::kClientWait;
@@ -925,7 +902,7 @@
 
   std::string render_path_string = base::GetFieldTrialParamValueByFeature(
       features::kWebXrRenderPath, features::kWebXrRenderPathParamName);
-  DVLOG(1) << __FUNCTION__ << ": WebXrRenderPath=" << render_path_string;
+  DVLOG(1) << __func__ << ": WebXrRenderPath=" << render_path_string;
   if (render_path_string == features::kWebXrRenderPathParamValueClientWait) {
     // Use the baseline kClientWait.
   } else if (render_path_string ==
@@ -953,7 +930,7 @@
       }
     }
   }
-  DVLOG(1) << __FUNCTION__ << ": render_path=" << static_cast<int>(render_path);
+  DVLOG(1) << __func__ << ": render_path=" << static_cast<int>(render_path);
   MetricsUtilAndroid::LogXrRenderPathUsed(render_path);
 
   device::mojom::XRPresentationTransportOptionsPtr transport_options =
@@ -983,7 +960,6 @@
   gvr_api_->InitializeGl();
   gfx::Transform head_pose;
   device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
-  webxr_ = std::make_unique<WebXrPresentationState>();
 
   // Create multisampled and non-multisampled buffers.
   specs_.push_back(gvr_api_->CreateBufferSpec());
@@ -1084,7 +1060,7 @@
     webvr_viewport_.right.SetSourceUv(UVFromGfxRect(bounds.right_bounds));
     current_webvr_frame_bounds_ =
         bounds;  // If we recreate the viewports, keep these bounds.
-    DVLOG(1) << __FUNCTION__ << ": resize from pending_bounds to "
+    DVLOG(1) << __func__ << ": resize from pending_bounds to "
              << bounds.source_size.width() << "x"
              << bounds.source_size.height();
     CreateOrResizeWebVRSurface(bounds.source_size);
@@ -1186,11 +1162,11 @@
     // We're in a WebVR session, but don't want to draw WebVR frames, i.e.
     // because UI has taken over for a permissions prompt. Do state cleanup if
     // needed.
-    if (webxr_->HaveAnimatingFrame() &&
-        webxr_->GetAnimatingFrame()->deferred_start_processing) {
+    if (webxr_.HaveAnimatingFrame() &&
+        webxr_.GetAnimatingFrame()->deferred_start_processing) {
       // We have an animating frame. Cancel it if it's waiting to start
       // processing. If not, keep it to receive the incoming SubmitFrame.
-      DVLOG(1) << __FUNCTION__ << ": cancel waiting WebVR frame, UI is active";
+      DVLOG(1) << __func__ << ": cancel waiting WebVR frame, UI is active";
       WebVrCancelAnimatingFrame();
     }
   }
@@ -1204,8 +1180,8 @@
   // OnWebVRTokenSignaled. In that case we continue handling the current frame
   // as a WebVR frame. Also, WebVR frames can still have overlay UI drawn on top
   // of them.
-  bool is_webvr_frame = frame_index >= 0;
-  DCHECK(!is_webvr_frame || webxr_->HaveProcessingFrame());
+  bool is_webxr_frame = frame_index >= 0;
+  DCHECK(!is_webxr_frame || webxr_.HaveProcessingFrame());
   CHECK(!acquired_frame_);
 
   // When using async reprojection, we need to know which pose was
@@ -1213,58 +1189,21 @@
   // submitting. Technically we don't need a pose if not reprojecting,
   // but keeping it uninitialized seems likely to cause problems down
   // the road. Copying it is cheaper than fetching a new one.
-  if (is_webvr_frame) {
+  if (is_webxr_frame) {
     // Copy into render info for overlay UI. WebVR doesn't use this.
-    DCHECK(webxr_->HaveProcessingFrame());
-    WebXrFrame* frame = webxr_->GetProcessingFrame();
+    DCHECK(webxr_.HaveProcessingFrame());
+    WebXrFrame* frame = webxr_.GetProcessingFrame();
     render_info_.head_pose = frame->head_pose;
   } else {
     device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(),
                                                  &render_info_.head_pose);
   }
 
-  // Update the render position of all UI elements (including desktop).
-  TRACE_EVENT_BEGIN0("gpu", "SceneUpdate");
-  base::TimeTicks scene_start = base::TimeTicks::Now();
-  bool ui_updated = ui_->OnBeginFrame(current_time, render_info_.head_pose);
-
-  // WebVR handles controller input in OnVsync.
-  base::TimeDelta controller_time = base::TimeDelta();
-  if (!is_webvr_frame) {
-    TRACE_EVENT0("gpu", "Controller");
-    base::TimeTicks controller_start = base::TimeTicks::Now();
-    ProcessControllerInput(render_info_, current_time,
-                           false /* is_web_xr_frame */);
-    controller_time = base::TimeTicks::Now() - controller_start;
-    ui_controller_update_time_.AddSample(controller_time);
-  }
-
-  if (ui_->SceneHasDirtyTextures()) {
-    if (!graphics_delegate_->MakeSkiaContextCurrent()) {
-      ForceExitVr();
-      return;
-    }
-    ui_->UpdateSceneTextures();
-    if (!graphics_delegate_->MakeMainContextCurrent()) {
-      ForceExitVr();
-      return;
-    }
-    ui_updated = true;
-  }
-
-  ui_updated |= content_frame_available_;
-  ReportUiStatusForTesting(scene_start, ui_updated);
-
-  base::TimeDelta scene_time = base::TimeTicks::Now() - scene_start;
-  // Don't double-count the controller time that was part of the scene time.
-  ui_processing_time_.AddSample(scene_time - controller_time);
-  TRACE_EVENT_END0("gpu", "SceneUpdate");
-
   UpdateViewports();
 
   // If needed, resize the primary buffer for use with WebVR. Resizing
   // needs to happen before acquiring a frame.
-  if (is_webvr_frame) {
+  if (is_webxr_frame) {
     if (!ResizeForWebVR(frame_index)) {
       // We don't have a valid size yet, can't draw.
       return;
@@ -1303,11 +1242,13 @@
   TRACE_EVENT1("gpu", "VrShellGl::DrawIntoAcquiredFrame", "frame", frame_index);
   last_used_head_pose_ = render_info_.head_pose;
 
-  bool is_webvr_frame = frame_index >= 0;
-  DCHECK(!is_webvr_frame || webxr_->HaveProcessingFrame());
+  bool is_webxr_frame = frame_index >= 0;
+  DCHECK(!is_webxr_frame || webxr_.HaveProcessingFrame());
+
+  UpdateUi(render_info_, current_time, is_webxr_frame ? kWebXrFrame : kUiFrame);
 
   gvr::Sizei primary_render_size =
-      is_webvr_frame ? swap_chain_.GetBufferSize(kNoMultiSampleBuffer)
+      is_webxr_frame ? swap_chain_.GetBufferSize(kNoMultiSampleBuffer)
                      : swap_chain_.GetBufferSize(kMultiSampleBuffer);
   UpdateEyeInfos(render_info_.head_pose, main_viewport_,
                  {primary_render_size.width, primary_render_size.height},
@@ -1320,7 +1261,7 @@
 
   // We can't use webvr and the quad layer at the same time because they
   // currently share the same non-multisampled buffer.
-  DCHECK(!is_webvr_frame || !use_quad_layer);
+  DCHECK(!is_webxr_frame || !use_quad_layer);
 
   viewport_list_ = gvr_api_->CreateEmptyBufferViewportList();
 
@@ -1329,7 +1270,7 @@
     // This should be the first layer as it needs to be rendered behind the
     // rest of the browser UI, which punches a transparent hole through to this
     // layer.
-    DCHECK(viewport_list_.GetSize() == 0);
+    DCHECK_EQ(viewport_list_.GetSize(), 0U);
 
     UpdateContentViewportTransforms(render_info_.head_pose);
 
@@ -1348,8 +1289,8 @@
     acquired_frame_.Unbind();
   }
 
-  if (is_webvr_frame) {
-    DCHECK(viewport_list_.GetSize() == 0);
+  if (is_webxr_frame) {
+    DCHECK_EQ(viewport_list_.GetSize(), 0U);
     viewport_list_.SetBufferViewport(0, webvr_viewport_.left);
     viewport_list_.SetBufferViewport(1, webvr_viewport_.right);
     acquired_frame_.BindBuffer(kNoMultiSampleBuffer);
@@ -1363,7 +1304,7 @@
     DrawWebVr();
     acquired_frame_.Unbind();
   } else {
-    DCHECK(viewport_list_.GetSize() <= 2);
+    DCHECK_LE(viewport_list_.GetSize(), 2U);
     viewport_list_.SetBufferViewport(viewport_list_.GetSize(),
                                      main_viewport_.left);
     viewport_list_.SetBufferViewport(viewport_list_.GetSize(),
@@ -1379,16 +1320,14 @@
     acquired_frame_.Unbind();
   }
 
-  content_frame_available_ = false;
-
   std::vector<const UiElement*> overlay_elements;
-  if (is_webvr_frame) {
+  if (is_webxr_frame) {
     overlay_elements = ui_->GetWebVrOverlayElementsToDraw();
   }
 
   TRACE_COUNTER1("gpu", "VR overlay element count", overlay_elements.size());
 
-  if (!overlay_elements.empty() && is_webvr_frame) {
+  if (!overlay_elements.empty() && is_webxr_frame) {
     // WebVR content may use an arbitrary size buffer. We need to draw browser
     // UI on a different buffer to make sure that our UI has enough resolution.
     acquired_frame_.BindBuffer(kMultiSampleBuffer);
@@ -1413,7 +1352,7 @@
         render_info_webvr_browser_ui.right_eye_model.view_matrix,
         overlay_elements, fov_recommended_right, kZNear, ui_.get()));
 
-    DCHECK(viewport_list_.GetSize() == 2);
+    DCHECK_EQ(viewport_list_.GetSize(), 2U);
     viewport_list_.SetBufferViewport(2, webvr_overlay_viewport_.left);
     viewport_list_.SetBufferViewport(3, webvr_overlay_viewport_.right);
     UpdateEyeInfos(render_info_webvr_browser_ui.head_pose,
@@ -1427,17 +1366,17 @@
 
   // GVR submit needs the exact head pose that was used for rendering.
   gfx::Transform submit_head_pose;
-  if (is_webvr_frame) {
+  if (is_webxr_frame) {
     // Don't use render_info_.head_pose here, that may have been
     // overwritten by OnVSync's controller handling. We need the pose that was
     // sent to JS.
-    submit_head_pose = webxr_->GetProcessingFrame()->head_pose;
+    submit_head_pose = webxr_.GetProcessingFrame()->head_pose;
   } else {
     submit_head_pose = render_info_.head_pose;
   }
   std::unique_ptr<gl::GLFenceEGL> fence = nullptr;
-  if (is_webvr_frame && surfaceless_rendering_) {
-    webxr_->GetProcessingFrame()->time_copied = base::TimeTicks::Now();
+  if (is_webxr_frame && surfaceless_rendering_) {
+    webxr_.GetProcessingFrame()->time_copied = base::TimeTicks::Now();
     if (webxr_use_gpu_fence_) {
       // Continue with submit once the previous frame's GL fence signals that
       // it is done rendering. This avoids blocking in GVR's Submit. Fence is
@@ -1473,10 +1412,10 @@
 }
 
 void VrShellGl::WebVrWaitForServerFence() {
-  DCHECK(webxr_->HaveProcessingFrame());
+  DCHECK(webxr_.HaveProcessingFrame());
 
   std::unique_ptr<gl::GLFence> gpu_fence(
-      webxr_->GetProcessingFrame()->gvr_handoff_fence.release());
+      webxr_.GetProcessingFrame()->gvr_handoff_fence.release());
 
   DCHECK(gpu_fence);
   // IMPORTANT: wait as late as possible to insert the server wait. Doing so
@@ -1495,8 +1434,8 @@
     std::unique_ptr<gl::GLFenceEGL> fence) {
   TRACE_EVENT1("gpu", "VrShellGl::DrawFrameSubmitWhenReady", "frame",
                frame_index);
-  DVLOG(2) << __FUNCTION__ << ": frame=" << static_cast<int>(frame_index);
-  bool use_polling = webxr_->mailbox_bridge_ready() &&
+  DVLOG(2) << __func__ << ": frame=" << static_cast<int>(frame_index);
+  bool use_polling = webxr_.mailbox_bridge_ready() &&
                      mailbox_bridge_->IsGpuWorkaroundEnabled(
                          gpu::DONT_USE_EGLCLIENTWAITSYNC_WITH_TIMEOUT);
   if (fence) {
@@ -1542,10 +1481,10 @@
 void VrShellGl::AddWebVrRenderTimeEstimate(
     int16_t frame_index,
     const base::TimeTicks& fence_complete_time) {
-  if (!webxr_->HaveRenderingFrame())
+  if (!webxr_.HaveRenderingFrame())
     return;
 
-  WebXrFrame* rendering_frame = webxr_->GetRenderingFrame();
+  WebXrFrame* rendering_frame = webxr_.GetRenderingFrame();
   base::TimeTicks prev_js_submit = rendering_frame->time_js_submit;
   if (webxr_use_gpu_fence_ && !prev_js_submit.is_null() &&
       !fence_complete_time.is_null()) {
@@ -1557,7 +1496,7 @@
   if (!submit_client_)
     return;
 
-  TRACE_EVENT0("gpu", __FUNCTION__);
+  TRACE_EVENT0("gpu", __func__);
   if (webxr_use_gpu_fence_) {
     // Renderer is waiting for a frame-separating GpuFence.
 
@@ -1584,10 +1523,10 @@
 
   gvr::Mat4f mat;
   TransformToGvrMat(head_pose, &mat);
-  bool is_webvr_frame = frame_index >= 0;
+  bool is_webxr_frame = frame_index >= 0;
   {
     std::unique_ptr<ScopedGpuTrace> browser_gpu_trace;
-    if (gl::GLFence::IsGpuFenceSupported() && !is_webvr_frame) {
+    if (gl::GLFence::IsGpuFenceSupported() && !is_webxr_frame) {
       // This fence instance is created for the tracing side effect. Insert it
       // before GVR submit. Then replace the previous instance below after GVR
       // submit completes, at which point the previous fence (if any) should be
@@ -1624,16 +1563,16 @@
   // false for a WebVR frame. Ignore the ShouldDrawWebVr status to ensure we
   // send render notifications while paused for exclusive UI mode. Skip the
   // steps if we lost the processing state, that means presentation has ended.
-  if (is_webvr_frame && webxr_->HaveProcessingFrame()) {
+  if (is_webxr_frame && webxr_.HaveProcessingFrame()) {
     // Report rendering completion to the Renderer so that it's permitted to
     // submit a fresh frame. We could do this earlier, as soon as the frame
     // got pulled off the transfer surface, but that results in overstuffed
     // buffers.
     WebVrSendRenderNotification(true);
 
-    base::TimeTicks pose_time = webxr_->GetProcessingFrame()->time_pose;
+    base::TimeTicks pose_time = webxr_.GetProcessingFrame()->time_pose;
     base::TimeTicks js_submit_time =
-        webxr_->GetProcessingFrame()->time_js_submit;
+        webxr_.GetProcessingFrame()->time_js_submit;
     webvr_js_time_.AddSample(js_submit_time - pose_time);
     if (!webxr_use_gpu_fence_) {
       // Estimate render time from wallclock time, we waited for the pre-submit
@@ -1642,10 +1581,10 @@
       webvr_render_time_.AddSample(now - js_submit_time);
     }
 
-    if (webxr_->HaveRenderingFrame()) {
-      webxr_->EndFrameRendering();
+    if (webxr_.HaveRenderingFrame()) {
+      webxr_.EndFrameRendering();
     }
-    webxr_->TransitionFrameProcessingToRendering();
+    webxr_.TransitionFrameProcessingToRendering();
   }
 
   // After saving the timestamp, fps will be available via GetFPS().
@@ -1654,14 +1593,14 @@
   DVLOG(1) << "fps: " << vr_ui_fps_meter_.GetFPS();
   TRACE_COUNTER1("gpu", "VR UI FPS", vr_ui_fps_meter_.GetFPS());
   TRACE_COUNTER2("gpu", "VR UI timing (us)", "scene update",
-                 ui_processing_time_.GetAverage().InMicroseconds(),
+                 ui_processing_time().GetAverage().InMicroseconds(),
                  "controller",
-                 ui_controller_update_time_.GetAverage().InMicroseconds());
+                 ui_controller_update_time().GetAverage().InMicroseconds());
 
-  if (is_webvr_frame) {
+  if (is_webxr_frame) {
     // We finished processing a frame, this may make pending WebVR
     // work eligible to proceed.
-    webxr_->TryDeferredProcessing();
+    webxr_.TryDeferredProcessing();
   }
 
   if (ShouldDrawWebVr()) {
@@ -1688,9 +1627,9 @@
 
   if (webxr_use_shared_buffer_draw_) {
     WebVrWaitForServerFence();
-    CHECK(webxr_->HaveProcessingFrame());
+    CHECK(webxr_.HaveProcessingFrame());
     WebXrSharedBuffer* buffer =
-        webxr_->GetProcessingFrame()->shared_buffer.get();
+        webxr_.GetProcessingFrame()->shared_buffer.get();
     CHECK(buffer);
 
     // Use an identity UV transform, the image is already oriented correctly.
@@ -1731,7 +1670,6 @@
 }
 
 void VrShellGl::OnPause() {
-  paused_ = true;
   vsync_helper_.CancelVSyncRequest();
   controller_delegate_->OnPause();
   ui_->OnPause();
@@ -1741,13 +1679,11 @@
 }
 
 void VrShellGl::OnResume() {
-  paused_ = false;
   gvr_api_->RefreshViewerProfile();
   viewports_need_updating_ = true;
   gvr_api_->ResumeTracking();
   controller_delegate_->OnResume();
-  if (!ready_to_draw_)
-    return;
+
   vsync_helper_.CancelVSyncRequest();
   OnVSync(base::TimeTicks::Now());
   if (web_vr_mode_)
@@ -1778,15 +1714,9 @@
     // an outstanding animating frame (if any).
     ClosePresentationBindings();
 
-    // In not-surfaceless mode, webxr_ may not be initialized yet at the time
-    // we get an incoming SetWebVrMode(false) call. In that case, skip the
-    // remaining steps.
-    if (!webxr_)
-      return;
-
     // Ensure that re-entering VR later gets a fresh start by clearing out the
     // current session's animating frame state.
-    webxr_->EndPresentation();
+    webxr_.EndPresentation();
     // Do not clear pending_frames_ here, need to track Surface state across
     // sessions.
     if (!pending_frames_.empty()) {
@@ -1794,9 +1724,10 @@
       // the Surface, and that will clear webvr_frame_processing_ once it's
       // done. Until then, webvr_frame_processing_ will stay true to block a
       // new session from starting processing.
-      DCHECK(webxr_->HaveProcessingFrame());
-      DCHECK(webxr_->GetProcessingFrame()->state_locked);
-      DCHECK(webxr_->GetProcessingFrame()->recycle_once_unlocked);
+      // TODO(acondor): Move these DCHECKs into a unittest.
+      DCHECK(webxr_.HaveProcessingFrame());
+      DCHECK(webxr_.GetProcessingFrame()->state_locked);
+      DCHECK(webxr_.GetProcessingFrame()->recycle_once_unlocked);
     }
   }
 }
@@ -1823,14 +1754,14 @@
   // This check needs to be first to ensure that we start the WebVR
   // first-frame timeout on presentation start.
   bool can_send_webvr_vsync = ui_->CanSendWebVrVSync();
-  if (!webxr_->last_ui_allows_sending_vsync && can_send_webvr_vsync) {
+  if (!webxr_.last_ui_allows_sending_vsync && can_send_webvr_vsync) {
     // We will start sending vsync to the WebVR page, so schedule the incoming
     // frame timeout.
     ScheduleOrCancelWebVrFrameTimeout();
   }
-  webxr_->last_ui_allows_sending_vsync = can_send_webvr_vsync;
+  webxr_.last_ui_allows_sending_vsync = can_send_webvr_vsync;
   if (!can_send_webvr_vsync) {
-    DVLOG(2) << __FUNCTION__ << ": waiting for can_send_webvr_vsync";
+    DVLOG(2) << __func__ << ": waiting for can_send_webvr_vsync";
     return false;
   }
 
@@ -1840,39 +1771,39 @@
   // use vsync aligned frames, and there's a flag to disable it for surfaceless
   // mode.
   if (surfaceless_rendering_ && webvr_vsync_align_ && !is_from_onvsync) {
-    DVLOG(3) << __FUNCTION__ << ": waiting for onvsync (vsync aligned)";
+    DVLOG(3) << __func__ << ": waiting for onvsync (vsync aligned)";
     return false;
   }
 
   if (!web_vr_mode_) {
-    DVLOG(2) << __FUNCTION__ << ": no active session, ignore";
+    DVLOG(2) << __func__ << ": no active session, ignore";
     return false;
   }
 
   if (get_frame_data_callback_.is_null()) {
-    DVLOG(2) << __FUNCTION__ << ": waiting for get_frame_data_callback_";
+    DVLOG(2) << __func__ << ": waiting for get_frame_data_callback_";
     return false;
   }
 
   if (!pending_vsync_) {
-    DVLOG(2) << __FUNCTION__ << ": waiting for pending_vsync (too fast)";
+    DVLOG(2) << __func__ << ": waiting for pending_vsync (too fast)";
     return false;
   }
 
   // If we already have a JS frame that's animating, don't send another one.
   // This check depends on the Renderer calling either SubmitFrame or
   // SubmitFrameMissing for each animated frame.
-  if (webxr_->HaveAnimatingFrame()) {
-    DVLOG(2) << __FUNCTION__
+  if (webxr_.HaveAnimatingFrame()) {
+    DVLOG(2) << __func__
              << ": waiting for current animating frame to start processing";
     return false;
   }
 
-  if (webxr_use_shared_buffer_draw_ && !webxr_->mailbox_bridge_ready()) {
+  if (webxr_use_shared_buffer_draw_ && !webxr_.mailbox_bridge_ready()) {
     // For exclusive scheduling, we need the mailbox bridge before the first
     // frame so that we can place a sync token. For shared buffer draw, we
     // need it to set up buffers before starting client rendering.
-    DVLOG(2) << __FUNCTION__ << ": waiting for mailbox_bridge_ready";
+    DVLOG(2) << __func__ << ": waiting for mailbox_bridge_ready";
     return false;
   }
 
@@ -1880,7 +1811,7 @@
       !(webvr_surface_size_.width() && webvr_surface_size_.height())) {
     // For shared buffer draw, wait for a nonzero size before creating
     // the shared buffer for use as a drawing destination.
-    DVLOG(2) << __FUNCTION__ << ": waiting for nonzero size";
+    DVLOG(2) << __func__ << ": waiting for nonzero size";
     return false;
   }
 
@@ -1893,13 +1824,13 @@
   TRACE_COUNTER2("gpu", "WebVR frame skip", "still rendering", still_rendering,
                  "overstuffed", overstuffed);
   if (still_rendering || overstuffed) {
-    DVLOG(2) << __FUNCTION__ << ": waiting for backlogged frames,"
+    DVLOG(2) << __func__ << ": waiting for backlogged frames,"
              << " still_rendering=" << still_rendering
              << " overstuffed=" << overstuffed;
     return false;
   }
 
-  DVLOG(2) << __FUNCTION__ << ": ready to animate frame";
+  DVLOG(2) << __func__ << ": ready to animate frame";
   return true;
 }
 
@@ -1910,8 +1841,8 @@
 }
 
 void VrShellGl::WebVrCancelAnimatingFrame() {
-  DVLOG(2) << __FUNCTION__;
-  webxr_->RecycleUnusedAnimatingFrame();
+  DVLOG(2) << __func__;
+  webxr_.RecycleUnusedAnimatingFrame();
   if (submit_client_) {
     // We haven't written to the Surface yet. Mark as transferred and rendered.
     submit_client_->OnSubmitFrameTransferred(true);
@@ -1920,9 +1851,9 @@
 }
 
 void VrShellGl::WebVrCancelProcessingFrameAfterTransfer() {
-  DVLOG(2) << __FUNCTION__;
-  DCHECK(webxr_->HaveProcessingFrame());
-  bool did_recycle = webxr_->RecycleProcessingFrameIfPossible();
+  DVLOG(2) << __func__;
+  DCHECK(webxr_.HaveProcessingFrame());
+  bool did_recycle = webxr_.RecycleProcessingFrameIfPossible();
   DCHECK(did_recycle);
   if (submit_client_) {
     // We've already sent the transferred notification.
@@ -1959,16 +1890,10 @@
     // rendering as WebVR uses the gamepad api. To ensure we always handle input
     // like app button presses, update the controller here, but not in
     // DrawFrame.
-    TRACE_EVENT0("gpu", "Controller");
-    base::TimeTicks controller_start = base::TimeTicks::Now();
     device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(),
                                                  &render_info_.head_pose);
-    ProcessControllerInput(render_info_, frame_time, true /* is_webxr_frame */);
-
+    ProcessControllerInput(render_info_, frame_time, kWebXrFrame);
     input_states_.push_back(controller_delegate_->GetInputSourceState());
-
-    ui_controller_update_time_.AddSample(base::TimeTicks::Now() -
-                                         controller_start);
   } else {
     DrawFrame(-1, frame_time);
   }
@@ -1976,7 +1901,7 @@
 
 void VrShellGl::GetFrameData(
     device::mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
-  TRACE_EVENT0("gpu", __FUNCTION__);
+  TRACE_EVENT0("gpu", __func__);
   if (!get_frame_data_callback_.is_null()) {
     DLOG(WARNING) << ": previous get_frame_data_callback_ was not used yet";
     mojo::ReportBadMessage(
@@ -1989,10 +1914,6 @@
   WebVrTryStartAnimatingFrame(false);
 }
 
-void VrShellGl::ForceExitVr() {
-  browser_->ForceExitVr();
-}
-
 namespace {
 bool ValidateRect(const gfx::RectF& bounds) {
   // Bounds should be between 0 and 1, with positive width/height.
@@ -2014,7 +1935,7 @@
     return;
   }
 
-  if (frame_index >= 0 && !webxr_->HaveAnimatingFrame()) {
+  if (frame_index >= 0 && !webxr_.HaveAnimatingFrame()) {
     // The optional UpdateLayerBounds call must happen before SubmitFrame.
     mojo::ReportBadMessage("UpdateLayerBounds called without animating frame");
     presentation_binding_.Close();
@@ -2075,9 +1996,8 @@
   // Also, AddWebVrRenderTimeEstimate zeroes the submit time once the rendered
   // frame is complete. In all of those cases, we don't need to wait for render
   // completion.
-  if (webxr_->HaveRenderingFrame() && webxr_->HaveProcessingFrame()) {
-    base::TimeTicks prev_js_submit =
-        webxr_->GetRenderingFrame()->time_js_submit;
+  if (webxr_.HaveRenderingFrame() && webxr_.HaveProcessingFrame()) {
+    base::TimeTicks prev_js_submit = webxr_.GetRenderingFrame()->time_js_submit;
     base::TimeDelta mean_js_time = webvr_js_time_.GetAverage();
     base::TimeDelta mean_js_wait = webvr_js_wait_time_.GetAverage();
     base::TimeDelta prev_render_time_left =
@@ -2131,18 +2051,17 @@
   // The internal frame index is an uint8_t that generates a wrapping 0.255
   // frame number. We store it in an int16_t to match mojo APIs, and to avoid
   // it appearing as a char in debug logs.
-  frame_data->frame_id = webxr_->StartFrameAnimating();
-  DVLOG(2) << __FUNCTION__ << " frame=" << frame_data->frame_id;
+  frame_data->frame_id = webxr_.StartFrameAnimating();
+  DVLOG(2) << __func__ << " frame=" << frame_data->frame_id;
 
   if (webxr_use_shared_buffer_draw_) {
     WebVrPrepareSharedBuffer(webvr_surface_size_);
   }
 
   if (webxr_use_shared_buffer_draw_) {
-    CHECK(webxr_->mailbox_bridge_ready());
-    CHECK(webxr_->HaveAnimatingFrame());
-    WebXrSharedBuffer* buffer =
-        webxr_->GetAnimatingFrame()->shared_buffer.get();
+    CHECK(webxr_.mailbox_bridge_ready());
+    CHECK(webxr_.HaveAnimatingFrame());
+    WebXrSharedBuffer* buffer = webxr_.GetAnimatingFrame()->shared_buffer.get();
     DCHECK(buffer);
     frame_data->buffer_holder = *buffer->mailbox_holder;
   }
@@ -2173,7 +2092,7 @@
 
   frame_data->pose = std::move(pose);
 
-  WebXrFrame* frame = webxr_->GetAnimatingFrame();
+  WebXrFrame* frame = webxr_.GetAnimatingFrame();
   frame->head_pose = head_mat;
   frame->time_pose = base::TimeTicks::Now();
 
@@ -2236,15 +2155,6 @@
   ui_->AcceptDoffPromptForTesting();
 }
 
-void VrShellGl::SetUiExpectingActivityForTesting(
-    UiTestActivityExpectation ui_expectation) {
-  DCHECK(ui_test_state_ == nullptr)
-      << "Attempted to set a UI activity expectation with one in progress";
-  ui_test_state_ = std::make_unique<UiTestState>();
-  ui_test_state_->quiescence_timeout_ms =
-      base::TimeDelta::FromMilliseconds(ui_expectation.quiescence_timeout_ms);
-}
-
 void VrShellGl::PerformControllerActionForTesting(
     ControllerTestInput controller_input) {
   if (controller_input.action ==
@@ -2274,34 +2184,4 @@
   }
 }
 
-void VrShellGl::ReportUiStatusForTesting(const base::TimeTicks& current_time,
-                                         bool ui_updated) {
-  if (ui_test_state_ == nullptr)
-    return;
-  base::TimeDelta time_since_start = current_time - ui_test_state_->start_time;
-  if (ui_updated) {
-    ui_test_state_->activity_started = true;
-    if (time_since_start > ui_test_state_->quiescence_timeout_ms) {
-      // The UI is being updated, but hasn't reached a stable state in the
-      // given time -> report timeout.
-      ReportUiActivityResultForTesting(VrUiTestActivityResult::kTimeoutNoEnd);
-    }
-  } else {
-    if (ui_test_state_->activity_started) {
-      // The UI has been updated since the test requested notification of
-      // quiescence, but wasn't this frame -> report that the UI is quiescent.
-      ReportUiActivityResultForTesting(VrUiTestActivityResult::kQuiescent);
-    } else if (time_since_start > ui_test_state_->quiescence_timeout_ms) {
-      // The UI has never been updated and we've reached the timeout.
-      ReportUiActivityResultForTesting(VrUiTestActivityResult::kTimeoutNoStart);
-    }
-  }
-}
-
-void VrShellGl::ReportUiActivityResultForTesting(
-    VrUiTestActivityResult result) {
-  ui_test_state_ = nullptr;
-  browser_->ReportUiActivityResultForTesting(result);
-}
-
 }  // namespace vr
diff --git a/chrome/browser/android/vr/vr_shell_gl.h b/chrome/browser/android/vr/vr_shell_gl.h
index 513839b..9471fe7 100644
--- a/chrome/browser/android/vr/vr_shell_gl.h
+++ b/chrome/browser/android/vr/vr_shell_gl.h
@@ -63,7 +63,6 @@
 class BrowserUiInterface;
 class FPSMeter;
 class GlBrowserInterface;
-class GraphicsDelegate;
 class MailboxToSurfaceBridge;
 class ScopedGpuTrace;
 class SlidingTimeDeltaAverage;
@@ -101,7 +100,7 @@
                   public device::mojom::XRPresentationProvider,
                   public device::mojom::XRFrameDataProvider {
  public:
-  VrShellGl(GlBrowserInterface* browser_interface,
+  VrShellGl(GlBrowserInterface* browser,
             std::unique_ptr<UiInterface> ui,
             gvr_context* gvr_api,
             bool reprojected_rendering,
@@ -113,7 +112,6 @@
 
   void Initialize(base::WaitableEvent* gl_surface_created_event,
                   base::OnceCallback<gfx::AcceleratedWidget()> callback);
-  void InitializeGl(gfx::AcceleratedWidget surface);
 
   void OnTriggerEvent(bool pressed);
   void OnPause();
@@ -159,11 +157,10 @@
   void CancelToast();
 
   void AcceptDoffPromptForTesting();
-  void SetUiExpectingActivityForTesting(
-      UiTestActivityExpectation ui_expectation);
   void PerformControllerActionForTesting(ControllerTestInput controller_input);
 
  private:
+  void InitializeGl(gfx::AcceleratedWidget surface);
   void GvrInit(gvr_context* gvr_api);
 
   device::mojom::XRPresentationTransportOptionsPtr
@@ -192,15 +189,6 @@
   void DrawContentQuad(bool draw_overlay_texture);
   bool WebVrPoseByteIsValid(int pose_index_byte);
 
-  void UpdateController(const RenderInfo& render_info,
-                        base::TimeTicks current_time);
-
-  void HandleControllerInput(const gfx::Point3F& laser_origin,
-                             const RenderInfo& render_info,
-                             base::TimeTicks current_time);
-  void HandleControllerAppButtonActivity(
-      const gfx::Vector3dF& controller_direction);
-
   void OnContentFrameAvailable();
   void OnContentOverlayFrameAvailable();
   void OnUiFrameAvailable();
@@ -241,8 +229,6 @@
   // Returns true if OK to proceed.
   bool SubmitFrameCommon(int16_t frame_index, base::TimeDelta time_waited);
 
-  void ForceExitVr();
-
   // Sends a GetFrameData response to the presentation client.
   void SendVSync();
 
@@ -278,10 +264,6 @@
 
   device::mojom::XRInputSourceStatePtr GetGazeInputSourceState();
 
-  void ReportUiStatusForTesting(const base::TimeTicks& current_time,
-                                bool ui_updated);
-  void ReportUiActivityResultForTesting(VrUiTestActivityResult result);
-
   std::unique_ptr<ControllerDelegate> controller_delegate_for_testing_;
 
   // samplerExternalOES texture data for WebVR content image.
@@ -293,7 +275,6 @@
   bool webvr_vsync_align_;
 
   scoped_refptr<gl::GLSurface> surface_;
-  std::unique_ptr<GraphicsDelegate> graphics_delegate_;
   scoped_refptr<gl::SurfaceTexture> content_surface_texture_;
   scoped_refptr<gl::SurfaceTexture> content_overlay_surface_texture_;
   scoped_refptr<gl::SurfaceTexture> ui_surface_texture_;
@@ -348,11 +329,9 @@
   gfx::Size content_tex_buffer_size_ = {0, 0};
   gfx::Size webvr_surface_size_ = {0, 0};
 
-  std::unique_ptr<WebXrPresentationState> webxr_ = nullptr;
+  WebXrPresentationState webxr_;
 
   bool web_vr_mode_ = false;
-  bool ready_to_draw_ = false;
-  bool paused_ = true;
   const bool surfaceless_rendering_;
   bool daydream_support_;
   bool content_paused_;
@@ -404,9 +383,6 @@
   SlidingTimeDeltaAverage webvr_acquire_time_;
   SlidingTimeDeltaAverage webvr_submit_time_;
 
-  SlidingTimeDeltaAverage ui_processing_time_;
-  SlidingTimeDeltaAverage ui_controller_update_time_;
-
   gfx::Point3F pointer_start_;
 
   RenderInfo render_info_;
@@ -425,14 +401,12 @@
 
   std::vector<gvr::BufferSpec> specs_;
 
-  bool content_frame_available_ = false;
   gfx::Transform last_used_head_pose_;
 
   ControllerModel controller_model_;
 
   std::unique_ptr<PlatformUiInputDelegate> vr_dialog_input_delegate_;
   bool showing_vr_dialog_ = false;
-  std::unique_ptr<UiTestState> ui_test_state_;
   bool using_controller_delegate_for_testing_ = false;
 
   base::WeakPtrFactory<VrShellGl> weak_ptr_factory_;
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 5f6539cf..4aae22f 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -194,6 +194,7 @@
     " onchange=\"selectchange = true\" onblur=\"selectblur = true\" >"
     " <option value=\"\" selected=\"yes\">--</option>"
     " <option value=\"CA\">California</option>"
+    " <option value=\"NY\">New York</option>"
     " <option value=\"TX\">Texas</option>"
     " </select><br>"
     "<label for=\"zip\">ZIP code:</label>"
@@ -715,8 +716,9 @@
   ExpectFilledTestForm();
 }
 
-// Test that autofill doesn't refill a field initially modified by the user.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, ModifyFieldAndFill) {
+// Test that autofill doesn't refill a text field initially modified by the
+// user.
+IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, ModifyTextFieldAndFill) {
   CreateTestProfile();
 
   // Load the test page.
@@ -732,16 +734,44 @@
   AcceptSuggestionUsingArrowDown();
 
   ExpectFieldValue("firstname", "Milton");
-  ExpectFieldValue("lastname", "Waddams");  // Modified by the user.
+  ExpectFieldValue("lastname", "Waddams");
   ExpectFieldValue("address1", "4120 Freidrich Lane");
   ExpectFieldValue("address2", "Basement");
-  ExpectFieldValue("city", "Montreal");
+  ExpectFieldValue("city", "Montreal");  // Modified by the user.
   ExpectFieldValue("state", "TX");
   ExpectFieldValue("zip", "78744");
   ExpectFieldValue("country", "US");
   ExpectFieldValue("phone", "15125551234");
 }
 
+// Test that autofill doesn't refill a select field initially modified by the
+// user.
+IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, ModifySelectFieldAndFill) {
+  CreateTestProfile();
+
+  // Load the test page.
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString)));
+
+  // Modify a field.
+  FocusFieldByName("state");
+  FillElementWithValue("state", "CA");
+
+  // Fill
+  FocusFirstNameField();
+  AcceptSuggestionUsingArrowDown();
+
+  ExpectFieldValue("firstname", "Milton");
+  ExpectFieldValue("lastname", "Waddams");
+  ExpectFieldValue("address1", "4120 Freidrich Lane");
+  ExpectFieldValue("address2", "Basement");
+  ExpectFieldValue("city", "Austin");
+  ExpectFieldValue("state", "CA");  // Modified by the user.
+  ExpectFieldValue("zip", "78744");
+  ExpectFieldValue("country", "US");
+  ExpectFieldValue("phone", "15125551234");
+}
+
 // Test that autofill works when the website prefills the form.
 IN_PROC_BROWSER_TEST_P(AutofillInteractiveTest, PrefillFormAndFill) {
   const char kPrefillScript[] =
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index d704465f..ddb62c85 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -103,8 +103,6 @@
   } else {
     offline_item.state = OfflineItemState::IN_PROGRESS;
   }
-
-  // TODO(crbug.com/865063): Update the icon.
 }
 
 bool BackgroundFetchDelegateImpl::JobDetails::ShouldReportProgressBySize() {
@@ -229,8 +227,10 @@
   if (title && job_details.fetch_description->title != *title)
     job_details.fetch_description->title = *title;
 
-  if (icon)
+  if (icon) {
     job_details.fetch_description->icon = *icon;
+    job_details.offline_item.refresh_visuals = true;
+  }
 
   UpdateOfflineItemAndUpdateObservers(&job_details);
 }
@@ -516,7 +516,7 @@
 
 void BackgroundFetchDelegateImpl::GetVisualsForItem(
     const offline_items_collection::ContentId& id,
-    const VisualsCallback& callback) {
+    VisualsCallback callback) {
   // GetVisualsForItem mustn't be called directly since offline_items_collection
   // is not re-entrant and it must be called even if there are no visuals.
   auto visuals =
@@ -525,10 +525,20 @@
   if (it != job_details_map_.end()) {
     visuals->icon =
         gfx::Image::CreateFrom1xBitmap(it->second.fetch_description->icon);
+    it->second.offline_item.refresh_visuals = false;
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, id, std::move(visuals)));
+      FROM_HERE, base::BindOnce(std::move(callback), id, std::move(visuals)));
+}
+
+void BackgroundFetchDelegateImpl::GetShareInfoForItem(
+    const offline_items_collection::ContentId& id,
+    ShareCallback callback) {
+  // TODO(xingliu): Provide OfflineItemShareInfo to |callback|.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), id,
+                                nullptr /* OfflineItemShareInfo */));
 }
 
 void BackgroundFetchDelegateImpl::AddObserver(Observer* observer) {
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 2434fdc9..e2b351c 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -88,7 +88,9 @@
                    SingleItemCallback callback) override;
   void GetAllItems(MultipleItemCallback callback) override;
   void GetVisualsForItem(const offline_items_collection::ContentId& id,
-                         const VisualsCallback& callback) override;
+                         VisualsCallback callback) override;
+  void GetShareInfoForItem(const offline_items_collection::ContentId& id,
+                           ShareCallback callback) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 2ce3eea..94d19844 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -215,10 +215,8 @@
   return nullptr;
 }
 
-BrowserProcessImpl::BrowserProcessImpl(
-    base::SequencedTaskRunner* local_state_task_runner)
-    : local_state_task_runner_(local_state_task_runner),
-      pref_service_factory_(
+BrowserProcessImpl::BrowserProcessImpl()
+    : pref_service_factory_(
           std::make_unique<prefs::InProcessPrefServiceFactory>()) {
   g_browser_process = this;
   platform_part_ = std::make_unique<BrowserProcessPlatformPart>();
@@ -471,15 +469,15 @@
  public:
   RundownTaskCounter();
 
-  // Posts a rundown task to |task_runner|, can be invoked an arbitrary number
-  // of times before calling TimedWait.
-  void Post(base::SequencedTaskRunner* task_runner);
+  // Increments |count_| and returns a closure bound to Decrement(). All
+  // closures returned by this RundownTaskCounter's GetRundownClosure() method
+  // must be invoked for TimedWait() to complete its wait without timing
+  // out.
+  base::OnceClosure GetRundownClosure();
 
-  // Waits until the count is zero or |end_time| is reached.
-  // This can only be called once per instance. Returns true if a count of zero
-  // is reached or false if the |end_time| is reached. It is valid to pass an
-  // |end_time| in the past.
-  bool TimedWaitUntil(const base::TimeTicks& end_time);
+  // Waits until the count is zero or |timeout| expires.
+  // This can only be called once per instance.
+  void TimedWait(base::TimeDelta timeout);
 
  private:
   friend class base::RefCountedThreadSafe<RundownTaskCounter>;
@@ -491,28 +489,22 @@
 
   // The count starts at one to defer the possibility of one->zero transitions
   // until TimedWait is called.
-  base::AtomicRefCount count_;
+  base::AtomicRefCount count_{1};
   base::WaitableEvent waitable_event_;
 
   DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter);
 };
 
-RundownTaskCounter::RundownTaskCounter()
-    : count_(1),
-      waitable_event_(base::WaitableEvent::ResetPolicy::MANUAL,
-                      base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+RundownTaskCounter::RundownTaskCounter() = default;
 
-void RundownTaskCounter::Post(base::SequencedTaskRunner* task_runner) {
+base::OnceClosure RundownTaskCounter::GetRundownClosure() {
   // As the count starts off at one, it should never get to zero unless
   // TimedWait has been called.
   DCHECK(!count_.IsZero());
 
   count_.Increment();
 
-  // The task must be non-nestable to guarantee that it runs after all tasks
-  // currently scheduled on |task_runner| have completed.
-  task_runner->PostNonNestableTask(
-      FROM_HERE, base::BindOnce(&RundownTaskCounter::Decrement, this));
+  return base::BindOnce(&RundownTaskCounter::Decrement, this);
 }
 
 void RundownTaskCounter::Decrement() {
@@ -520,20 +512,25 @@
     waitable_event_.Signal();
 }
 
-bool RundownTaskCounter::TimedWaitUntil(const base::TimeTicks& end_time) {
+void RundownTaskCounter::TimedWait(base::TimeDelta timeout) {
   // Decrement the excess count from the constructor.
   Decrement();
 
-  return waitable_event_.TimedWaitUntil(end_time);
+  // RundownTaskCounter::TimedWait() could return
+  // |waitable_event_.TimedWait()|'s result if any user ever cared about whether
+  // it returned per success or timeout. Currently no user of this API cares and
+  // as such this return value is ignored.
+  waitable_event_.TimedWait(timeout);
 }
 
 }  // namespace
 
 void BrowserProcessImpl::FlushLocalStateAndReply(base::OnceClosure reply) {
-  if (local_state_)
-    local_state_->CommitPendingWrite();
-  local_state_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
-                                             std::move(reply));
+  if (local_state_) {
+    local_state_->CommitPendingWrite(std::move(reply));
+    return;
+  }
+  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(reply));
 }
 
 void BrowserProcessImpl::EndSession() {
@@ -546,8 +543,8 @@
     Profile* profile = profiles[i];
     profile->SetExitType(Profile::EXIT_SESSION_ENDED);
     if (profile->GetPrefs()) {
-      profile->GetPrefs()->CommitPendingWrite();
-      rundown_counter->Post(profile->GetIOTaskRunner().get());
+      profile->GetPrefs()->CommitPendingWrite(
+          base::OnceClosure(), rundown_counter->GetRundownClosure());
     }
   }
 
@@ -559,9 +556,8 @@
     // MetricsService lazily writes to prefs, force it to write now.
     // On ChromeOS, chrome gets killed when hangs, so no need to
     // commit metrics::prefs::kStabilitySessionEndCompleted change immediately.
-    local_state_->CommitPendingWrite();
-
-    rundown_counter->Post(local_state_task_runner_.get());
+    local_state_->CommitPendingWrite(base::OnceClosure(),
+                                     rundown_counter->GetRundownClosure());
 #endif
   }
 
@@ -588,8 +584,7 @@
   // GPU process synchronously. Because the system may not be allowing
   // processes to launch, this can result in a hang. See
   // http://crbug.com/318527.
-  const base::TimeTicks end_time = base::TimeTicks::Now() + kEndSessionTimeout;
-  rundown_counter->TimedWaitUntil(end_time);
+  rundown_counter->TimedWait(kEndSessionTimeout);
 #else
   NOTIMPLEMENTED();
 #endif
@@ -1117,8 +1112,8 @@
   auto delegate = pref_service_factory_->CreateDelegate();
   delegate->InitPrefRegistry(pref_registry.get());
   local_state_ = chrome_prefs::CreateLocalState(
-      local_state_path, local_state_task_runner_.get(), policy_service(),
-      std::move(pref_registry), false, std::move(delegate));
+      local_state_path, policy_service(), std::move(pref_registry), false,
+      std::move(delegate));
   DCHECK(local_state_);
 
   sessions::SessionIdGenerator::GetInstance()->Init(local_state_.get());
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 834e6c6..ecd6a24 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -47,7 +47,6 @@
 
 namespace base {
 class CommandLine;
-class SequencedTaskRunner;
 }
 
 namespace extensions {
@@ -75,9 +74,7 @@
 class BrowserProcessImpl : public BrowserProcess,
                            public KeepAliveStateObserver {
  public:
-  // |local_state_task_runner| must be a shutdown-blocking task runner.
-  explicit BrowserProcessImpl(
-      base::SequencedTaskRunner* local_state_task_runner);
+  BrowserProcessImpl();
   ~BrowserProcessImpl() override;
 
   // Called to complete initialization.
@@ -323,9 +320,6 @@
 
   scoped_refptr<DownloadRequestLimiter> download_request_limiter_;
 
-  // Sequenced task runner for local state related I/O tasks.
-  const scoped_refptr<base::SequencedTaskRunner> local_state_task_runner_;
-
   // Ensures that the observers of plugin/print disable/enable state
   // notifications are properly added and removed.
   PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/browser_process_impl_unittest.cc b/chrome/browser/browser_process_impl_unittest.cc
index 30400aa..3a7af64 100644
--- a/chrome/browser/browser_process_impl_unittest.cc
+++ b/chrome/browser/browser_process_impl_unittest.cc
@@ -31,8 +31,7 @@
         loop_(base::MessageLoop::TYPE_UI),
         ui_thread_(content::BrowserThread::UI, &loop_),
         command_line_(base::CommandLine::NO_PROGRAM),
-        browser_process_impl_(
-            new BrowserProcessImpl(base::ThreadTaskRunnerHandle::Get().get())) {
+        browser_process_impl_(new BrowserProcessImpl()) {
     // Create() and StartWithDefaultParams() TaskScheduler in seperate steps to
     // properly simulate the browser process' lifecycle.
     base::TaskScheduler::Create("BrowserProcessImplTest");
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 8faaf838..b596e7d0 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -349,7 +349,7 @@
 }
 #endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 
-void InitializeLocalState(base::SequencedTaskRunner* local_state_task_runner) {
+void InitializeLocalState() {
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::InitializeLocalState")
 
   // Load local state.  This includes the application locale so we know which
@@ -406,7 +406,6 @@
                                    std::string());
       const std::unique_ptr<PrefService> parent_local_state =
           chrome_prefs::CreateLocalState(parent_profile,
-                                         local_state_task_runner,
                                          g_browser_process->policy_service(),
                                          std::move(registry), false, nullptr);
       // Right now, we only inherit the locale setting from the parent profile.
@@ -690,20 +689,6 @@
                 prefs::kWebDriverOverridesIncompatiblePolicies)));
 }
 
-// The initial read is done synchronously, the TaskPriority is thus only used
-// for flushes to disks and BACKGROUND is therefore appropriate. Priority of
-// remaining BACKGROUND+BLOCK_SHUTDOWN tasks is bumped by the TaskScheduler on
-// shutdown. However, some shutdown use cases happen without
-// TaskScheduler::Shutdown() (e.g. ChromeRestartRequest::Start() and
-// BrowserProcessImpl::EndSession()) and we must thus unfortunately make this
-// USER_VISIBLE until we solve https://crbug.com/747495 to allow bumping
-// priority of a sequence on demand.
-scoped_refptr<base::SequencedTaskRunner> CreateLocalStateTaskRunner() {
-  return base::CreateSequencedTaskRunnerWithTraits(
-      {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
-       base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
-}
-
 // Initializes the shared instance of ResourceBundle and returns the locale. An
 // empty string return value indicates failure.
 std::string InitResourceBundleAndDetermineLocale(
@@ -1005,16 +990,11 @@
   for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
     chrome_extra_parts_[i]->PreEarlyInitialization();
 
-  // Create BrowserProcess in PreEarlyInitialization() so that we can load
-  // field trials (and all it depends upon).
-  scoped_refptr<base::SequencedTaskRunner> local_state_task_runner =
-      CreateLocalStateTaskRunner();
-  browser_process_ =
-      std::make_unique<BrowserProcessImpl>(local_state_task_runner.get());
+  browser_process_ = std::make_unique<BrowserProcessImpl>();
 
   bool failed_to_load_resource_bundle = false;
-  const int load_local_state_result = LoadLocalState(
-      local_state_task_runner.get(), &failed_to_load_resource_bundle);
+  const int load_local_state_result =
+      LoadLocalState(&failed_to_load_resource_bundle);
   if (load_local_state_result == chrome::RESULT_CODE_MISSING_DATA &&
       failed_to_load_resource_bundle) {
     if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -1089,13 +1069,12 @@
 }
 
 int ChromeBrowserMainParts::LoadLocalState(
-    base::SequencedTaskRunner* local_state_task_runner,
     bool* failed_to_load_resource_bundle) {
   *failed_to_load_resource_bundle = false;
   if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_))
     return chrome::RESULT_CODE_MISSING_DATA;
 
-  InitializeLocalState(local_state_task_runner);
+  InitializeLocalState();
 
   ConvertFlagsToSwitches();
 
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index 1c5426c..4d0e815 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -29,10 +29,6 @@
 class ShutdownWatcherHelper;
 class WebUsbDetector;
 
-namespace base {
-class SequencedTaskRunner;
-}
-
 namespace chrome_browser {
 // For use by ShowMissingLocaleMessageBox.
 #if defined(OS_WIN)
@@ -130,8 +126,7 @@
   // If the return value is RESULT_CODE_MISSING_DATA, then
   // |failed_to_load_resource_bundle| indicates if the ResourceBundle couldn't
   // be loaded.
-  int LoadLocalState(base::SequencedTaskRunner* local_state_task_runner,
-                     bool* failed_to_load_resource_bundle);
+  int LoadLocalState(bool* failed_to_load_resource_bundle);
 
   // Applies any preferences (to local state) needed for first run. This is
   // always called and early outs if not first-run. Return value is an exit
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 9846c9c..0458d3db 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -367,6 +367,7 @@
 #if !defined(OS_ANDROID)
 #include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
 #include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/media/unified_autoplay_config.h"
 #include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
@@ -1432,6 +1433,17 @@
 #endif
 }
 
+void ChromeContentBrowserClient::LogInitiatorSchemeBypassingDocumentBlocking(
+    const url::Origin& initiator_origin,
+    int render_process_id,
+    content::ResourceType resource_type) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  ChromeContentBrowserClientExtensionsPart::
+      LogInitiatorSchemeBypassingDocumentBlocking(
+          initiator_origin, render_process_id, resource_type);
+#endif
+}
+
 // These are treated as WebUI schemes but do not get WebUI bindings. Also,
 // view-source is allowed for these schemes.
 void ChromeContentBrowserClient::GetAdditionalWebUISchemes(
@@ -3113,11 +3125,21 @@
   }
 
 #if !defined(OS_ANDROID)
-  // If autoplay is allowed by policy then update the autoplay policy in web
-  // preferences.
   if (IsAutoplayAllowedByPolicy(contents, prefs)) {
+    // If autoplay is allowed by policy then force the no user gesture required
+    // autoplay policy.
     web_prefs->autoplay_policy =
         content::AutoplayPolicy::kNoUserGestureRequired;
+  } else if (base::FeatureList::IsEnabled(media::kAutoplaySoundSettings) &&
+             web_prefs->autoplay_policy ==
+                 content::AutoplayPolicy::kDocumentUserActivationRequired) {
+    // If the autoplay sound settings feature is enabled and the autoplay policy
+    // is set to using the unified policy then set the default autoplay policy
+    // based on user preference.
+    web_prefs->autoplay_policy =
+        UnifiedAutoplayConfig::ShouldBlockAutoplay(profile)
+            ? content::AutoplayPolicy::kDocumentUserActivationRequired
+            : content::AutoplayPolicy::kNoUserGestureRequired;
   }
 #endif  // !defined(OS_ANDROID)
 
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 173ea46e..9aa0e926 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -118,6 +118,10 @@
   bool ShouldLockToOrigin(content::BrowserContext* browser_context,
                           const GURL& effective_site_url) override;
   const char* GetInitiatorSchemeBypassingDocumentBlocking() override;
+  void LogInitiatorSchemeBypassingDocumentBlocking(
+      const url::Origin& initiator_origin,
+      int render_process_id,
+      content::ResourceType resource_type) override;
   void GetAdditionalWebUISchemes(
       std::vector<std::string>* additional_schemes) override;
   void GetAdditionalViewSourceSchemes(
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h
index aaf3be55..ba936539 100644
--- a/chrome/browser/chrome_notification_types.h
+++ b/chrome/browser/chrome_notification_types.h
@@ -258,14 +258,6 @@
   NOTIFICATION_COOKIE_CHANGED_FOR_EXTENSIONS,
 #endif
 
-  // Download Notifications --------------------------------------------------
-
-  // Sent when a download is initiated. It is possible that the download will
-  // not actually begin due to the DownloadRequestLimiter cancelling it
-  // prematurely.
-  // The source is the corresponding WebContents. There are no details.
-  NOTIFICATION_DOWNLOAD_INITIATED,
-
   // Misc --------------------------------------------------------------------
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 9a37ce5..db60e48 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2165,6 +2165,7 @@
     "policy/upload_job_unittest.cc",
     "policy/user_cloud_policy_manager_chromeos_unittest.cc",
     "policy/user_cloud_policy_store_chromeos_unittest.cc",
+    "policy/weekly_time/time_utils_unittest.cc",
     "policy/weekly_time/weekly_time_interval_unittest.cc",
     "policy/weekly_time/weekly_time_unittest.cc",
     "power/cpu_data_collector_unittest.cc",
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
index b56227c7..78f4eb8 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/extensions/external_loader.h"
 #include "chrome/browser/extensions/external_provider_impl.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/chromeos_paths.h"
@@ -53,6 +54,7 @@
 #include "components/user_manager/user_manager.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/cros_system_api/switches/chrome_switches.h"
 
 namespace chromeos {
@@ -165,9 +167,11 @@
   if (g_test_overrides)
     return g_test_overrides->CreateExternalCache(delegate, true);
 
+  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory =
+      g_browser_process->shared_url_loader_factory();
   auto cache = std::make_unique<ExternalCacheImpl>(
-      GetCrxCacheDir(), g_browser_process->system_request_context(),
-      GetBackgroundTaskRunner(), delegate, true /* always_check_updates */,
+      GetCrxCacheDir(), shared_url_loader_factory, GetBackgroundTaskRunner(),
+      delegate, true /* always_check_updates */,
       false /* wait_for_cache_initialization */);
   cache->set_flush_on_put(true);
   return cache;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index c1ada1b..ae4b008 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -186,6 +186,10 @@
 #include "components/rlz/rlz_tracker.h"
 #endif
 
+#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
+#include "chrome/browser/ui/ash/assistant/assistant_client.h"
+#endif
+
 namespace chromeos {
 
 namespace {
@@ -686,6 +690,12 @@
   arc_voice_interaction_controller_client_ =
       std::make_unique<arc::VoiceInteractionControllerClient>();
 
+#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
+  // Assistant has to be initialized before session_controller_client to avoid
+  // race of SessionChanged event and assistant_client initialization.
+  assistant_client_ = std::make_unique<AssistantClient>();
+#endif
+
   chromeos::ResourceReporter::GetInstance()->StartMonitoring(
       task_manager::TaskManagerInterface::GetTaskManager());
 
@@ -1061,6 +1071,12 @@
 
   arc_service_launcher_->Shutdown();
 
+#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
+  // Assistant has to shut down before voice interaction controller client to
+  // correctly remove the observer.
+  assistant_client_.reset();
+#endif
+
   arc_voice_interaction_controller_client_.reset();
 
   // Unregister CrosSettings observers before CrosSettings is destroyed.
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index b6d0103..6ccc4a2d 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/chrome_browser_main_linux.h"
 #include "chrome/browser/chromeos/external_metrics.h"
 #include "chrome/browser/memory/memory_kills_monitor.h"
+#include "chromeos/assistant/buildflags.h"
 
 class SpokenFeedbackEventRewriterDelegate;
 
@@ -24,6 +25,10 @@
 class VoiceInteractionControllerClient;
 }
 
+#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
+class AssistantClient;
+#endif
+
 namespace chromeos {
 
 class ArcKioskAppManager;
@@ -111,6 +116,10 @@
   std::unique_ptr<arc::VoiceInteractionControllerClient>
       arc_voice_interaction_controller_client_;
 
+#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
+  std::unique_ptr<AssistantClient> assistant_client_;
+#endif
+
   std::unique_ptr<LowDiskNotification> low_disk_notification_;
   std::unique_ptr<ArcKioskAppManager> arc_kiosk_app_manager_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 9d1c15c..969e670 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -16,15 +16,19 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/crostini/crostini_remover.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/file_manager/path_util.h"
+#include "chrome/browser/chromeos/file_manager/volume_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chromeos/dbus/concierge_client.h"
+#include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
 #include "chromeos/dbus/image_loader_client.h"
+#include "chromeos/disks/disk_mount_manager.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "content/public/browser/browser_thread.h"
@@ -32,6 +36,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "net/base/escape.h"
 #include "net/base/network_change_notifier.h"
+#include "storage/browser/fileapi/external_mount_points.h"
 
 namespace crostini {
 
@@ -58,10 +63,9 @@
   ~CrostiniRestarterService() override = default;
 
   CrostiniManager::RestartId Register(
+      Profile* profile,
       std::string vm_name,
-      std::string crypothome_id,
       std::string container_name,
-      std::string container_username,
       CrostiniManager::RestartCrostiniCallback callback,
       CrostiniManager::RestartObserver* observer);
 
@@ -113,15 +117,18 @@
   }
 };
 
-class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> {
+class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter>,
+                          public chromeos::disks::DiskMountManager::Observer {
  public:
   CrostiniRestarter(CrostiniRestarterService* restarter_service,
+                    Profile* profile,
                     std::string vm_name,
                     std::string cryptohome_id,
                     std::string container_name,
                     std::string container_username,
                     CrostiniManager::RestartCrostiniCallback callback)
-      : vm_name_(std::move(vm_name)),
+      : profile_(profile),
+        vm_name_(std::move(vm_name)),
         cryptohome_id_(std::move(cryptohome_id)),
         container_name_(std::move(container_name)),
         container_username_(std::move(container_username)),
@@ -135,11 +142,11 @@
       return;
 
     CrostiniManager* crostini_manager = CrostiniManager::GetInstance();
-    // Finish Restart immediately if testing.
+    // Go to StartContainerFinished immediately if testing.
     if (crostini_manager->skip_restart_for_testing()) {
       content::BrowserThread::PostTask(
           content::BrowserThread::UI, FROM_HERE,
-          base::BindOnce(&CrostiniRestarter::FinishRestart,
+          base::BindOnce(&CrostiniRestarter::StartContainerFinished,
                          base::WrapRefCounted(this),
                          ConciergeClientResult::SUCCESS));
       return;
@@ -169,7 +176,7 @@
  private:
   friend class base::RefCountedThreadSafe<CrostiniRestarter>;
 
-  ~CrostiniRestarter() {
+  ~CrostiniRestarter() override {
     if (callback_) {
       LOG(ERROR) << "Destroying without having called the callback.";
     }
@@ -258,18 +265,109 @@
 
   void StartContainerFinished(ConciergeClientResult result) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    if (result != ConciergeClientResult::SUCCESS) {
-      LOG(ERROR) << "Failed to start container.";
+    // Tell observers.
+    for (auto& observer : observer_list_) {
+      observer.OnContainerStarted(result);
     }
     if (is_aborted_)
       return;
-    FinishRestart(result);
+    if (result != ConciergeClientResult::SUCCESS) {
+      LOG(ERROR) << "Failed to start container.";
+      FinishRestart(result);
+      return;
+    }
+
+    // If default termina/penguin, then do sshfs mount, else we are finished.
+    if (vm_name_ == kCrostiniDefaultVmName &&
+        container_name_ == kCrostiniDefaultContainerName) {
+      CrostiniManager::GetInstance()->GetContainerSshKeys(
+          vm_name_, container_name_, cryptohome_id_,
+          base::BindOnce(&CrostiniRestarter::GetContainerSshKeysFinished,
+                         this));
+    } else {
+      FinishRestart(result);
+    }
   }
 
+  void GetContainerSshKeysFinished(crostini::ConciergeClientResult result,
+                                   const std::string& container_public_key,
+                                   const std::string& host_private_key,
+                                   const std::string& hostname) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    // Tell observers.
+    for (auto& observer : observer_list_) {
+      observer.OnSshKeysFetched(result);
+    }
+    if (is_aborted_)
+      return;
+    if (result != crostini::ConciergeClientResult::SUCCESS) {
+      LOG(ERROR) << "Failed to get ssh keys.";
+      FinishRestart(result);
+      return;
+    }
+
+    // Add DiskMountManager::OnMountEvent observer.
+    auto* dmgr = chromeos::disks::DiskMountManager::GetInstance();
+    dmgr->AddObserver(this);
+
+    // Call to sshfs to mount.
+    source_path_ = base::StringPrintf(
+        "sshfs://%s@%s:", container_username_.c_str(), hostname.c_str());
+    dmgr->MountPath(source_path_, "",
+                    file_manager::util::GetCrostiniMountPointName(profile_),
+                    file_manager::util::GetCrostiniMountOptions(
+                        hostname, host_private_key, container_public_key),
+                    chromeos::MOUNT_TYPE_NETWORK_STORAGE,
+                    chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
+  }
+
+  void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
+                    chromeos::MountError error_code,
+                    const chromeos::disks::DiskMountManager::MountPointInfo&
+                        mount_info) override {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    // Ignore any other mount/unmount events.
+    if (event != chromeos::disks::DiskMountManager::MountEvent::MOUNTING ||
+        mount_info.source_path != source_path_) {
+      return;
+    }
+    // Remove DiskMountManager::OnMountEvent observer.
+    chromeos::disks::DiskMountManager::GetInstance()->RemoveObserver(this);
+
+    if (error_code != chromeos::MountError::MOUNT_ERROR_NONE) {
+      LOG(ERROR) << "Error mounting crostini container: error_code="
+                 << error_code << ", source_path=" << mount_info.source_path
+                 << ", mount_path=" << mount_info.mount_path
+                 << ", mount_type=" << mount_info.mount_type
+                 << ", mount_condition=" << mount_info.mount_condition;
+    } else {
+      // Register filesystem and add volume to VolumeManager.
+      base::FilePath mount_path =
+          base::FilePath(FILE_PATH_LITERAL(mount_info.mount_path));
+      storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+          file_manager::util::GetCrostiniMountPointName(profile_),
+          storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(),
+          mount_path);
+
+      // VolumeManager is null in unittest.
+      if (auto* vmgr = file_manager::VolumeManager::Get(profile_))
+        vmgr->AddSshfsCrostiniVolume(mount_path);
+    }
+
+    // Abort not checked until end of function.  On abort, do not call
+    // FinishRestart, but still remove observer and add volume as per above.
+    if (is_aborted_)
+      return;
+    FinishRestart(ConciergeClientResult::SUCCESS);
+  }
+
+  Profile* profile_;
   std::string vm_name_;
   std::string cryptohome_id_;
   std::string container_name_;
   std::string container_username_;
+  std::string source_path_;
   CrostiniManager::RestartCrostiniCallback callback_;
   base::ObserverList<CrostiniManager::RestartObserver> observer_list_;
   CrostiniManager::RestartId restart_id_;
@@ -282,15 +380,14 @@
 CrostiniManager::RestartId CrostiniRestarter::next_restart_id_ = 0;
 
 CrostiniManager::RestartId CrostiniRestarterService::Register(
+    Profile* profile,
     std::string vm_name,
-    std::string cryptohome_id,
     std::string container_name,
-    std::string container_username,
     CrostiniManager::RestartCrostiniCallback callback,
     CrostiniManager::RestartObserver* observer) {
   auto restarter = base::MakeRefCounted<CrostiniRestarter>(
-      this, std::move(vm_name), std::move(cryptohome_id),
-      std::move(container_name), std::move(container_username),
+      this, profile, std::move(vm_name), CryptohomeIdForProfile(profile),
+      std::move(container_name), ContainerUserNameForProfile(profile),
       std::move(callback));
   if (observer)
     restarter->AddObserver(observer);
@@ -968,8 +1065,7 @@
     RestartObserver* observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   return CrostiniRestarterServiceFactory::GetForProfile(profile)->Register(
-      std::move(vm_name), CryptohomeIdForProfile(profile),
-      std::move(container_name), ContainerUserNameForProfile(profile),
+      profile, std::move(vm_name), std::move(container_name),
       std::move(callback), observer);
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 6f9a05a..359bf4e 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -44,6 +44,7 @@
   LAUNCH_CONTAINER_APPLICATION_FAILED,
   INSTALL_LINUX_PACKAGE_FAILED,
   INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE,
+  SSHFS_MOUNT_ERROR,
   UNKNOWN_ERROR,
 };
 
@@ -143,6 +144,8 @@
     virtual void OnConciergeStarted(ConciergeClientResult result) = 0;
     virtual void OnDiskImageCreated(ConciergeClientResult result) = 0;
     virtual void OnVmStarted(ConciergeClientResult result) = 0;
+    virtual void OnContainerStarted(ConciergeClientResult result) = 0;
+    virtual void OnSshKeysFetched(ConciergeClientResult result) = 0;
   };
 
   // Checks if the cros-termina component is installed.
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 3a2770b..5de8000 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -3,15 +3,19 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_cicerone_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
+#include "chromeos/disks/mock_disk_mount_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "storage/browser/fileapi/external_mount_points.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace crostini {
@@ -450,6 +454,18 @@
     }
   }
 
+  void OnContainerStarted(ConciergeClientResult result) override {
+    if (abort_on_container_started_) {
+      Abort();
+    }
+  }
+
+  void OnSshKeysFetched(ConciergeClientResult result) override {
+    if (abort_on_ssh_keys_fetched_) {
+      Abort();
+    }
+  }
+
  protected:
   void Abort() {
     CrostiniManager::GetInstance()->AbortRestartCrostini(profile(),
@@ -457,13 +473,31 @@
     run_loop()->Quit();
   }
 
+  void SshfsMount(const std::string& source_path,
+                  const std::string& source_format,
+                  const std::string& mount_label,
+                  const std::vector<std::string>& mount_options,
+                  chromeos::MountType type,
+                  chromeos::MountAccessMode access_mode) {
+    disk_mount_manager_mock_->NotifyMountEvent(
+        chromeos::disks::DiskMountManager::MountEvent::MOUNTING,
+        chromeos::MountError::MOUNT_ERROR_NONE,
+        chromeos::disks::DiskMountManager::MountPointInfo(
+            source_path, "/media/fuse/" + mount_label,
+            chromeos::MountType::MOUNT_TYPE_NETWORK_STORAGE,
+            chromeos::disks::MountCondition::MOUNT_CONDITION_NONE));
+  }
+
   CrostiniManager::RestartId restart_id_ =
       CrostiniManager::kUninitializedRestartId;
   bool abort_on_component_loaded_ = false;
   bool abort_on_concierge_started_ = false;
   bool abort_on_disk_image_created_ = false;
   bool abort_on_vm_started_ = false;
+  bool abort_on_container_started_ = false;
+  bool abort_on_ssh_keys_fetched_ = false;
   int restart_crostini_callback_count_ = 0;
+  chromeos::disks::MockDiskMountManager* disk_mount_manager_mock_;
 };
 
 TEST_F(CrostiniManagerRestartTest, RestartSuccess) {
@@ -476,6 +510,8 @@
   EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
   EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
   EXPECT_TRUE(fake_concierge_client_->start_container_called());
+  // Mount only performed for termina/penguin.
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
   EXPECT_EQ(1, restart_crostini_callback_count_);
 }
 
@@ -490,6 +526,7 @@
   EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
   EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
   EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
   EXPECT_EQ(0, restart_crostini_callback_count_);
 }
 
@@ -504,6 +541,7 @@
   EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
   EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
   EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
   EXPECT_EQ(0, restart_crostini_callback_count_);
 }
 
@@ -518,6 +556,7 @@
   EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
   EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
   EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
   EXPECT_EQ(0, restart_crostini_callback_count_);
 }
 
@@ -532,9 +571,41 @@
   EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
   EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
   EXPECT_FALSE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
   EXPECT_EQ(0, restart_crostini_callback_count_);
 }
 
+TEST_F(CrostiniManagerRestartTest, AbortOnContainerStarted) {
+  abort_on_container_started_ = true;
+  // Use termina/penguin names to allow fetch ssh keys.
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile(), kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), run_loop()->QuitClosure()),
+      this);
+  run_loop()->Run();
+  EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_TRUE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
+  EXPECT_EQ(0, restart_crostini_callback_count_);
+}
+
+TEST_F(CrostiniManagerRestartTest, OnlyMountTerminaPenguin) {
+  // Use names other than termina/penguin.  Will not mount sshfs.
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile(), kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), run_loop()->QuitClosure()),
+      this);
+  run_loop()->Run();
+  EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_TRUE(fake_concierge_client_->start_container_called());
+  EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
+  EXPECT_EQ(1, restart_crostini_callback_count_);
+}
+
 TEST_F(CrostiniManagerRestartTest, MultiRestartAllowed) {
   CrostiniManager::GetInstance()->RestartCrostini(
       profile(), kVmName, kContainerName,
@@ -556,4 +627,48 @@
   EXPECT_EQ(3, restart_crostini_callback_count_);
 }
 
+TEST_F(CrostiniManagerRestartTest, MountForTerminaPenguin) {
+  // DiskMountManager mock.  Verify that correct values are received
+  // from concierge and passed to DiskMountManager.
+  disk_mount_manager_mock_ = new chromeos::disks::MockDiskMountManager;
+  chromeos::disks::DiskMountManager::InitializeForTesting(
+      disk_mount_manager_mock_);
+  disk_mount_manager_mock_->SetupDefaultReplies();
+  std::string known_hosts;
+  base::Base64Encode("[hostname]:2222 pubkey", &known_hosts);
+  std::string identity;
+  base::Base64Encode("privkey", &identity);
+  std::vector<std::string> mount_options = {
+      "UserKnownHostsBase64=" + known_hosts, "IdentityBase64=" + identity,
+      "Port=2222"};
+  EXPECT_CALL(*disk_mount_manager_mock_,
+              MountPath("sshfs://testing_profile@hostname:", "",
+                        "crostini_test_termina_penguin", mount_options,
+                        chromeos::MOUNT_TYPE_NETWORK_STORAGE,
+                        chromeos::MOUNT_ACCESS_MODE_READ_WRITE))
+      .WillOnce(Invoke(
+          this,
+          &CrostiniManagerRestartTest_MountForTerminaPenguin_Test::SshfsMount));
+
+  // Use termina/penguin to perform mount.
+  restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
+      profile(), kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), run_loop()->QuitClosure()));
+
+  run_loop()->Run();
+  EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
+  EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
+  EXPECT_TRUE(fake_concierge_client_->start_container_called());
+  EXPECT_TRUE(fake_concierge_client_->get_container_ssh_keys_called());
+  EXPECT_EQ(1, restart_crostini_callback_count_);
+  base::FilePath path;
+  EXPECT_TRUE(
+      storage::ExternalMountPoints::GetSystemInstance()->GetRegisteredPath(
+          "crostini_test_termina_penguin", &path));
+  EXPECT_EQ(base::FilePath("/media/fuse/crostini_test_termina_penguin"), path);
+
+  chromeos::disks::DiskMountManager::Shutdown();
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
index 03c628c..782aa10c 100644
--- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
+++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
@@ -47,7 +47,7 @@
 CreateCryptAuthClientFactoryImpl(Profile* profile) {
   return std::make_unique<cryptauth::CryptAuthClientFactoryImpl>(
       IdentityManagerFactory::GetForProfile(profile),
-      profile->GetRequestContext(),
+      profile->GetURLLoaderFactory(),
       cryptauth::device_classifier_util::GetDeviceClassifier());
 }
 
diff --git a/chrome/browser/chromeos/drive/OWNERS b/chrome/browser/chromeos/drive/OWNERS
index 8121074..931afe6 100644
--- a/chrome/browser/chromeos/drive/OWNERS
+++ b/chrome/browser/chromeos/drive/OWNERS
@@ -3,6 +3,5 @@
 hirono@chromium.org
 kinaba@chromium.org
 sammc@chromium.org
-sashab@chromium.org
 slangley@chromium.org
 yoshiki@chromium.org
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index f081c007..cf90e81 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -297,8 +297,9 @@
 
  private:
   // drivefs::DriveFsHost::Delegate:
-  net::URLRequestContextGetter* GetRequestContext() override {
-    return profile_->GetRequestContext();
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
+      override {
+    return profile_->GetURLLoaderFactory();
   }
 
   service_manager::Connector* GetConnector() override {
diff --git a/chrome/browser/chromeos/extensions/arc_apps_private_api.cc b/chrome/browser/chromeos/extensions/arc_apps_private_api.cc
index 6844601..cc3e18b 100644
--- a/chrome/browser/chromeos/extensions/arc_apps_private_api.cc
+++ b/chrome/browser/chromeos/extensions/arc_apps_private_api.cc
@@ -7,12 +7,64 @@
 #include <string>
 #include <vector>
 
+#include "base/logging.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/common/extensions/api/arc_apps_private.h"
 #include "ui/events/event_constants.h"
 
+namespace extensions {
+
+// static
+BrowserContextKeyedAPIFactory<ArcAppsPrivateAPI>*
+ArcAppsPrivateAPI::GetFactoryInstance() {
+  static base::NoDestructor<BrowserContextKeyedAPIFactory<ArcAppsPrivateAPI>>
+      instance;
+  return instance.get();
+}
+
+ArcAppsPrivateAPI::ArcAppsPrivateAPI(content::BrowserContext* context)
+    : context_(context), scoped_prefs_observer_(this) {
+  EventRouter::Get(context_)->RegisterObserver(
+      this, api::arc_apps_private::OnInstalled::kEventName);
+}
+
+ArcAppsPrivateAPI::~ArcAppsPrivateAPI() = default;
+
+void ArcAppsPrivateAPI::Shutdown() {
+  EventRouter::Get(context_)->UnregisterObserver(this);
+  scoped_prefs_observer_.RemoveAll();
+}
+
+void ArcAppsPrivateAPI::OnListenerAdded(const EventListenerInfo& details) {
+  DCHECK_EQ(details.event_name, api::arc_apps_private::OnInstalled::kEventName);
+  auto* prefs = ArcAppListPrefs::Get(Profile::FromBrowserContext(context_));
+  if (prefs && !scoped_prefs_observer_.IsObserving(prefs))
+    scoped_prefs_observer_.Add(prefs);
+}
+
+void ArcAppsPrivateAPI::OnListenerRemoved(const EventListenerInfo& details) {
+  if (!EventRouter::Get(context_)->HasEventListener(
+          api::arc_apps_private::OnInstalled::kEventName)) {
+    scoped_prefs_observer_.RemoveAll();
+  }
+}
+
+void ArcAppsPrivateAPI::OnAppRegistered(
+    const std::string& app_id,
+    const ArcAppListPrefs::AppInfo& app_info) {
+  if (!app_info.launchable)
+    return;
+  api::arc_apps_private::AppInfo app_info_result;
+  app_info_result.package_name = app_info.package_name;
+  auto event = std::make_unique<Event>(
+      events::ARC_APPS_PRIVATE_ON_INSTALLED,
+      api::arc_apps_private::OnInstalled::kEventName,
+      api::arc_apps_private::OnInstalled::Create(app_info_result), context_);
+  EventRouter::Get(context_)->BroadcastEvent(std::move(event));
+}
+
 ArcAppsPrivateGetLaunchableAppsFunction::
     ArcAppsPrivateGetLaunchableAppsFunction() = default;
 
@@ -21,24 +73,23 @@
 
 ExtensionFunction::ResponseAction
 ArcAppsPrivateGetLaunchableAppsFunction::Run() {
-  ArcAppListPrefs* prefs =
+  auto* prefs =
       ArcAppListPrefs::Get(Profile::FromBrowserContext(browser_context()));
   if (!prefs)
     return RespondNow(Error("Not available"));
 
-  std::vector<extensions::api::arc_apps_private::AppInfo> result;
+  std::vector<api::arc_apps_private::AppInfo> result;
   const std::vector<std::string> app_ids = prefs->GetAppIds();
   for (const auto& app_id : app_ids) {
     std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(app_id);
     if (app_info && app_info->launchable) {
-      extensions::api::arc_apps_private::AppInfo app_info_result;
-      app_info_result.id = app_id;
+      api::arc_apps_private::AppInfo app_info_result;
+      app_info_result.package_name = app_info->package_name;
       result.push_back(std::move(app_info_result));
     }
   }
   return RespondNow(ArgumentList(
-      extensions::api::arc_apps_private::GetLaunchableApps::Results::Create(
-          result)));
+      api::arc_apps_private::GetLaunchableApps::Results::Create(result)));
 }
 
 ArcAppsPrivateLaunchAppFunction::ArcAppsPrivateLaunchAppFunction() = default;
@@ -46,16 +97,23 @@
 ArcAppsPrivateLaunchAppFunction::~ArcAppsPrivateLaunchAppFunction() = default;
 
 ExtensionFunction::ResponseAction ArcAppsPrivateLaunchAppFunction::Run() {
-  std::unique_ptr<extensions::api::arc_apps_private::LaunchApp::Params> params(
-      extensions::api::arc_apps_private::LaunchApp::Params::Create(*args_));
+  std::unique_ptr<api::arc_apps_private::LaunchApp::Params> params(
+      api::arc_apps_private::LaunchApp::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  if (!ArcAppListPrefs::Get(Profile::FromBrowserContext(browser_context())))
+  ArcAppListPrefs* prefs =
+      ArcAppListPrefs::Get(Profile::FromBrowserContext(browser_context()));
+  if (!prefs)
     return RespondNow(Error("Not available"));
 
+  const std::string app_id = prefs->GetAppIdByPackageName(params->package_name);
+  if (app_id.empty())
+    return RespondNow(Error("App not found"));
   if (!arc::LaunchApp(
-          browser_context(), params->app_id, ui::EF_NONE,
+          browser_context(), app_id, ui::EF_NONE,
           arc::UserInteractionType::APP_STARTED_FROM_EXTENSION_API)) {
     return RespondNow(Error("Launch failed"));
   }
   return RespondNow(NoArguments());
-}
\ No newline at end of file
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/arc_apps_private_api.h b/chrome/browser/chromeos/extensions/arc_apps_private_api.h
index c15cc63d..d4bb602e 100644
--- a/chrome/browser/chromeos/extensions/arc_apps_private_api.h
+++ b/chrome/browser/chromeos/extensions/arc_apps_private_api.h
@@ -6,8 +6,60 @@
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_ARC_APPS_PRIVATE_API_H_
 
 #include "base/macros.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_function.h"
 
+namespace extensions {
+
+class ArcAppsPrivateAPI : public BrowserContextKeyedAPI,
+                          public EventRouter::Observer,
+                          public ArcAppListPrefs::Observer {
+ public:
+  static BrowserContextKeyedAPIFactory<ArcAppsPrivateAPI>* GetFactoryInstance();
+
+  explicit ArcAppsPrivateAPI(content::BrowserContext* context);
+  ~ArcAppsPrivateAPI() override;
+
+  // BrowserContextKeyedAPI:
+  void Shutdown() override;
+
+  // EventRouter::Observer:
+  void OnListenerAdded(const EventListenerInfo& details) override;
+  void OnListenerRemoved(const EventListenerInfo& details) override;
+
+  // ArcAppListPrefs::Observer:
+  void OnAppRegistered(const std::string& app_id,
+                       const ArcAppListPrefs::AppInfo& app_info) override;
+
+ private:
+  friend class BrowserContextKeyedAPIFactory<ArcAppsPrivateAPI>;
+
+  static const char* service_name() { return "ArcAppsPrivateAPI"; }
+
+  // BrowserContextKeyedAPI:
+  static const bool kServiceIsNULLWhileTesting = true;
+
+  content::BrowserContext* const context_;
+
+  ScopedObserver<ArcAppListPrefs, ArcAppsPrivateAPI> scoped_prefs_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppsPrivateAPI);
+};
+
+template <>
+struct BrowserContextFactoryDependencies<ArcAppsPrivateAPI> {
+  static void DeclareFactoryDependencies(
+      BrowserContextKeyedAPIFactory<ArcAppsPrivateAPI>* factory) {
+    factory->DependsOn(
+        ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
+    factory->DependsOn(ArcAppListPrefsFactory::GetInstance());
+  }
+};
+
 class ArcAppsPrivateGetLaunchableAppsFunction
     : public UIThreadExtensionFunction {
  public:
@@ -43,4 +95,6 @@
   DISALLOW_COPY_AND_ASSIGN(ArcAppsPrivateLaunchAppFunction);
 };
 
+}  // namespace extensions
+
 #endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_ARC_APPS_PRIVATE_API_H_
\ No newline at end of file
diff --git a/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc b/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc
index 845a027..99368eb 100644
--- a/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/arc_apps_private_apitest.cc
@@ -5,9 +5,11 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/path_service.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #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 "components/arc/arc_bridge_service.h"
@@ -15,6 +17,8 @@
 #include "components/arc/arc_util.h"
 #include "components/arc/test/connection_holder_util.h"
 #include "components/arc/test/fake_app_instance.h"
+#include "extensions/test/extension_test_message_listener.h"
+#include "extensions/test/result_catcher.h"
 
 namespace {
 
@@ -62,7 +66,7 @@
   DISALLOW_COPY_AND_ASSIGN(ArcAppsPrivateApiTest);
 };
 
-IN_PROC_BROWSER_TEST_F(ArcAppsPrivateApiTest, GetAppIdAndLaunchApp) {
+IN_PROC_BROWSER_TEST_F(ArcAppsPrivateApiTest, GetPackageNameAndLaunchApp) {
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(browser()->profile());
   ASSERT_TRUE(prefs);
   std::unique_ptr<arc::FakeAppInstance> app_instance = CreateAppInstance(prefs);
@@ -72,17 +76,17 @@
   static_cast<arc::mojom::AppHost*>(prefs)->OnTaskCreated(
       0 /* task_id */, "Package_1", "Dummy_activity_1", "App_1",
       base::nullopt /* intent */);
+
   // Stopping the service makes the app non-ready.
   arc::ArcServiceManager::Get()->arc_bridge_service()->app()->CloseInstance(
       app_instance.get());
-
   EXPECT_EQ(0u, app_instance->launch_requests().size());
-  // Verify |chrome.arcAppsPrivate.getLaunchableApps| returns the id of
-  // the launchable app only. The JS test will attempt to launch the app.
-  EXPECT_TRUE(RunPlatformAppTestWithArg(
-      "arc_app_launcher",
-      ArcAppListPrefs::GetAppId("Package_0", "Dummy_activity_0").c_str()))
+  // Verify |chrome.arcAppsPrivate.getLaunchableApps| returns the package name
+  // of the launchable app only. The JS test will attempt to launch the app.
+  EXPECT_TRUE(
+      RunPlatformAppTestWithArg("arc_app_launcher/launch_app", "Package_0"))
       << message_;
+
   // Verify the app is not launched because it's not ready.
   EXPECT_EQ(0u, app_instance->launch_requests().size());
   // Restarting the service makes the app ready. Verify the app is launched
@@ -91,4 +95,35 @@
   app_instance->SendRefreshAppList({launchable_app});
   ASSERT_EQ(1u, app_instance->launch_requests().size());
   EXPECT_TRUE(app_instance->launch_requests()[0]->IsForApp(launchable_app));
+}
+
+IN_PROC_BROWSER_TEST_F(ArcAppsPrivateApiTest, OnInstalled) {
+  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(browser()->profile());
+  ASSERT_TRUE(prefs);
+  std::unique_ptr<arc::FakeAppInstance> app_instance = CreateAppInstance(prefs);
+  arc::mojom::AppInfo launchable_app("App_0", "Package_0", "Dummy_activity_0");
+
+  // The JS test will observe the onInstalled event and attempt to launch the
+  // newly installed app.
+  SetCustomArg("Package_0");
+  extensions::ResultCatcher catcher;
+  ExtensionTestMessageListener ready_listener("ready", false);
+
+  base::FilePath path =
+      test_data_dir_.AppendASCII("arc_app_launcher/install_event");
+  const extensions::Extension* app = LoadExtension(path);
+  ASSERT_TRUE(app);
+  EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
+
+  EXPECT_EQ(0u, app_instance->launch_requests().size());
+  // Add one launchable app and one non-launchable app.
+  app_instance->SendRefreshAppList({launchable_app});
+  static_cast<arc::mojom::AppHost*>(prefs)->OnTaskCreated(
+      0 /* task_id */, "Package_1", "Dummy_activity_1", "App_1",
+      base::nullopt /* intent */);
+  // Verify the JS test receives the onInstalled event for the launchable app
+  // only, and the app is launched successfully.
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+  ASSERT_EQ(1u, app_instance->launch_requests().size());
+  EXPECT_TRUE(app_instance->launch_requests()[0]->IsForApp(launchable_app));
 }
\ No newline at end of file
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
index eb78793..d3fc3b5 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
@@ -12,10 +12,11 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/extensions/external_cache_impl.h"
 #include "chrome/browser/extensions/policy_handlers.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/prefs/pref_value_map.h"
 #include "extensions/browser/pref_names.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace chromeos {
 
@@ -34,9 +35,12 @@
     const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner) {
   DCHECK(!external_cache_);
   store_->AddObserver(this);
+
+  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory =
+      g_browser_process->shared_url_loader_factory();
   external_cache_ = std::make_unique<ExternalCacheImpl>(
-      cache_dir_, g_browser_process->system_request_context(),
-      cache_task_runner, this, true /* always_check_updates */,
+      cache_dir_, shared_url_loader_factory, cache_task_runner, this,
+      true /* always_check_updates */,
       false /* wait_for_cache_initialization */);
 
   if (store_->is_initialized())
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
index 6d5a2933..f2fc817 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
@@ -37,10 +37,8 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -66,8 +64,6 @@
 const char kExtensionId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
 const char kExtensionUpdateManifest[] =
     "extensions/good_v1_update_manifest.xml";
-const char kExtensionCRXSourceDir[] = "extensions";
-const char kExtensionCRXFile[] = "good.crx";
 const char kExtensionCRXVersion[] = "1.0.0.0";
 
 class MockExternalPolicyProviderVisitor
@@ -111,11 +107,20 @@
   void VerifyAndResetVisitorCallExpectations();
   void SetForceInstallListPolicy();
 
+  network::TestURLLoaderFactory::PendingRequest* GetPendingRequest(
+      size_t index = 0) {
+    if (index >= test_url_loader_factory_.pending_requests()->size())
+      return nullptr;
+    return &test_url_loader_factory_.pending_requests()->at(index);
+  }
+
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   base::FilePath cache_dir_;
   policy::MockCloudPolicyStore store_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+      test_shared_loader_factory_;
   base::FilePath test_dir_;
 
   scoped_refptr<DeviceLocalAccountExternalPolicyLoader> loader_;
@@ -132,8 +137,10 @@
 
 DeviceLocalAccountExternalPolicyLoaderTest::
     DeviceLocalAccountExternalPolicyLoaderTest()
-    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
-}
+    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+      test_shared_loader_factory_(
+          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+              &test_url_loader_factory_)) {}
 
 DeviceLocalAccountExternalPolicyLoaderTest::
     ~DeviceLocalAccountExternalPolicyLoaderTest() {
@@ -143,10 +150,8 @@
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   cache_dir_ = temp_dir_.GetPath().Append(kCacheDir);
   ASSERT_TRUE(base::CreateDirectoryAndGetError(cache_dir_, NULL));
-  request_context_getter_ =
-      new net::TestURLRequestContextGetter(base::ThreadTaskRunnerHandle::Get());
-  TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(
-      request_context_getter_.get());
+  TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory(
+      test_shared_loader_factory_);
   ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
 
   loader_ = new DeviceLocalAccountExternalPolicyLoader(&store_, cache_dir_);
@@ -162,7 +167,7 @@
 }
 
 void DeviceLocalAccountExternalPolicyLoaderTest::TearDown() {
-  TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(NULL);
+  TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory(nullptr);
 }
 
 void DeviceLocalAccountExternalPolicyLoaderTest::
@@ -240,25 +245,22 @@
 
   // Spin the loop, allowing the loader to process the force-install list.
   // Verify that the loader announces an empty extension list.
-  net::TestURLFetcherFactory factory;
   EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
       .Times(1);
   base::RunLoop().RunUntilIdle();
 
   // Verify that a downloader has started and is attempting to download an
   // update manifest.
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(
-      extensions::ExtensionDownloader::kManifestFetcherId);
-  ASSERT_TRUE(fetcher);
-  ASSERT_TRUE(fetcher->delegate());
+  EXPECT_EQ(1, test_url_loader_factory_.NumPending());
 
   // Return a manifest to the downloader.
   std::string manifest;
   EXPECT_TRUE(base::ReadFileToString(test_dir_.Append(kExtensionUpdateManifest),
                                      &manifest));
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(manifest);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  auto* pending_request = GetPendingRequest();
+  test_url_loader_factory_.AddResponse(pending_request->request.url.spec(),
+                                       manifest);
 
   // Wait for the manifest to be parsed.
   content::WindowedNotificationObserver(
@@ -266,18 +268,12 @@
       content::NotificationService::AllSources()).Wait();
 
   // Verify that the downloader is attempting to download a CRX file.
-  fetcher = factory.GetFetcherByID(
-      extensions::ExtensionDownloader::kExtensionFetcherId);
-  ASSERT_TRUE(fetcher);
-  ASSERT_TRUE(fetcher->delegate());
+  EXPECT_EQ(1, test_url_loader_factory_.NumPending());
 
-  // Create a temporary CRX file and return its path to the downloader.
-  EXPECT_TRUE(base::CopyFile(
-      test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile),
-      temp_dir_.GetPath().Append(kExtensionCRXFile)));
-  fetcher->set_response_code(200);
-  fetcher->SetResponseFilePath(temp_dir_.GetPath().Append(kExtensionCRXFile));
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  // Trigger downloading of the temporary CRX file.
+  pending_request = GetPendingRequest();
+  test_url_loader_factory_.AddResponse(pending_request->request.url.spec(),
+                                       "Content is irrelevant.");
 
   // Spin the loop. Verify that the loader announces the presence of a new CRX
   // file, served from the cache directory.
@@ -298,12 +294,6 @@
   cache_run_loop.Run();
   VerifyAndResetVisitorCallExpectations();
 
-  // Verify that the CRX file actually exists in the cache directory and its
-  // contents matches the file returned to the downloader.
-  EXPECT_TRUE(base::ContentsEqual(
-      test_dir_.Append(kExtensionCRXSourceDir).Append(kExtensionCRXFile),
-      cached_crx_path));
-
   // Stop the cache. Verify that the loader announces an empty extension list.
   EXPECT_CALL(visitor_, OnExternalProviderReady(provider_.get()))
       .Times(1);
diff --git a/chrome/browser/chromeos/extensions/external_cache_impl.cc b/chrome/browser/chromeos/extensions/external_cache_impl.cc
index 91a2ab96b..e88a3e5 100644
--- a/chrome/browser/chromeos/extensions/external_cache_impl.cc
+++ b/chrome/browser/chromeos/extensions/external_cache_impl.cc
@@ -31,7 +31,7 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace chromeos {
 
@@ -67,13 +67,13 @@
 
 ExternalCacheImpl::ExternalCacheImpl(
     const base::FilePath& cache_dir,
-    net::URLRequestContextGetter* request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const scoped_refptr<base::SequencedTaskRunner>& backend_task_runner,
     ExternalCacheDelegate* delegate,
     bool always_check_updates,
     bool wait_for_cache_initialization)
     : local_cache_(cache_dir, 0, base::TimeDelta(), backend_task_runner),
-      request_context_(request_context),
+      url_loader_factory_(std::move(url_loader_factory)),
       backend_task_runner_(backend_task_runner),
       delegate_(delegate),
       always_check_updates_(always_check_updates),
@@ -267,10 +267,10 @@
   if (local_cache_.is_shutdown())
     return;
 
-  // If request_context_ is missing we can't download anything.
-  if (request_context_.get()) {
-    downloader_ = ChromeExtensionDownloaderFactory::CreateForRequestContext(
-        request_context_.get(), this, GetConnector());
+  // If url_loader_factory_ is missing we can't download anything.
+  if (url_loader_factory_) {
+    downloader_ = ChromeExtensionDownloaderFactory::CreateForURLLoaderFactory(
+        url_loader_factory_, this, GetConnector());
   }
 
   cached_extensions_->Clear();
diff --git a/chrome/browser/chromeos/extensions/external_cache_impl.h b/chrome/browser/chromeos/extensions/external_cache_impl.h
index 0d58e5e3..f8180ce 100644
--- a/chrome/browser/chromeos/extensions/external_cache_impl.h
+++ b/chrome/browser/chromeos/extensions/external_cache_impl.h
@@ -30,8 +30,8 @@
 class ExtensionDownloader;
 }
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 namespace service_manager {
@@ -47,15 +47,15 @@
                           public content::NotificationObserver,
                           public extensions::ExtensionDownloaderDelegate {
  public:
-  // The |request_context| is used for update checks. All file I/O is done via
-  // the |backend_task_runner|. If |always_check_updates| is |false|, update
+  // The |url_loader_factory| is used for update checks. All file I/O is done
+  // via the |backend_task_runner|. If |always_check_updates| is |false|, update
   // checks are performed for extensions that have an |external_update_url|
   // only. If |wait_for_cache_initialization| is |true|, the cache contents will
   // not be read until a flag file appears in the cache directory, signaling
   // that the cache is ready.
   ExternalCacheImpl(
       const base::FilePath& cache_dir,
-      net::URLRequestContextGetter* request_context,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const scoped_refptr<base::SequencedTaskRunner>& backend_task_runner,
       ExternalCacheDelegate* delegate,
       bool always_check_updates,
@@ -129,8 +129,8 @@
 
   extensions::LocalExtensionCache local_cache_;
 
-  // Request context used by the |downloader_|.
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
+  // URL lader factory used by the |downloader_|.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   // Task runner for executing file I/O tasks.
   const scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
diff --git a/chrome/browser/chromeos/extensions/external_cache_impl_unittest.cc b/chrome/browser/chromeos/extensions/external_cache_impl_unittest.cc
index dc09cf2e..01a755e2 100644
--- a/chrome/browser/chromeos/extensions/external_cache_impl_unittest.cc
+++ b/chrome/browser/chromeos/extensions/external_cache_impl_unittest.cc
@@ -24,9 +24,9 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/common/extension_urls.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher_impl.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -45,23 +45,18 @@
                               public ExternalCacheDelegate {
  public:
   ExternalCacheImplTest()
-      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD),
+        test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {}
   ~ExternalCacheImplTest() override = default;
 
-  net::URLRequestContextGetter* request_context_getter() {
-    return request_context_getter_.get();
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory() {
+    return test_shared_loader_factory_;
   }
 
   const base::DictionaryValue* provided_prefs() { return prefs_.get(); }
 
-  // testing::Test overrides:
-  void SetUp() override {
-    request_context_getter_ = new net::TestURLRequestContextGetter(
-        content::BrowserThread::GetTaskRunnerForThread(
-            content::BrowserThread::IO));
-    fetcher_factory_.reset(new net::TestURLFetcherFactory());
-  }
-
   // ExternalCacheDelegate:
   void OnExtensionListsUpdated(const base::DictionaryValue* prefs) override {
     prefs_.reset(prefs->DeepCopy());
@@ -125,8 +120,8 @@
  private:
   content::TestBrowserThreadBundle thread_bundle_;
 
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  std::unique_ptr<net::TestURLFetcherFactory> fetcher_factory_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
 
   base::ScopedTempDir cache_dir_;
   base::ScopedTempDir temp_dir_;
@@ -142,7 +137,7 @@
 TEST_F(ExternalCacheImplTest, Basic) {
   base::FilePath cache_dir(CreateCacheDir(false));
   ExternalCacheImpl external_cache(
-      cache_dir, request_context_getter(),
+      cache_dir, url_loader_factory(),
       base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}), this, true,
       false);
   external_cache.use_null_connector_for_test();
@@ -261,7 +256,7 @@
 TEST_F(ExternalCacheImplTest, PreserveInstalled) {
   base::FilePath cache_dir(CreateCacheDir(false));
   ExternalCacheImpl external_cache(
-      cache_dir, request_context_getter(),
+      cache_dir, url_loader_factory(),
       base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}), this, true,
       false);
   external_cache.use_null_connector_for_test();
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc
index 5c8f21d..2fcacb5 100644
--- a/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc
@@ -72,9 +72,13 @@
   Disk CreateTestDisk(const std::string& device_path,
                       const std::string& mount_path,
                       bool is_read_only_hardware) {
-    return Disk(device_path, mount_path, false, "", "", "", "", "", "", "", "",
-                "", device_path, chromeos::DEVICE_TYPE_UNKNOWN, 0, false,
-                is_read_only_hardware, false, false, false, false, "vfat", "");
+    return *Disk::Builder()
+                .SetDevicePath(device_path)
+                .SetMountPath(mount_path)
+                .SetSystemPathPrefix(device_path)
+                .SetIsReadOnlyHardware(is_read_only_hardware)
+                .SetFileSystemType("vfat")
+                .Build();
   }
 
   std::unique_ptr<DeviceEventRouterImpl> device_event_router;
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index ac0b09d5..6b3d9b38 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -285,31 +285,39 @@
         if (static_cast<size_t>(disk_info_index) >= arraysize(kTestDisks))
           return;
 
+        std::unique_ptr<Disk> disk =
+            Disk::Builder()
+                .SetDevicePath(kTestMountPoints[i].source_path)
+                .SetMountPath(kTestMountPoints[i].mount_path)
+                .SetWriteDisabledByPolicy(
+                    kTestDisks[disk_info_index].write_disabled_by_policy)
+                .SetSystemPath(kTestDisks[disk_info_index].system_path)
+                .SetFilePath(kTestDisks[disk_info_index].file_path)
+                .SetDeviceLabel(kTestDisks[disk_info_index].device_label)
+                .SetDriveLabel(kTestDisks[disk_info_index].drive_label)
+                .SetVendorId(kTestDisks[disk_info_index].vendor_id)
+                .SetVendorName(kTestDisks[disk_info_index].vendor_name)
+                .SetProductId(kTestDisks[disk_info_index].product_id)
+                .SetProductName(kTestDisks[disk_info_index].product_name)
+                .SetFileSystemUUID(kTestDisks[disk_info_index].fs_uuid)
+                .SetSystemPathPrefix(
+                    kTestDisks[disk_info_index].system_path_prefix)
+                .SetDeviceType(kTestDisks[disk_info_index].device_type)
+                .SetSizeInBytes(kTestDisks[disk_info_index].size_in_bytes)
+                .SetIsParent(kTestDisks[disk_info_index].is_parent)
+                .SetIsReadOnlyHardware(
+                    kTestDisks[disk_info_index].is_read_only_hardware)
+                .SetHasMedia(kTestDisks[disk_info_index].has_media)
+                .SetOnBootDevice(kTestDisks[disk_info_index].on_boot_device)
+                .SetOnRemovableDevice(
+                    kTestDisks[disk_info_index].on_removable_device)
+                .SetIsHidden(kTestDisks[disk_info_index].is_hidden)
+                .SetFileSystemType(kTestDisks[disk_info_index].file_system_type)
+                .SetBaseMountPath(kTestDisks[disk_info_index].base_mount_path)
+                .Build();
+
         volumes_.insert(DiskMountManager::DiskMap::value_type(
-            kTestMountPoints[i].source_path,
-            std::make_unique<Disk>(
-                kTestMountPoints[i].source_path, kTestMountPoints[i].mount_path,
-                kTestDisks[disk_info_index].write_disabled_by_policy,
-                kTestDisks[disk_info_index].system_path,
-                kTestDisks[disk_info_index].file_path,
-                kTestDisks[disk_info_index].device_label,
-                kTestDisks[disk_info_index].drive_label,
-                kTestDisks[disk_info_index].vendor_id,
-                kTestDisks[disk_info_index].vendor_name,
-                kTestDisks[disk_info_index].product_id,
-                kTestDisks[disk_info_index].product_name,
-                kTestDisks[disk_info_index].fs_uuid,
-                kTestDisks[disk_info_index].system_path_prefix,
-                kTestDisks[disk_info_index].device_type,
-                kTestDisks[disk_info_index].size_in_bytes,
-                kTestDisks[disk_info_index].is_parent,
-                kTestDisks[disk_info_index].is_read_only_hardware,
-                kTestDisks[disk_info_index].has_media,
-                kTestDisks[disk_info_index].on_boot_device,
-                kTestDisks[disk_info_index].on_removable_device,
-                kTestDisks[disk_info_index].is_hidden,
-                kTestDisks[disk_info_index].file_system_type,
-                kTestDisks[disk_info_index].base_mount_path)));
+            kTestMountPoints[i].source_path, std::move(disk)));
       }
     }
   }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 7193c0f..032488f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -19,7 +19,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_package_installer_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
@@ -66,7 +65,6 @@
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "google_apis/drive/auth_service.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "storage/browser/fileapi/external_mount_points.h"
 #include "storage/common/fileapi/file_system_types.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "url/gurl.h"
@@ -671,92 +669,9 @@
     crostini::ConciergeClientResult result) {
   if (result != crostini::ConciergeClientResult::SUCCESS) {
     Respond(Error(
-        base::StringPrintf("Error restarting crostini container: %d", result)));
+        base::StringPrintf("Error mounting crostini container: %d", result)));
     return;
   }
-
-  crostini::CrostiniManager::GetInstance()->GetContainerSshKeys(
-      kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
-      CryptohomeIdForProfile(Profile::FromBrowserContext(browser_context())),
-      base::BindOnce(
-          &FileManagerPrivateMountCrostiniContainerFunction::SshKeysCallback,
-          this));
-}
-
-void FileManagerPrivateMountCrostiniContainerFunction::SshKeysCallback(
-    crostini::ConciergeClientResult result,
-    const std::string& container_public_key,
-    const std::string& host_private_key,
-    const std::string& hostname) {
-  if (result != crostini::ConciergeClientResult::SUCCESS) {
-    Respond(Error(
-        base::StringPrintf("Error fetching crostini ssh keys: %d", result)));
-    return;
-  }
-
-  // Add an observer for OnMountEvent and keep this object alive to receive it.
-  chromeos::disks::DiskMountManager* manager =
-      chromeos::disks::DiskMountManager::GetInstance();
-  manager->AddObserver(this);
-  self_ = this;
-
-  // Call to sshfs to mount.
-  // Path = sshfs://<username>@<hostname>:
-  // Label = crostini_<cryptohome_id>_<vm_name>_<container_name>
-  Profile* profile = Profile::FromBrowserContext(browser_context());
-  std::string port = "2222";
-  source_path_ = base::StringPrintf(
-      "sshfs://%s@%s:", ContainerUserNameForProfile(profile).c_str(),
-      hostname.c_str());
-  mount_label_ = file_manager::util::GetCrostiniMountPointName(profile);
-  std::vector<std::string> mount_options;
-  std::string base64_known_hosts;
-  std::string base64_identity;
-  base::Base64Encode(host_private_key, &base64_identity);
-  base::Base64Encode(
-      base::StringPrintf("[%s]:%s %s", hostname.c_str(), port.c_str(),
-                         container_public_key.c_str()),
-      &base64_known_hosts);
-  mount_options.push_back("UserKnownHostsBase64=" + base64_known_hosts);
-  mount_options.push_back("IdentityBase64=" + base64_identity);
-  mount_options.push_back("Port=" + port);
-  manager->MountPath(source_path_, "", mount_label_, mount_options,
-                     chromeos::MOUNT_TYPE_NETWORK_STORAGE,
-                     chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
-}
-
-void FileManagerPrivateMountCrostiniContainerFunction::OnMountEvent(
-    chromeos::disks::DiskMountManager::MountEvent event,
-    chromeos::MountError error_code,
-    const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) {
-  // Ignore any other mount/unmount events.
-  if (event != chromeos::disks::DiskMountManager::MountEvent::MOUNTING ||
-      mount_info.source_path != source_path_) {
-    return;
-  }
-  // Remove observer and self ref.
-  chromeos::disks::DiskMountManager::GetInstance()->RemoveObserver(this);
-  auto self = std::move(self_);
-
-  if (error_code != chromeos::MountError::MOUNT_ERROR_NONE) {
-    Respond(Error(base::StringPrintf(
-        "Error mounting crostini container: error_code=%d, "
-        "source_path=%s, mount_path=%s, mount_type=%d, mount_condition=%d",
-        error_code, mount_info.source_path.c_str(),
-        mount_info.mount_path.c_str(), mount_info.mount_type,
-        mount_info.mount_condition)));
-    return;
-  }
-
-  // Register filesystem and add volume to VolumeManager.
-  base::FilePath mount_path =
-      base::FilePath(FILE_PATH_LITERAL(mount_info.mount_path));
-  storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
-      mount_label_, storage::kFileSystemTypeNativeLocal,
-      storage::FileSystemMountOption(), mount_path);
-
-  file_manager::VolumeManager::Get(browser_context())
-      ->AddSshfsCrostiniVolume(mount_path);
   Respond(NoArguments());
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index 05d65f3..cd8f86a 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -19,7 +19,6 @@
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
-#include "chromeos/disks/disk_mount_manager.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 #include "storage/browser/fileapi/file_system_url.h"
 
@@ -283,8 +282,7 @@
 // Implements the chrome.fileManagerPrivate.mountCrostiniContainer method.
 // Starts and mounts crostini container.
 class FileManagerPrivateMountCrostiniContainerFunction
-    : public LoggedAsyncExtensionFunction,
-      public chromeos::disks::DiskMountManager::Observer {
+    : public LoggedAsyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.mountCrostiniContainer",
                              FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER)
@@ -295,22 +293,10 @@
 
   bool RunAsync() override;
   void RestartCallback(crostini::ConciergeClientResult);
-  void SshKeysCallback(crostini::ConciergeClientResult,
-                       const std::string& container_public_key,
-                       const std::string& host_private_key,
-                       const std::string& hostname);
-
-  // DiskMountManager::Observer
-  void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
-                    chromeos::MountError error_code,
-                    const chromeos::disks::DiskMountManager::MountPointInfo&
-                        mount_info) override;
 
  private:
   std::string source_path_;
   std::string mount_label_;
-  // Self reference used to keep object alive to receive OnMountEvent.
-  scoped_refptr<FileManagerPrivateMountCrostiniContainerFunction> self_;
 };
 
 // Implements the chrome.fileManagerPrivate.installLinuxPackage method.
diff --git a/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc b/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
index 678d804..a40cb7e 100644
--- a/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
+++ b/chrome/browser/chromeos/file_manager/fake_disk_mount_manager.cc
@@ -160,8 +160,8 @@
     chromeos::disks::DiskMountManager::DiskEvent event,
     const chromeos::disks::Disk* disk) {
   for (auto& observer : observers_) {
-    disk->IsAutoMountable() ? observer.OnAutoMountableDiskEvent(event, *disk)
-                            : observer.OnBootDeviceDiskEvent(event, *disk);
+    disk->is_auto_mountable() ? observer.OnAutoMountableDiskEvent(event, *disk)
+                              : observer.OnBootDeviceDiskEvent(event, *disk);
   }
 }
 
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index 8c296c2..42142d5 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 
 #include "base/barrier_closure.h"
+#include "base/base64.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/sys_info.h"
@@ -138,6 +139,25 @@
   return base::FilePath("/media/fuse/" + GetCrostiniMountPointName(profile));
 }
 
+std::vector<std::string> GetCrostiniMountOptions(
+    const std::string& hostname,
+    const std::string& host_private_key,
+    const std::string& container_public_key) {
+  const std::string port = "2222";
+  std::vector<std::string> options;
+  std::string base64_known_hosts;
+  std::string base64_identity;
+  base::Base64Encode(host_private_key, &base64_identity);
+  base::Base64Encode(
+      base::StringPrintf("[%s]:%s %s", hostname.c_str(), port.c_str(),
+                         container_public_key.c_str()),
+      &base64_known_hosts);
+  options.push_back("UserKnownHostsBase64=" + base64_known_hosts);
+  options.push_back("IdentityBase64=" + base64_identity);
+  options.push_back("Port=" + port);
+  return options;
+}
+
 std::string ConvertFileSystemURLToPathInsideCrostini(
     Profile* profile,
     const storage::FileSystemURL& file_system_url) {
diff --git a/chrome/browser/chromeos/file_manager/path_util.h b/chrome/browser/chromeos/file_manager/path_util.h
index 1be3dee..1b025f8 100644
--- a/chrome/browser/chromeos/file_manager/path_util.h
+++ b/chrome/browser/chromeos/file_manager/path_util.h
@@ -52,6 +52,12 @@
 // The actual directory the crostini "Linux Files" folder is mounted.
 base::FilePath GetCrostiniMountDirectory(Profile* profile);
 
+// The sshfs mount options for crostini "Linux Files" mount.
+std::vector<std::string> GetCrostiniMountOptions(
+    const std::string& hostname,
+    const std::string& host_private_key,
+    const std::string& container_public_key);
+
 // Convert a cracked url to a path inside the Crostini VM.
 std::string ConvertFileSystemURLToPathInsideCrostini(
     Profile* profile,
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 9449e474..53c0659a 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -545,8 +545,12 @@
 void VolumeManager::AddSshfsCrostiniVolume(
     const base::FilePath& sshfs_mount_path) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DoMountEvent(chromeos::MOUNT_ERROR_NONE,
-               Volume::CreateForSshfsCrostini(sshfs_mount_path));
+  std::unique_ptr<Volume> volume =
+      Volume::CreateForSshfsCrostini(sshfs_mount_path);
+  // Ignore if volume already exists.
+  if (mounted_volumes_.find(volume->volume_id()) != mounted_volumes_.end())
+    return;
+  DoMountEvent(chromeos::MOUNT_ERROR_NONE, std::move(volume));
 
   // Listen for crostini container shutdown and remove volume.
   crostini::CrostiniManager::GetInstance()->AddShutdownContainerCallback(
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
index ae46fd8..ca4c4b9 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
@@ -272,17 +272,18 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const Disk disk("device1", "", false, "", "", "", "", "", "", "", "", "", "",
-                  chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false, false, true,
-                  false, false, "", "");
+  std::unique_ptr<const Disk> disk =
+      Disk::Builder().SetDevicePath("device1").SetOnBootDevice(true).Build();
 
-  volume_manager()->OnBootDeviceDiskEvent(DiskMountManager::DISK_ADDED, disk);
+  volume_manager()->OnBootDeviceDiskEvent(DiskMountManager::DISK_ADDED, *disk);
   EXPECT_EQ(0U, observer.events().size());
 
-  volume_manager()->OnBootDeviceDiskEvent(DiskMountManager::DISK_REMOVED, disk);
+  volume_manager()->OnBootDeviceDiskEvent(DiskMountManager::DISK_REMOVED,
+                                          *disk);
   EXPECT_EQ(0U, observer.events().size());
 
-  volume_manager()->OnBootDeviceDiskEvent(DiskMountManager::DISK_CHANGED, disk);
+  volume_manager()->OnBootDeviceDiskEvent(DiskMountManager::DISK_CHANGED,
+                                          *disk);
   EXPECT_EQ(0U, observer.events().size());
 
   volume_manager()->RemoveObserver(&observer);
@@ -292,21 +293,19 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const bool kIsHidden = true;
-  const Disk kDisk("device1", "", false, "", "", "", "", "", "", "", "", "", "",
-                   chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false, false, false,
-                   false, kIsHidden, "", "");
+  std::unique_ptr<const Disk> disk =
+      Disk::Builder().SetDevicePath("device1").SetIsHidden(true).Build();
 
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                             kDisk);
+                                             *disk);
   EXPECT_EQ(0U, observer.events().size());
 
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_REMOVED,
-                                             kDisk);
+                                             *disk);
   EXPECT_EQ(0U, observer.events().size());
 
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_CHANGED,
-                                             kDisk);
+                                             *disk);
   EXPECT_EQ(0U, observer.events().size());
 
   volume_manager()->RemoveObserver(&observer);
@@ -319,20 +318,15 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const Disk kEmptyDevicePathDisk("",  // empty device path.
-                                  "", false, "", "", "", "", "", "", "", "", "",
-                                  "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false,
-                                  false, false, false, false, false, "", "");
+  std::unique_ptr<const Disk> empty_device_path_disk = Disk::Builder().Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                             kEmptyDevicePathDisk);
+                                             *empty_device_path_disk);
   EXPECT_EQ(0U, observer.events().size());
 
-  const bool kHasMedia = true;
-  const Disk kMediaDisk("device1", "", false, "", "", "", "", "", "", "", "",
-                        "", "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false,
-                        kHasMedia, false, false, false, "", "");
+  std::unique_ptr<const Disk> media_disk =
+      Disk::Builder().SetDevicePath("device1").SetHasMedia(true).Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                             kMediaDisk);
+                                             *media_disk);
   ASSERT_EQ(1U, observer.events().size());
   const LoggingObserver::Event& event = observer.events()[0];
   EXPECT_EQ(LoggingObserver::Event::DISK_ADDED, event.type);
@@ -359,13 +353,14 @@
     LoggingObserver observer;
     volume_manager()->AddObserver(&observer);
 
-    const bool kHasMedia = true;
-    const Disk kMountedMediaDisk("device1", "mounted", false, "", "", "", "",
-                                 "", "", "", "", "", "",
-                                 chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false,
-                                 kHasMedia, false, false, false, "", "");
+    std::unique_ptr<const Disk> mounted_media_disk =
+        Disk::Builder()
+            .SetDevicePath("device1")
+            .SetMountPath("mounted")
+            .SetHasMedia(true)
+            .Build();
     volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                               kMountedMediaDisk);
+                                               *mounted_media_disk);
     ASSERT_EQ(1U, observer.events().size());
     const LoggingObserver::Event& event = observer.events()[0];
     EXPECT_EQ(LoggingObserver::Event::DISK_ADDED, event.type);
@@ -382,12 +377,10 @@
     LoggingObserver observer;
     volume_manager()->AddObserver(&observer);
 
-    const bool kWithoutMedia = false;
-    const Disk kNoMediaDisk("device1", "", false, "", "", "", "", "", "", "",
-                            "", "", "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false,
-                            false, kWithoutMedia, false, false, false, "", "");
+    std::unique_ptr<const Disk> no_media_disk =
+        Disk::Builder().SetDevicePath("device1").Build();
     volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                               kNoMediaDisk);
+                                               *no_media_disk);
     ASSERT_EQ(1U, observer.events().size());
     const LoggingObserver::Event& event = observer.events()[0];
     EXPECT_EQ(LoggingObserver::Event::DISK_ADDED, event.type);
@@ -406,12 +399,10 @@
     LoggingObserver observer;
     volume_manager()->AddObserver(&observer);
 
-    const bool kHasMedia = true;
-    const Disk kMediaDisk("device1", "", false, "", "", "", "", "", "", "", "",
-                          "", "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false,
-                          false, kHasMedia, false, false, false, "", "");
+    std::unique_ptr<const Disk> media_disk =
+        Disk::Builder().SetDevicePath("device1").SetHasMedia(true).Build();
     volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                               kMediaDisk);
+                                               *media_disk);
     ASSERT_EQ(1U, observer.events().size());
     const LoggingObserver::Event& event = observer.events()[0];
     EXPECT_EQ(LoggingObserver::Event::DISK_ADDED, event.type);
@@ -428,11 +419,12 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const Disk kMountedDisk("device1", "mount_path", false, "", "", "", "", "",
-                          "", "", "", "", "", chromeos::DEVICE_TYPE_UNKNOWN, 0,
-                          false, false, false, false, false, false, "", "");
+  std::unique_ptr<const Disk> mounted_disk = Disk::Builder()
+                                                 .SetDevicePath("device1")
+                                                 .SetMountPath("mount_path")
+                                                 .Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_REMOVED,
-                                             kMountedDisk);
+                                             *mounted_disk);
 
   ASSERT_EQ(1U, observer.events().size());
   const LoggingObserver::Event& event = observer.events()[0];
@@ -452,11 +444,10 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const Disk kNotMountedDisk("device1", "", false, "", "", "", "", "", "", "",
-                             "", "", "", chromeos::DEVICE_TYPE_UNKNOWN, 0,
-                             false, false, false, false, false, false, "", "");
+  std::unique_ptr<const Disk> not_mounted_disk =
+      Disk::Builder().SetDevicePath("device1").Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_REMOVED,
-                                             kNotMountedDisk);
+                                             *not_mounted_disk);
 
   ASSERT_EQ(1U, observer.events().size());
   const LoggingObserver::Event& event = observer.events()[0];
@@ -473,11 +464,10 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const Disk kDisk("device1", "", false, "", "", "", "", "", "", "", "", "", "",
-                   chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false, true, false,
-                   false, false, "", "");
+  std::unique_ptr<const Disk> disk =
+      Disk::Builder().SetDevicePath("device1").SetHasMedia(true).Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_CHANGED,
-                                             kDisk);
+                                             *disk);
 
   EXPECT_EQ(1U, observer.events().size());
   EXPECT_EQ(1U, disk_mount_manager_->mount_requests().size());
@@ -496,11 +486,10 @@
   LoggingObserver observer;
   volume_manager()->AddObserver(&observer);
 
-  const Disk kDisk("device1", "", false, "", "", "", "", "", "", "", "", "", "",
-                   chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false, true, false,
-                   false, false, "", "");
+  std::unique_ptr<const Disk> disk =
+      Disk::Builder().SetDevicePath("device1").SetHasMedia(true).Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_CHANGED,
-                                             kDisk);
+                                             *disk);
 
   EXPECT_EQ(1U, observer.events().size());
   EXPECT_EQ(1U, disk_mount_manager_->mount_requests().size());
@@ -582,10 +571,10 @@
 }
 
 TEST_F(VolumeManagerTest, OnMountEvent_Remounting) {
-  std::unique_ptr<Disk> disk(
-      new Disk("device1", "", false, "", "", "", "", "", "", "", "", "uuid1",
-               "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false, false, false,
-               false, false, "", ""));
+  std::unique_ptr<Disk> disk = Disk::Builder()
+                                   .SetDevicePath("device1")
+                                   .SetFileSystemUUID("uuid1")
+                                   .Build();
   disk_mount_manager_->AddDiskForTest(std::move(disk));
   disk_mount_manager_->MountPath("device1", "", "", {},
                                  chromeos::MOUNT_TYPE_DEVICE,
@@ -777,13 +766,12 @@
   secondary.volume_manager()->AddObserver(&secondary_observer);
 
   // Add 1 disk.
-  const Disk kMediaDisk("device1", "", false, "", "", "", "", "", "", "", "",
-                        "", "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false,
-                        true, false, false, false, "", "");
+  std::unique_ptr<const Disk> media_disk =
+      Disk::Builder().SetDevicePath("device1").SetHasMedia(true).Build();
   volume_manager()->OnAutoMountableDiskEvent(DiskMountManager::DISK_ADDED,
-                                             kMediaDisk);
+                                             *media_disk);
   secondary.volume_manager()->OnAutoMountableDiskEvent(
-      DiskMountManager::DISK_ADDED, kMediaDisk);
+      DiskMountManager::DISK_ADDED, *media_disk);
 
   // The profile with external storage enabled should have mounted the volume.
   bool has_volume_mounted = false;
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc
index 89517f36..322dc7a 100644
--- a/chrome/browser/chromeos/first_run/first_run.cc
+++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h"
@@ -33,7 +33,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/notification_observer.h"
@@ -42,6 +41,7 @@
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace chromeos {
@@ -124,14 +124,15 @@
 
     // Whether the account is supported for voice interaction.
     bool account_supported = false;
-    SigninManagerBase* signin_manager =
-        SigninManagerFactory::GetForProfile(profile_);
-    if (signin_manager) {
+    identity::IdentityManager* identity_manager =
+        IdentityManagerFactory::GetForProfile(profile_);
+    if (identity_manager) {
       std::string hosted_domain =
-          signin_manager->GetAuthenticatedAccountInfo().hosted_domain;
+          identity_manager->GetPrimaryAccountInfo().hosted_domain;
       if (hosted_domain == AccountTrackerService::kNoHostedDomainFound ||
-          hosted_domain == "google.com")
+          hosted_domain == "google.com") {
         account_supported = true;
+      }
     }
 
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
index 61ff70de..0d7121f 100644
--- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -6,26 +6,23 @@
 
 #include "base/command_line.h"
 #include "base/location.h"
-#include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/active_directory_test_helper.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/test/js_checker.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/settings/stub_install_attributes.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
-#include "chrome/common/chrome_paths.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
-#include "chromeos/chromeos_paths.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
@@ -48,7 +45,6 @@
 
 constexpr char kAdOfflineAuthId[] = "offline-ad-auth";
 
-constexpr char kAdMachineName[] = "machine_name";
 constexpr char kTestActiveDirectoryUser[] = "test-user";
 constexpr char kTestUserRealm[] = "user.realm";
 constexpr char kAdMachineInput[] = "machineNameInput";
@@ -67,35 +63,9 @@
 constexpr char kAdNewPassword2Input[] = "newPassword2";
 constexpr char kNewPassword[] = "new_password";
 constexpr char kDifferentNewPassword[] = "different_new_password";
-constexpr char kDMToken[] = "dm_token";
 
 constexpr char kCloseButtonId[] = "closeButton";
 
-class TestAuthPolicyClient : public FakeAuthPolicyClient {
- public:
-  TestAuthPolicyClient() { FakeAuthPolicyClient::SetStarted(true); }
-
-  void AuthenticateUser(const authpolicy::AuthenticateUserRequest& request,
-                        int password_fd,
-                        AuthCallback callback) override {
-    authpolicy::ActiveDirectoryAccountInfo account_info;
-    if (auth_error_ == authpolicy::ERROR_NONE) {
-      if (request.account_id().empty()) {
-        account_info.set_account_id(
-            base::MD5String(request.user_principal_name()));
-      } else {
-        account_info.set_account_id(request.account_id());
-      }
-    }
-    base::SequencedTaskRunnerHandle::Get()->PostNonNestableTask(
-        FROM_HERE,
-        base::BindOnce(std::move(callback), auth_error_, account_info));
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestAuthPolicyClient);
-};
-
 class ActiveDirectoryLoginTest : public LoginManagerTest {
  public:
   ActiveDirectoryLoginTest()
@@ -107,23 +77,24 @@
 
   ~ActiveDirectoryLoginTest() override = default;
 
-  void SetUp() override {
-    SetupTestAuthPolicyClient();
-    LoginManagerTest::SetUp();
-  }
-
   void SetUpInProcessBrowserTestFixture() override {
     LoginManagerTest::SetUpInProcessBrowserTestFixture();
-    base::FilePath user_data_dir;
-    ASSERT_TRUE(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
-    chromeos::RegisterStubPathOverrides(user_data_dir);
+
+    auto fake_client = std::make_unique<FakeAuthPolicyClient>();
+    fake_auth_policy_client_ = fake_client.get();
+    fake_auth_policy_client_->DisableOperationDelayForTesting();
+    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
+        std::move(fake_client));
+
+    // Note: FakeCryptohomeClient needs paths to be set to load install attribs.
+    active_directory_test_helper::OverridePaths();
     DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
         std::make_unique<FakeCryptohomeClient>());
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitch(switches::kOobeSkipPostLogin);
     LoginManagerTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kOobeSkipPostLogin);
   }
 
   void SetUpOnMainThread() override {
@@ -134,41 +105,13 @@
         ->GetOobeUI()
         ->signin_screen_handler()
         ->SetOfflineTimeoutForTesting(base::TimeDelta::Max());
-    fake_auth_policy_client()->DisableOperationDelayForTesting();
     LoginManagerTest::SetUpOnMainThread();
   }
 
   void MarkAsActiveDirectoryEnterprise() {
     StartupUtils::MarkOobeCompleted();
-    AuthPolicyLoginHelper helper;
-    {
-      base::RunLoop loop;
-      helper.set_dm_token(kDMToken);
-      helper.JoinAdDomain(
-          kAdMachineName, "" /* distinguished_name */,
-          authpolicy::KerberosEncryptionTypes::ENC_TYPES_STRONG,
-          kTestActiveDirectoryUser + ("@" + test_realm_), "" /* password */,
-          base::BindOnce(
-              [](base::OnceClosure closure, const std::string& expected_domain,
-                 authpolicy::ErrorType error, const std::string& domain) {
-                EXPECT_EQ(authpolicy::ERROR_NONE, error);
-                EXPECT_EQ(expected_domain, domain);
-                std::move(closure).Run();
-              },
-              loop.QuitClosure(), test_realm_));
-      loop.Run();
-    }
-    ASSERT_TRUE(tpm_util::LockDeviceActiveDirectoryForTesting(test_realm_));
-    {
-      base::RunLoop loop;
-      fake_auth_policy_client()->RefreshDevicePolicy(base::BindOnce(
-          [](base::OnceClosure closure, authpolicy::ErrorType error) {
-            EXPECT_EQ(authpolicy::ERROR_NONE, error);
-            std::move(closure).Run();
-          },
-          loop.QuitClosure()));
-      loop.Run();
-    }
+    active_directory_test_helper::PrepareLogin(kTestActiveDirectoryUser +
+                                               ("@" + test_realm_));
   }
 
   void TriggerPasswordChangeScreen() {
@@ -187,13 +130,6 @@
                           ".fire('tap')");
   }
 
-  void SetupTestAuthPolicyClient() {
-    auto test_client = std::make_unique<TestAuthPolicyClient>();
-    fake_auth_policy_client_ = test_client.get();
-    DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
-        std::move(test_client));
-  }
-
   // Checks if Active Directory login is visible.
   void TestLoginVisible() {
     OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_GAIA_SIGNIN);
@@ -337,7 +273,7 @@
     return "document.querySelector('#" + parent_id + " /deep/ #" + element_id +
            "')";
   }
-  TestAuthPolicyClient* fake_auth_policy_client() {
+  FakeAuthPolicyClient* fake_auth_policy_client() {
     return fake_auth_policy_client_;
   }
 
@@ -345,7 +281,7 @@
   std::string autocomplete_realm_;
 
  private:
-  TestAuthPolicyClient* fake_auth_policy_client_;
+  FakeAuthPolicyClient* fake_auth_policy_client_;
 
   DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryLoginTest);
 };
@@ -354,13 +290,13 @@
  public:
   ActiveDirectoryLoginAutocompleteTest() = default;
   void SetUpInProcessBrowserTestFixture() override {
+    ActiveDirectoryLoginTest::SetUpInProcessBrowserTestFixture();
+
     enterprise_management::ChromeDeviceSettingsProto device_settings;
     device_settings.mutable_login_screen_domain_auto_complete()
         ->set_login_screen_domain_auto_complete(kTestUserRealm);
     fake_auth_policy_client()->set_device_policy(device_settings);
     autocomplete_realm_ = kTestUserRealm;
-
-    ActiveDirectoryLoginTest::SetUpInProcessBrowserTestFixture();
   }
 
  private:
@@ -369,13 +305,16 @@
 
 }  // namespace
 
-// Marks as Active Directory enterprise device and OOBE as completed.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PRE_LoginSuccess) {
-  MarkAsActiveDirectoryEnterprise();
-}
+// Declares a PRE_ test that calls MarkAsActiveDirectoryEnterprise() and the
+// test itself.
+#define IN_PROC_BROWSER_TEST_F_WITH_PRE(class_name, test_name) \
+  IN_PROC_BROWSER_TEST_F(class_name, PRE_##test_name) {        \
+    MarkAsActiveDirectoryEnterprise();                         \
+  }                                                            \
+  IN_PROC_BROWSER_TEST_F(class_name, test_name)
 
 // Test successful Active Directory login.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, LoginSuccess) {
+IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, LoginSuccess) {
   TestNoError();
   TestDomainVisible();
 
@@ -386,13 +325,8 @@
   session_start_waiter.Wait();
 }
 
-// Marks as Active Directory enterprise device and OOBE as completed.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PRE_LoginErrors) {
-  MarkAsActiveDirectoryEnterprise();
-}
-
 // Test different UI errors for Active Directory login.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, LoginErrors) {
+IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, LoginErrors) {
   SetupActiveDirectoryJSNotifications();
   TestNoError();
   TestDomainVisible();
@@ -433,14 +367,9 @@
   TestDomainVisible();
 }
 
-// Marks as Active Directory enterprise device and OOBE as completed.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest,
-                       PRE_PasswordChange_LoginSuccess) {
-  MarkAsActiveDirectoryEnterprise();
-}
-
 // Test successful Active Directory login from the password change screen.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PasswordChange_LoginSuccess) {
+IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest,
+                                PasswordChange_LoginSuccess) {
   TestLoginVisible();
   TestDomainVisible();
 
@@ -456,13 +385,9 @@
   session_start_waiter.Wait();
 }
 
-// Marks as Active Directory enterprise device and OOBE as completed.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PRE_PasswordChange_UIErrors) {
-  MarkAsActiveDirectoryEnterprise();
-}
-
 // Test different UI errors for Active Directory password change screen.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PasswordChange_UIErrors) {
+IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest,
+                                PasswordChange_UIErrors) {
   TestLoginVisible();
   TestDomainVisible();
 
@@ -492,15 +417,9 @@
   TestAdPasswordChangeError(kAdOldPasswordInput);
 }
 
-// Marks as Active Directory enterprise device and OOBE as completed.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest,
-                       PRE_PasswordChange_ReopenClearErrors) {
-  MarkAsActiveDirectoryEnterprise();
-}
-
 // Test reopening Active Directory password change screen clears errors.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest,
-                       PasswordChange_ReopenClearErrors) {
+IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest,
+                                PasswordChange_ReopenClearErrors) {
   TestLoginVisible();
   TestDomainVisible();
 
@@ -515,17 +434,14 @@
   TriggerPasswordChangeScreen();
 }
 
-// Marks as Active Directory enterprise device and OOBE as completed.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginAutocompleteTest,
-                       PRE_TestAutocomplete) {
-  MarkAsActiveDirectoryEnterprise();
-}
-
 // Tests that DeviceLoginScreenDomainAutoComplete policy overrides device realm
 // for user autocomplete.
-IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginAutocompleteTest, TestAutocomplete) {
+IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginAutocompleteTest,
+                                TestAutocomplete) {
   TestLoginVisible();
   TestDomainVisible();
 }
 
+#undef IN_PROC_BROWSER_TEST_F_WITH_PRE
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/active_directory_test_helper.cc b/chrome/browser/chromeos/login/active_directory_test_helper.cc
new file mode 100644
index 0000000..7b187c67
--- /dev/null
+++ b/chrome/browser/chromeos/login/active_directory_test_helper.cc
@@ -0,0 +1,93 @@
+// 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/chromeos/login/active_directory_test_helper.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/string_split.h"
+#include "chrome/common/chrome_paths.h"
+#include "chromeos/chromeos_paths.h"
+#include "chromeos/dbus/auth_policy_client.h"
+#include "chromeos/dbus/authpolicy/active_directory_info.pb.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/upstart_client.h"
+#include "chromeos/dbus/util/tpm_util.h"
+#include "chromeos/login/auth/authpolicy_login_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace active_directory_test_helper {
+
+namespace {
+
+constexpr char kAdMachineName[] = "ad-machine-name";
+constexpr char kDmToken[] = "dm-token";
+
+}  // namespace
+
+void PrepareLogin(const std::string& user_principal_name) {
+  std::vector<std::string> user_and_domain = base::SplitString(
+      user_principal_name, "@", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(2u, user_and_domain.size());
+
+  // Start the D-Bus service.
+  chromeos::DBusThreadManager::Get()
+      ->GetUpstartClient()
+      ->StartAuthPolicyService();
+
+  // Join the AD domain.
+  chromeos::AuthPolicyLoginHelper helper;
+  {
+    base::RunLoop loop;
+    helper.set_dm_token(kDmToken);
+    helper.JoinAdDomain(
+        kAdMachineName, "" /* distinguished_name */,
+        authpolicy::KerberosEncryptionTypes::ENC_TYPES_STRONG,
+        user_principal_name, "" /* password */,
+        base::BindOnce(
+            [](base::OnceClosure closure, const std::string& expected_domain,
+               authpolicy::ErrorType error, const std::string& domain) {
+              EXPECT_EQ(authpolicy::ERROR_NONE, error);
+              EXPECT_EQ(expected_domain, domain);
+              std::move(closure).Run();
+            },
+            loop.QuitClosure(), user_and_domain[1]));
+    loop.Run();
+  }
+
+  // Lock the device to AD mode. Paths need to be set here, so install attribs
+  // can be saved to disk.
+  OverridePaths();
+  ASSERT_TRUE(
+      tpm_util::LockDeviceActiveDirectoryForTesting(user_and_domain[1]));
+
+  // Fetch device policy.
+  {
+    base::RunLoop run_loop;
+    chromeos::DBusThreadManager::Get()
+        ->GetAuthPolicyClient()
+        ->RefreshDevicePolicy(base::BindOnce(
+            [](base::OnceClosure quit_closure, authpolicy::ErrorType error) {
+              EXPECT_EQ(authpolicy::ERROR_NONE, error);
+              std::move(quit_closure).Run();
+            },
+            run_loop.QuitClosure()));
+    run_loop.Run();
+  }
+}
+
+void OverridePaths() {
+  base::FilePath user_data_dir;
+  ASSERT_TRUE(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
+  RegisterStubPathOverrides(user_data_dir);
+}
+
+}  // namespace active_directory_test_helper
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/active_directory_test_helper.h b/chrome/browser/chromeos/login/active_directory_test_helper.h
new file mode 100644
index 0000000..fe96562
--- /dev/null
+++ b/chrome/browser/chromeos/login/active_directory_test_helper.h
@@ -0,0 +1,26 @@
+// 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_CHROMEOS_LOGIN_ACTIVE_DIRECTORY_TEST_HELPER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_ACTIVE_DIRECTORY_TEST_HELPER_H_
+
+#include <string>
+
+namespace chromeos {
+
+namespace active_directory_test_helper {
+
+// Starts AuthPolicyService, joins the Active Directory domain using
+// |user_principal_name| for authentication (user@example.com), locks the device
+// to Active Directory mode and fetches device policy.
+void PrepareLogin(const std::string& user_principal_name);
+
+// Sets stub path overrides.
+void OverridePaths();
+
+}  // namespace active_directory_test_helper
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_ACTIVE_DIRECTORY_TEST_HELPER_H_
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc
index e5946c2..ef4df2a 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.cc
@@ -11,6 +11,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
@@ -229,9 +230,9 @@
                        weak_ptr_factory_.GetWeakPtr()));
     return;
   }
-  Reset();
-  if (!on_setup_success_.is_null())
-    std::move(on_setup_success_).Run();
+  StartupUtils::MarkDeviceRegistered(
+      base::BindOnce(&DemoSetupController::OnDeviceRegistered,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void DemoSetupController::OnMultipleLicensesAvailable(
@@ -299,6 +300,13 @@
   device_local_account_policy_store_->Store(policy);
 }
 
+void DemoSetupController::OnDeviceRegistered() {
+  VLOG(1) << "Demo mode setup finished successfully.";
+  Reset();
+  if (!on_setup_success_.is_null())
+    std::move(on_setup_success_).Run();
+}
+
 void DemoSetupController::SetupFailed(const std::string& message,
                                       DemoSetupError error) {
   Reset();
@@ -322,9 +330,9 @@
 
 void DemoSetupController::OnStoreLoaded(policy::CloudPolicyStore* store) {
   DCHECK_EQ(store, device_local_account_policy_store_);
-  Reset();
-  if (!on_setup_success_.is_null())
-    std::move(on_setup_success_).Run();
+  StartupUtils::MarkDeviceRegistered(
+      base::BindOnce(&DemoSetupController::OnDeviceRegistered,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void DemoSetupController::OnStoreError(policy::CloudPolicyStore* store) {
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h
index 74cfda3d..bf36212 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h
+++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h
@@ -103,6 +103,10 @@
   // loaded.
   void OnDeviceLocalAccountPolicyLoaded(base::Optional<std::string> blob);
 
+  // Called when device is marked as registered and the second part of OOBE flow
+  // is completed. This is the last step of demo mode setup flow.
+  void OnDeviceRegistered();
+
   // Finish the flow with an error message.
   void SetupFailed(const std::string& message, DemoSetupError error);
 
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller_unittest.cc b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller_unittest.cc
index a73566c..67eabad 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_setup_controller_unittest.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_controller_unittest.cc
@@ -15,6 +15,8 @@
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_setup_test_utils.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
+#include "chrome/test/base/scoped_testing_local_state.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
@@ -81,7 +83,8 @@
 
 class DemoSetupControllerTest : public testing::Test {
  protected:
-  DemoSetupControllerTest() = default;
+  DemoSetupControllerTest()
+      : testing_local_state_(TestingBrowserProcess::GetGlobal()) {}
   ~DemoSetupControllerTest() override = default;
 
   void SetUp() override {
@@ -103,6 +106,7 @@
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
+  ScopedTestingLocalState testing_local_state_;
 
   DISALLOW_COPY_AND_ASSIGN(DemoSetupControllerTest);
 };
diff --git a/chrome/browser/chromeos/login/demo_setup_browsertest.cc b/chrome/browser/chromeos/login/demo_setup_browsertest.cc
index 2ee0b1a..7b291920 100644
--- a/chrome/browser/chromeos/login/demo_setup_browsertest.cc
+++ b/chrome/browser/chromeos/login/demo_setup_browsertest.cc
@@ -506,6 +506,8 @@
   // needed to be able to check it reliably.
 
   OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  EXPECT_TRUE(StartupUtils::IsOobeCompleted());
+  EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, OnlineSetupFlowError) {
@@ -554,6 +556,8 @@
   // needed to be able to check it reliably.
   WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
                       DemoSetupDialog::kError);
+  EXPECT_FALSE(StartupUtils::IsOobeCompleted());
+  EXPECT_FALSE(StartupUtils::IsDeviceRegistered());
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, OfflineSetupFlowSuccess) {
@@ -597,6 +601,8 @@
   // needed to be able to check it reliably.
 
   OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
+  EXPECT_TRUE(StartupUtils::IsOobeCompleted());
+  EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, OfflineSetupFlowError) {
@@ -639,6 +645,9 @@
   // needed to be able to check it reliably.
   WaitForScreenDialog(OobeScreen::SCREEN_OOBE_DEMO_SETUP,
                       DemoSetupDialog::kError);
+
+  EXPECT_FALSE(StartupUtils::IsOobeCompleted());
+  EXPECT_FALSE(StartupUtils::IsDeviceRegistered());
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupTest, NextDisabledOnNetworkScreen) {
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index 4ee61db..0c5f958 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -35,7 +35,6 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_auth_policy_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_names.h"
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index a9ea5d0..437cfbe 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -107,8 +107,8 @@
 using net::test_server::BasicHttpResponse;
 using net::test_server::HttpRequest;
 using net::test_server::HttpResponse;
-using testing::Return;
 using testing::_;
+using testing::Return;
 
 namespace chromeos {
 
@@ -1078,8 +1078,9 @@
   // Initialize device policy.
   std::set<std::string> device_affiliation_ids;
   device_affiliation_ids.insert(kAffiliationID);
-  policy::affiliation_test_helper::SetDeviceAffiliationID(
-      &test_helper_, fake_session_manager_client_, device_affiliation_ids);
+  policy::affiliation_test_helper::SetDeviceAffiliationIDs(
+      &test_helper_, fake_session_manager_client_,
+      nullptr /* fake_auth_policy_client */, device_affiliation_ids);
 
   // Initialize user policy.
   EXPECT_CALL(provider_, IsInitializationComplete(_))
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
index bba09fe..a98c3f9 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.cc
@@ -8,18 +8,19 @@
 
 #include "base/logging.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/consent_auditor/consent_auditor_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/browser_sync/profile_sync_service.h"
+#include "components/consent_auditor/consent_auditor.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/signin_manager.h"
 #include "components/user_manager/user_manager.h"
 
 namespace chromeos {
 namespace {
 
-constexpr const char kUserActionConinueAndReview[] = "continue-and-review";
-constexpr const char kUserActionContinueWithDefaults[] =
-    "continue-with-defaults";
 constexpr const char kUserActionContinueWithSyncOnly[] =
     "continue-with-sync-only";
 constexpr const char kUserActionContinueWithSyncAndPersonalization[] =
@@ -75,16 +76,6 @@
 }
 
 void SyncConsentScreen::OnUserAction(const std::string& action_id) {
-  if (action_id == kUserActionConinueAndReview) {
-    profile_->GetPrefs()->SetBoolean(prefs::kShowSyncSettingsOnSessionStart,
-                                     true);
-    Finish(ScreenExitCode::SYNC_CONSENT_FINISHED);
-    return;
-  }
-  if (action_id == kUserActionContinueWithDefaults) {
-    Finish(ScreenExitCode::SYNC_CONSENT_FINISHED);
-    return;
-  }
   if (action_id == kUserActionContinueWithSyncOnly) {
     // TODO(alemate) https://crbug.com/822889
     Finish(ScreenExitCode::SYNC_CONSENT_FINISHED);
@@ -102,6 +93,32 @@
   UpdateScreen();
 }
 
+void SyncConsentScreen::OnContinueAndReview(
+    const std::vector<int>& consent_description,
+    const int consent_confirmation) {
+  RecordConsent(consent_description, consent_confirmation);
+  profile_->GetPrefs()->SetBoolean(prefs::kShowSyncSettingsOnSessionStart,
+                                   true);
+  Finish(ScreenExitCode::SYNC_CONSENT_FINISHED);
+}
+
+void SyncConsentScreen::OnContinueWithDefaults(
+    const std::vector<int>& consent_description,
+    const int consent_confirmation) {
+  RecordConsent(consent_description, consent_confirmation);
+  Finish(ScreenExitCode::SYNC_CONSENT_FINISHED);
+}
+
+void SyncConsentScreen::SetDelegateForTesting(
+    SyncConsentScreen::SyncConsentScreenTestDelegate* delegate) {
+  test_delegate_ = delegate;
+}
+
+SyncConsentScreen::SyncConsentScreenTestDelegate*
+SyncConsentScreen::GetDelegateForTesting() const {
+  return test_delegate_;
+}
+
 SyncConsentScreen::SyncScreenBehavior SyncConsentScreen::GetSyncScreenBehavior()
     const {
   // Skip for users without Gaia account.
@@ -126,14 +143,10 @@
   }
 
   // Skip for sync-disabled case.
-  const browser_sync::ProfileSyncService* sync_service =
-      GetSyncService(profile_);
-  if (sync_service->HasDisableReason(
-          syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY)) {
+  if (IsProfileSyncDisabledByPolicy())
     return SyncScreenBehavior::SKIP;
-  }
 
-  if (sync_service->IsEngineInitialized())
+  if (IsProfileSyncEngineInitialized())
     return SyncScreenBehavior::SHOW;
 
   return SyncScreenBehavior::UNKNOWN;
@@ -160,4 +173,52 @@
   }
 }
 
+void SyncConsentScreen::RecordConsent(
+    const std::vector<int>& consent_description,
+    const int consent_confirmation) {
+  consent_auditor::ConsentAuditor* consent_auditor =
+      ConsentAuditorFactory::GetForProfile(profile_);
+  const std::string& google_account_id =
+      SigninManagerFactory::GetForProfile(profile_)
+          ->GetAuthenticatedAccountId();
+  // TODO(alemate): Support unified_consent_enabled
+  sync_pb::UserConsentTypes::SyncConsent sync_consent;
+  sync_consent.set_confirmation_grd_id(consent_confirmation);
+  for (int id : consent_description) {
+    sync_consent.add_description_grd_ids(id);
+  }
+  sync_consent.set_status(sync_pb::UserConsentTypes::ConsentStatus::
+                              UserConsentTypes_ConsentStatus_GIVEN);
+  consent_auditor->RecordSyncConsent(google_account_id, sync_consent);
+
+  if (test_delegate_) {
+    test_delegate_->OnConsentRecordedIds(consent_description,
+                                         consent_confirmation);
+  }
+}
+
+bool SyncConsentScreen::IsProfileSyncDisabledByPolicy() const {
+  if (test_sync_disabled_by_policy_.has_value())
+    return test_sync_disabled_by_policy_.value();
+  const browser_sync::ProfileSyncService* sync_service =
+      GetSyncService(profile_);
+  return sync_service->HasDisableReason(
+      syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY);
+}
+
+bool SyncConsentScreen::IsProfileSyncEngineInitialized() const {
+  if (test_sync_engine_initialized_.has_value())
+    return test_sync_engine_initialized_.value();
+  const browser_sync::ProfileSyncService* sync_service =
+      GetSyncService(profile_);
+  return sync_service->IsEngineInitialized();
+}
+
+void SyncConsentScreen::SetProfileSyncDisabledByPolicyForTesting(bool value) {
+  test_sync_disabled_by_policy_ = value;
+}
+void SyncConsentScreen::SetProfileSyncEngineInitializedForTesting(bool value) {
+  test_sync_engine_initialized_ = value;
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_screen.h b/chrome/browser/chromeos/login/screens/sync_consent_screen.h
index 36e58fc..a32f534 100644
--- a/chrome/browser/chromeos/login/screens/sync_consent_screen.h
+++ b/chrome/browser/chromeos/login/screens/sync_consent_screen.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
 #include "chrome/browser/chromeos/login/screens/sync_consent_screen_view.h"
 #include "components/sync/driver/sync_service_observer.h"
@@ -32,6 +33,26 @@
   };
 
  public:
+  class SyncConsentScreenTestDelegate {
+   public:
+    SyncConsentScreenTestDelegate() = default;
+
+    // This is called from SyncConsentScreen when user consent is passed to
+    // consent auditor with resource ids recorder as consent.
+    virtual void OnConsentRecordedIds(
+        const std::vector<int>& consent_description,
+        const int consent_confirmation) = 0;
+
+    // This is called from SyncConsentScreenHandler when user consent is passed
+    // to consent auditor with resource strings recorder as consent.
+    virtual void OnConsentRecordedStrings(
+        const ::login::StringList& consent_description,
+        const std::string& consent_confirmation) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(SyncConsentScreenTestDelegate);
+  };
+
   SyncConsentScreen(BaseScreenDelegate* base_screen_delegate,
                     SyncConsentScreenView* view);
   ~SyncConsentScreen() override;
@@ -44,6 +65,25 @@
   // syncer::SyncServiceObserver:
   void OnStateChanged(syncer::SyncService* sync) override;
 
+  // Reacts to "Continue and review settings after sign-in"
+  void OnContinueAndReview(const std::vector<int>& consent_description,
+                           const int consent_confirmation);
+
+  // Reacts to "Continue with default settings"
+  void OnContinueWithDefaults(const std::vector<int>& consent_description,
+                              const int consent_confirmation);
+
+  // Sets internal condition "Sync disabled by policy" for tests.
+  void SetProfileSyncDisabledByPolicyForTesting(bool value);
+
+  // Sets internal condition "Sync engine initialized" for tests.
+  void SetProfileSyncEngineInitializedForTesting(bool value);
+
+  // Test API.
+  void SetDelegateForTesting(
+      SyncConsentScreen::SyncConsentScreenTestDelegate* delegate);
+  SyncConsentScreenTestDelegate* GetDelegateForTesting() const;
+
  private:
   // Returns new SyncScreenBehavior value.
   SyncScreenBehavior GetSyncScreenBehavior() const;
@@ -51,6 +91,16 @@
   // Calculates updated |behavior_| and performs required update actions.
   void UpdateScreen();
 
+  // Records user Sync consent.
+  void RecordConsent(const std::vector<int>& consent_description,
+                     const int consent_confirmation);
+
+  // Returns true if profile sync is disabled by policy.
+  bool IsProfileSyncDisabledByPolicy() const;
+
+  // Returns true if profile sync has finished initialization.
+  bool IsProfileSyncEngineInitialized() const;
+
   // Controls screen appearance.
   // Spinner is shown until sync status has been decided.
   SyncScreenBehavior behavior_ = UNKNOWN;
@@ -64,6 +114,12 @@
   // True when screen is shown.
   bool shown_ = false;
 
+  base::Optional<bool> test_sync_disabled_by_policy_;
+  base::Optional<bool> test_sync_engine_initialized_;
+
+  // Notify tests.
+  SyncConsentScreenTestDelegate* test_delegate_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(SyncConsentScreen);
 };
 
diff --git a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
new file mode 100644
index 0000000..c2138a9f
--- /dev/null
+++ b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
@@ -0,0 +1,244 @@
+// 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 "base/command_line.h"
+#include "base/macros.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/screens/gaia_view.h"
+#include "chrome/browser/chromeos/login/screens/sync_consent_screen.h"
+#include "chrome/browser/chromeos/login/test/js_checker.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
+#include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/notification_service.h"
+
+namespace chromeos {
+namespace {
+constexpr base::TimeDelta kJsConditionCheckFrequency =
+    base::TimeDelta::FromMilliseconds(2000);
+}  // anonymous namespace
+
+class ConsentRecordedWaiter
+    : public SyncConsentScreen::SyncConsentScreenTestDelegate {
+ public:
+  ConsentRecordedWaiter() = default;
+
+  void Wait() {
+    if (!consent_description_strings_.empty())
+      return;
+
+    run_loop_.Run();
+  }
+
+  // SyncConsentScreen::SyncConsentScreenTestDelegate
+  void OnConsentRecordedIds(const std::vector<int>& consent_description,
+                            const int consent_confirmation) override {
+    consent_description_ids_ = consent_description;
+    consent_confirmation_id_ = consent_confirmation;
+  }
+
+  void OnConsentRecordedStrings(
+      const ::login::StringList& consent_description,
+      const std::string& consent_confirmation) override {
+    consent_description_strings_ = consent_description;
+    consent_confirmation_string_ = consent_confirmation;
+
+    // SyncConsentScreenHandler::SyncConsentScreenHandlerTestDelegate is
+    // notified after SyncConsentScreen::SyncConsentScreenTestDelegate, so
+    // this is the only place where we need to quit loop.
+    run_loop_.Quit();
+  }
+
+  const std::vector<int>& get_consent_description_ids() const {
+    return consent_description_ids_;
+  }
+  int get_consent_confirmation_id() const { return consent_confirmation_id_; }
+  const ::login::StringList& get_consent_description_strings() const {
+    return consent_description_strings_;
+  }
+  const std::string& get_consent_confirmation_string() const {
+    return consent_confirmation_string_;
+  }
+
+ private:
+  std::vector<int> consent_description_ids_;
+  int consent_confirmation_id_;
+
+  ::login::StringList consent_description_strings_;
+  std::string consent_confirmation_string_;
+
+  base::RunLoop run_loop_;
+};
+
+// Waits for js condition to be fulfilled.
+class JsConditionWaiter {
+ public:
+  JsConditionWaiter(const test::JSChecker& js_checker,
+                    const std::string& js_condition)
+      : js_checker_(js_checker), js_condition_(js_condition) {}
+
+  ~JsConditionWaiter() = default;
+
+  void Wait() {
+    if (IsConditionFulfilled())
+      return;
+
+    timer_.Start(FROM_HERE, kJsConditionCheckFrequency, this,
+                 &JsConditionWaiter::CheckCondition);
+    run_loop_.Run();
+  }
+
+ private:
+  bool IsConditionFulfilled() { return js_checker_.GetBool(js_condition_); }
+
+  void CheckCondition() {
+    if (IsConditionFulfilled()) {
+      run_loop_.Quit();
+      timer_.Stop();
+    }
+  }
+
+  test::JSChecker js_checker_;
+  const std::string js_condition_;
+
+  base::RepeatingTimer timer_;
+  base::RunLoop run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsConditionWaiter);
+};
+
+class SyncConsentTest : public OobeBaseTest {
+ public:
+  SyncConsentTest() = default;
+  ~SyncConsentTest() override = default;
+
+  void TearDownOnMainThread() override {
+    // If the login display is still showing, exit gracefully.
+    if (LoginDisplayHost::default_host()) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::BindOnce(&chrome::AttemptExit));
+      RunUntilBrowserProcessQuits();
+    }
+
+    OobeBaseTest::TearDownOnMainThread();
+  }
+
+  void LoginToSyncConsentScreen() {
+    content::WindowedNotificationObserver observer(
+        chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+        content::NotificationService::AllSources());
+    WizardController::default_controller()->SkipToLoginForTesting(
+        LoginScreenContext());
+    observer.Wait();
+    WaitForGaiaPageEvent("ready");
+
+    LoginDisplayHost::default_host()
+        ->GetOobeUI()
+        ->GetGaiaScreenView()
+        ->ShowSigninScreenForTest(OobeBaseTest::kFakeUserEmail,
+                                  OobeBaseTest::kFakeUserPassword,
+                                  OobeBaseTest::kEmptyUserServices);
+
+    JsConditionWaiter(js_checker_,
+                      "Oobe.getInstance().currentScreen.id == 'sync-consent'")
+        .Wait();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncConsentTest);
+};
+
+IN_PROC_BROWSER_TEST_F(SyncConsentTest, SyncConsentRecorder) {
+  LoginToSyncConsentScreen();
+
+  SyncConsentScreen* screen = static_cast<SyncConsentScreen*>(
+      WizardController::default_controller()->GetScreen(
+          OobeScreen::SCREEN_SYNC_CONSENT));
+  ConsentRecordedWaiter consent_recorded_waiter;
+  screen->SetDelegateForTesting(&consent_recorded_waiter);
+
+  screen->SetProfileSyncDisabledByPolicyForTesting(false);
+  screen->SetProfileSyncEngineInitializedForTesting(true);
+  screen->OnStateChanged(nullptr);
+
+  JsConditionWaiter(js_checker_, "!$('sync-consent-impl').hidden").Wait();
+  JsExpect("!$('sync-consent-impl').$.syncConsentOverviewDialog.hidden");
+  JS().Evaluate(
+      "$('sync-consent-impl').$. settingsSaveAndContinueButton.click()");
+  consent_recorded_waiter.Wait();
+  screen->SetDelegateForTesting(nullptr);  // cleanup
+
+  const std::vector<std::string> expected_consent_strings(
+      {"You're signed in!", "Chrome sync",
+       "Your bookmarks, history, passwords, and other settings will be synced "
+       "to your Google Account so you can use them on all your devices.",
+       "Personalize Google services",
+       "Google may use your browsing history to personalize Search, ads, and "
+       "other Google services. You can change this anytime at "
+       "myaccount.google.com/activitycontrols/search",
+       "Review sync options following setup", "Accept and continue"});
+
+  const std::vector<int> expected_consent_ids({
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_TITLE,
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_NAME,
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_DESCRIPTION,
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_NAME,
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_DESCRIPTION,
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_REVIEW_SYNC_OPTIONS_LATER,
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE,
+  });
+
+  const std::string expected_consent_confirmation_string =
+      "Accept and continue";
+  const int expected_consent_confirmation_id =
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE;
+
+  EXPECT_EQ(expected_consent_strings,
+            consent_recorded_waiter.get_consent_description_strings());
+  EXPECT_EQ(expected_consent_confirmation_string,
+            consent_recorded_waiter.get_consent_confirmation_string());
+  EXPECT_EQ(expected_consent_ids,
+            consent_recorded_waiter.get_consent_description_ids());
+  EXPECT_EQ(expected_consent_confirmation_id,
+            consent_recorded_waiter.get_consent_confirmation_id());
+}
+
+// Check that policy-disabled sync does not trigger SyncConsent screen.
+//
+// We need to check that "disabled by policy" disables SyncConsent screen
+// independently from sync engine statis. So we run test twice, both for "sync
+// engine not yet initialized" and "sync engine initialized" cases. Therefore
+// we use WithParamInterface<bool> here.
+class SyncConsenPolicyDisabledTest : public SyncConsentTest,
+                                     public testing::WithParamInterface<bool> {
+};
+
+IN_PROC_BROWSER_TEST_P(SyncConsenPolicyDisabledTest,
+                       SyncConsentPolicyDisabled) {
+  LoginToSyncConsentScreen();
+
+  SyncConsentScreen* screen = static_cast<SyncConsentScreen*>(
+      WizardController::default_controller()->GetScreen(
+          OobeScreen::SCREEN_SYNC_CONSENT));
+  ConsentRecordedWaiter consent_recorded_waiter;
+  screen->SetDelegateForTesting(&consent_recorded_waiter);
+
+  screen->SetProfileSyncDisabledByPolicyForTesting(true);
+  screen->SetProfileSyncEngineInitializedForTesting(GetParam());
+  screen->OnStateChanged(nullptr);
+
+  // Expect to see "user image selection" or some other screen here.
+  JsConditionWaiter(js_checker_,
+                    "Oobe.getInstance().currentScreen.id != 'sync-consent'")
+      .Wait();
+}
+
+INSTANTIATE_TEST_CASE_P(/* no prefix */,
+                        SyncConsenPolicyDisabledTest,
+                        testing::Bool());
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
index 74c040160..1fd2223 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
@@ -118,7 +118,9 @@
 void OobeUIDialogDelegate::Close() {
   if (!dialog_widget_)
     return;
-  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogVisibility(false);
+  // We do not call LoginScreen::NotifyOobeDialogVisibility here, because this
+  // would cause the LoginShelfView to update its button visibility even though
+  // the login screen is about to be destroyed. See http://crbug/836172
   dialog_widget_->Close();
 }
 
diff --git a/chrome/browser/chromeos/login/user_board_view_mojo.cc b/chrome/browser/chromeos/login/user_board_view_mojo.cc
index bc30634b..3622ada 100644
--- a/chrome/browser/chromeos/login/user_board_view_mojo.cc
+++ b/chrome/browser/chromeos/login/user_board_view_mojo.cc
@@ -91,6 +91,19 @@
                                                                 default_locale);
 }
 
+void UserBoardViewMojo::ShowBannerMessage(const base::string16& message,
+                                          bool is_warning) {
+  // As of M69, ShowBannerMessage is used only for showing ext4 migration
+  // warning banner message.
+  // TODO(fukino): Remove ShowWarningMessage and related implementation along
+  // with the migration screen once the transition to ext4 is compilete.
+  if (!message.empty()) {
+    LoginScreenClient::Get()->login_screen()->ShowWarningBanner(message);
+  } else {
+    LoginScreenClient::Get()->login_screen()->HideWarningBanner();
+  }
+}
+
 void UserBoardViewMojo::ShowUserPodCustomIcon(
     const AccountId& account_id,
     const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions&
diff --git a/chrome/browser/chromeos/login/user_board_view_mojo.h b/chrome/browser/chromeos/login/user_board_view_mojo.h
index c255b70..c41cc505 100644
--- a/chrome/browser/chromeos/login/user_board_view_mojo.h
+++ b/chrome/browser/chromeos/login/user_board_view_mojo.h
@@ -25,7 +25,7 @@
                                const std::string& default_locale,
                                bool multiple_recommended_locales) override;
   void ShowBannerMessage(const base::string16& message,
-                         bool is_warning) override{};
+                         bool is_warning) override;
   void ShowUserPodCustomIcon(
       const AccountId& account_id,
       const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions& icon)
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 22f0293..8a21865 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -2358,6 +2358,7 @@
 
   CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME);
   EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
+  EXPECT_FALSE(StartupUtils::IsOobeCompleted());
 }
 
 IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, DemoPreferencesCanceled) {
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
index c9f968d3..dbf7c60 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.cc
@@ -9,6 +9,8 @@
 
 #include "base/logging.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/users/affiliation.h"
+#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/auth_policy_client.h"
@@ -154,9 +156,10 @@
 }
 
 void ActiveDirectoryPolicyManager::PublishPolicy() {
-  if (!store_->is_initialized()) {
+  if (!store_->is_initialized())
     return;
-  }
+  OnPublishPolicy();
+
   std::unique_ptr<PolicyBundle> bundle = std::make_unique<PolicyBundle>();
   PolicyMap& policy_map =
       bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
@@ -263,7 +266,8 @@
 UserActiveDirectoryPolicyManager::~UserActiveDirectoryPolicyManager() = default;
 
 void UserActiveDirectoryPolicyManager::Init(SchemaRegistry* registry) {
-  DCHECK(store()->is_initialized() || waiting_for_initial_policy_fetch_);
+  DCHECK(store()->is_initialized() || waiting_for_initial_policy_fetch_ ||
+         !policy_required_ /* policy may not be required in tests */);
   if (store()->is_initialized() && !store()->has_policy() && policy_required_) {
     // Exit the session in case of immediate load if policy is required.
     LOG(ERROR) << "Policy from forced immediate load could not be obtained. "
@@ -329,6 +333,20 @@
   PublishPolicy();
 }
 
+void UserActiveDirectoryPolicyManager::OnPublishPolicy() {
+  const em::PolicyData* policy_data = store()->policy();
+  if (!policy_data)
+    return;
+
+  // Update user affiliation IDs.
+  chromeos::AffiliationIDSet set_of_user_affiliation_ids(
+      policy_data->user_affiliation_ids().begin(),
+      policy_data->user_affiliation_ids().end());
+
+  chromeos::ChromeUserManager::Get()->SetUserAffiliation(
+      account_id_, set_of_user_affiliation_ids);
+}
+
 void UserActiveDirectoryPolicyManager::OnBlockingFetchTimeout() {
   DCHECK(waiting_for_initial_policy_fetch_);
   LOG(WARNING) << "Timed out while waiting for the policy fetch. "
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager.h b/chrome/browser/chromeos/policy/active_directory_policy_manager.h
index 3d56527..ccaac42 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager.h
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager.h
@@ -45,7 +45,7 @@
   void OnStoreLoaded(CloudPolicyStore* cloud_policy_store) override;
   void OnStoreError(CloudPolicyStore* cloud_policy_store) override;
 
-  // ComponentActiveDirectoryPolicyService::Delegate
+  // ComponentActiveDirectoryPolicyService::Delegate:
   void OnComponentActiveDirectoryPolicyUpdated() override;
 
   CloudPolicyStore* store() const { return store_.get(); }
@@ -88,6 +88,9 @@
   // requirements to continue have not been met.
   virtual void CancelWaitForInitialPolicy() {}
 
+  // Called by PublishPolicy() before the policy is sent off to UpdatePolicy().
+  virtual void OnPublishPolicy() {}
+
   // Whether policy fetch has ever been reported as completed by authpolicyd
   // during lifetime of the object (after Chrome was started).
   bool fetch_ever_completed_ = false;
@@ -154,9 +157,16 @@
 
  protected:
   // ActiveDirectoryPolicyManager:
+
+  // Calls AuthPolicyClient to fetch user policy.
   void DoPolicyFetch(PolicyScheduler::TaskCallback callback) override;
+
+  // Cancels the initial wait timeout for policy fetches during sign-in.
   void CancelWaitForInitialPolicy() override;
 
+  // Updates user affiliation IDs.
+  void OnPublishPolicy() override;
+
  private:
   // Called when |initial_policy_timeout_| times out, to cancel the blocking
   // wait for the initial policy fetch.
@@ -204,6 +214,8 @@
 
  protected:
   // ActiveDirectoryPolicyManager:
+
+  // Calls AuthPolicyClient to fetch device policy.
   void DoPolicyFetch(PolicyScheduler::TaskCallback callback) override;
 
  private:
diff --git a/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc b/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc
index 68d5ec5..0e6cf54 100644
--- a/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/active_directory_policy_manager_unittest.cc
@@ -14,12 +14,14 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chromeos/dbus/auth_policy_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/account_id/account_id.h"
 #include "components/policy/core/common/cloud/mock_cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
 #include "components/policy/core/common/schema_registry.h"
+#include "components/user_manager/scoped_user_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -93,7 +95,9 @@
 // been fired.
 class ActiveDirectoryPolicyManagerTest : public testing::Test {
  public:
-  ActiveDirectoryPolicyManagerTest() = default;
+  ActiveDirectoryPolicyManagerTest()
+      : user_manager_enabler_(
+            std::make_unique<chromeos::FakeChromeUserManager>()) {}
 
   // testing::Test overrides:
   void SetUp() override {
@@ -140,6 +144,9 @@
   // Owned by DBusThreadManager.
   TestAuthPolicyClient* mock_client_ = nullptr;
 
+  // Used to set FakeUserManager.
+  user_manager::ScopedUserManager user_manager_enabler_;
+
   // Initialized by the individual tests but owned by the test class so that it
   // can be shut down automatically after the test has run.
   std::unique_ptr<ActiveDirectoryPolicyManager> policy_manager_;
diff --git a/chrome/browser/chromeos/policy/affiliation_test_helper.cc b/chrome/browser/chromeos/policy/affiliation_test_helper.cc
index 1639e271..ed1832ea 100644
--- a/chrome/browser/chromeos/policy/affiliation_test_helper.cc
+++ b/chrome/browser/chromeos/policy/affiliation_test_helper.cc
@@ -24,6 +24,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.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/login/auth/key.h"
@@ -68,40 +69,70 @@
             base::checked_cast<int>(user_key_bits.length()));
 }
 
-void SetDeviceAffiliationID(
+void SetDeviceAffiliationIDs(
     policy::DevicePolicyCrosTestHelper* test_helper,
     chromeos::FakeSessionManagerClient* fake_session_manager_client,
+    chromeos::FakeAuthPolicyClient* fake_auth_policy_client,
     const std::set<std::string>& device_affiliation_ids) {
-  test_helper->InstallOwnerKey();
-  test_helper->MarkAsEnterpriseOwned();
-
+  // Assume it's Active Directory when the AuthPolicyClient is started.
+  // Make sure we don't overwrite the install attributes in that case.
+  const bool is_active_directory =
+      fake_auth_policy_client && fake_auth_policy_client->started();
+  if (!is_active_directory) {
+    test_helper->InstallOwnerKey();
+    test_helper->MarkAsEnterpriseOwned();
+  }
   policy::DevicePolicyBuilder* device_policy = test_helper->device_policy();
   for (const auto& device_affiliation_id : device_affiliation_ids) {
     device_policy->policy_data().add_device_affiliation_ids(
         device_affiliation_id);
   }
-  device_policy->SetDefaultSigningKey();
+  if (!is_active_directory)
+    device_policy->SetDefaultSigningKey();
   device_policy->Build();
 
   fake_session_manager_client->set_device_policy(device_policy->GetBlob());
   fake_session_manager_client->OnPropertyChangeComplete(true);
+
+  // Need fake_auth_policy_client for Active Directory accounts.
+  if (fake_auth_policy_client)
+    fake_auth_policy_client->set_device_affiliation_ids(device_affiliation_ids);
 }
 
 void SetUserAffiliationIDs(
     policy::UserPolicyBuilder* user_policy,
     chromeos::FakeSessionManagerClient* fake_session_manager_client,
+    chromeos::FakeAuthPolicyClient* fake_auth_policy_client,
     const AccountId& user_account_id,
     const std::set<std::string>& user_affiliation_ids) {
+  const bool is_active_directory =
+      user_account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY;
   user_policy->policy_data().set_username(user_account_id.GetUserEmail());
-  user_policy->policy_data().set_gaia_id(user_account_id.GetGaiaId());
-  SetUserKeys(user_policy);
+  if (!is_active_directory) {
+    user_policy->policy_data().set_gaia_id(user_account_id.GetGaiaId());
+    SetUserKeys(user_policy);
+  }
   for (const auto& user_affiliation_id : user_affiliation_ids) {
     user_policy->policy_data().add_user_affiliation_ids(user_affiliation_id);
   }
   user_policy->Build();
+
+  // Make sure AD policy is stored using the proper cryptohome key. This code
+  // runs before the AD account is migrated, so it would use the email address.
+  // TODO(ljusten): Clean this up as soon as CL:1055509 lands.
+  cryptohome::Identification cryptohome_id =
+      is_active_directory ? cryptohome::Identification::FromString(
+                                user_account_id.GetAccountIdKey())
+                          : cryptohome::Identification(user_account_id);
+
   fake_session_manager_client->set_user_policy(
-      cryptohome::CreateAccountIdentifierFromAccountId(user_account_id),
+      cryptohome::CreateAccountIdentifierFromIdentification(cryptohome_id),
       user_policy->GetBlob());
+
+  // Need fake_auth_policy_client for Active Directory accounts.
+  DCHECK(!is_active_directory || fake_auth_policy_client);
+  if (fake_auth_policy_client)
+    fake_auth_policy_client->set_user_affiliation_ids(user_affiliation_ids);
 }
 
 void PreLoginUser(const AccountId& account_id) {
@@ -119,8 +150,12 @@
       chromeos::UserSessionManager::GetInstance());
   session_manager_test_api.SetShouldObtainTokenHandleInTests(false);
 
-  chromeos::UserContext user_context(user_manager::UserType::USER_TYPE_REGULAR,
-                                     account_id);
+  const bool is_active_directory =
+      account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY;
+  const user_manager::UserType user_type =
+      is_active_directory ? user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY
+                          : user_manager::UserType::USER_TYPE_REGULAR;
+  chromeos::UserContext user_context(user_type, account_id);
   user_context.SetKey(chromeos::Key("password"));
   if (account_id.GetUserEmail() == kEnterpriseUserEmail) {
     user_context.SetRefreshToken(kFakeRefreshToken);
diff --git a/chrome/browser/chromeos/policy/affiliation_test_helper.h b/chrome/browser/chromeos/policy/affiliation_test_helper.h
index 78068007..1a957c15 100644
--- a/chrome/browser/chromeos/policy/affiliation_test_helper.h
+++ b/chrome/browser/chromeos/policy/affiliation_test_helper.h
@@ -17,6 +17,7 @@
 
 namespace chromeos {
 class FakeSessionManagerClient;
+class FakeAuthPolicyClient;
 }  // namespace chromeos
 
 namespace policy {
@@ -30,7 +31,7 @@
 // boilerplate in other places (http://crbug.com/549111).
 void SetUserKeys(policy::UserPolicyBuilder* user_policy);
 
-// Sets device affiliation ID to |fake_session_manager| from
+// Sets device affiliation ID to |fake_session_manager_client| from
 // |device_affiliation_ids| and modifies |test_helper| so that it contains
 // correct values of device affiliation IDs for future use. To add some device
 // policies and have device affiliation ID valid please use |test_helper|
@@ -45,25 +46,31 @@
 // std::set<std::string> device_affiliation_ids;
 // device_affiliation_ids.insert(some-affiliation-id);
 //
-// affiliation_test_helper::SetDeviceAffiliationID(&test_helper,
-//                                                 fake_session_manager_client,
-//                                                 device_affiliation_ids);
+// affiliation_test_helper::SetDeviceAffiliationIDs(
+//     &test_helper,
+//     fake_session_manager_client,
+//     nullptr /* fake_auth_policy_client */
+//     device_affiliation_ids);
 //
 // If it is used together with SetUserAffiliationIDs() (which is the most common
 // case) |fake_session_manager_client| must point to the same object as in
 // SetUserAffiliationIDs() call.
 // In browser tests one can call this function from
 // SetUpInProcessBrowserTestFixture().
-void SetDeviceAffiliationID(
+//
+// |fake_auth_policy_client| is only needed if the test supports Active
+// Directory user accounts. If not, it may be nullptr.
+void SetDeviceAffiliationIDs(
     policy::DevicePolicyCrosTestHelper* test_helper,
     chromeos::FakeSessionManagerClient* fake_session_manager_client,
+    chromeos::FakeAuthPolicyClient* fake_auth_policy_client,
     const std::set<std::string>& device_affiliation_ids);
 
-// Sets user affiliation ID for |user_account_id| to |fake_session_manager| from
-// |user_affiliation_ids| and modifies |user_policy| so that it contains
-// correct values of user affiliation IDs for future use. To add user policies
-// and have user affiliation IDs valid please use |user_policy| modified by this
-// function. Example:
+// Sets user affiliation ID for |user_account_id| to
+// |fake_session_manager_client| from |user_affiliation_ids| and modifies
+// |user_policy| so that it contains correct values of user affiliation IDs for
+// future use. To add user policies and have user affiliation IDs valid please
+// use |user_policy| modified by this function. Example:
 //
 // FakeSessionManagerClient* fake_session_manager_client =
 //    new chromeos::FakeSessionManagerClient;
@@ -75,17 +82,24 @@
 // user_affiliation_ids.insert("some-affiliation-id");
 //
 // affiliation_test_helper::SetUserAffiliationIDs(
-//    &user_policy, fake_session_manager_client, "user@example.com",
+//    &user_policy,
+//    fake_session_manager_client,
+//    nullptr /* fake_auth_policy_client */,
+//    account_id,
 //    user_affiliation_ids);
 //
-// If it is used together SetDeviceAffiliationID() (which is the most common
+// If it is used together SetDeviceAffiliationIDs() (which is the most common
 // case) |fake_session_manager_client| must point to the same object as in
-// SetDeviceAffiliationID() call.
+// SetDeviceAffiliationIDs() call.
 // In browser tests one can call this function from
 // SetUpInProcessBrowserTestFixture().
+//
+// |fake_auth_policy_client| is only needed if the test supports Active
+// Directory user accounts. If not, it may be nullptr.
 void SetUserAffiliationIDs(
     policy::UserPolicyBuilder* user_policy,
     chromeos::FakeSessionManagerClient* fake_session_manager_client,
+    chromeos::FakeAuthPolicyClient* fake_auth_policy_client,
     const AccountId& user_account_id,
     const std::set<std::string>& user_affiliation_ids);
 
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 72c5b34..f4833ab 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -65,6 +65,8 @@
 
 namespace policy {
 
+namespace em = enterprise_management;
+
 namespace {
 
 // Install attributes for tests.
@@ -178,7 +180,7 @@
   if (device_cloud_policy_manager_) {
     device_cloud_policy_invalidator_ =
         std::make_unique<AffiliatedCloudPolicyInvalidator>(
-            enterprise_management::DeviceRegisterRequest::DEVICE,
+            em::DeviceRegisterRequest::DEVICE,
             device_cloud_policy_manager_->core(),
             affiliated_invalidation_service_provider_.get());
     device_remote_commands_invalidator_ =
@@ -254,12 +256,9 @@
 }
 
 std::string BrowserPolicyConnectorChromeOS::GetEnterpriseDisplayDomain() const {
-  if (device_cloud_policy_manager_) {
-    const enterprise_management::PolicyData* policy =
-        device_cloud_policy_manager_->device_store()->policy();
-    if (policy && policy->has_display_domain())
-      return policy->display_domain();
-  }
+  const em::PolicyData* policy = GetDevicePolicy();
+  if (policy && policy->has_display_domain())
+    return policy->display_domain();
   return GetEnterpriseEnrollmentDomain();
 }
 
@@ -268,32 +267,23 @@
 }
 
 std::string BrowserPolicyConnectorChromeOS::GetDeviceAssetID() const {
-  if (device_cloud_policy_manager_) {
-    const enterprise_management::PolicyData* policy =
-        device_cloud_policy_manager_->device_store()->policy();
-    if (policy && policy->has_annotated_asset_id())
-      return policy->annotated_asset_id();
-  }
+  const em::PolicyData* policy = GetDevicePolicy();
+  if (policy && policy->has_annotated_asset_id())
+    return policy->annotated_asset_id();
   return std::string();
 }
 
 std::string BrowserPolicyConnectorChromeOS::GetDeviceAnnotatedLocation() const {
-  if (device_cloud_policy_manager_) {
-    const enterprise_management::PolicyData* policy =
-        device_cloud_policy_manager_->device_store()->policy();
-    if (policy && policy->has_annotated_location())
-      return policy->annotated_location();
-  }
+  const em::PolicyData* policy = GetDevicePolicy();
+  if (policy && policy->has_annotated_location())
+    return policy->annotated_location();
   return std::string();
 }
 
 std::string BrowserPolicyConnectorChromeOS::GetDirectoryApiID() const {
-  if (device_cloud_policy_manager_) {
-    const enterprise_management::PolicyData* policy =
-        device_cloud_policy_manager_->device_store()->policy();
-    if (policy && policy->has_directory_api_id())
-      return policy->directory_api_id();
-  }
+  const em::PolicyData* policy = GetDevicePolicy();
+  if (policy && policy->has_directory_api_id())
+    return policy->directory_api_id();
   return std::string();
 }
 
@@ -409,15 +399,22 @@
 chromeos::AffiliationIDSet
 BrowserPolicyConnectorChromeOS::GetDeviceAffiliationIDs() const {
   chromeos::AffiliationIDSet affiliation_ids;
-  if (device_cloud_policy_manager_) {
-    const enterprise_management::PolicyData* const policy_data =
-        device_cloud_policy_manager_->device_store()->policy();
-    if (policy_data) {
-      affiliation_ids.insert(policy_data->device_affiliation_ids().begin(),
-                             policy_data->device_affiliation_ids().end());
-    }
+  const em::PolicyData* policy = GetDevicePolicy();
+  if (policy) {
+    affiliation_ids.insert(policy->device_affiliation_ids().begin(),
+                           policy->device_affiliation_ids().end());
   }
   return affiliation_ids;
 }
 
+const em::PolicyData* BrowserPolicyConnectorChromeOS::GetDevicePolicy() const {
+  if (device_cloud_policy_manager_)
+    return device_cloud_policy_manager_->device_store()->policy();
+
+  if (device_active_directory_policy_manager_)
+    return device_active_directory_policy_manager_->store()->policy();
+
+  return nullptr;
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
index 60b21a6e..81218d9b 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -20,6 +20,10 @@
 class PrefRegistrySimple;
 class PrefService;
 
+namespace enterprise_management {
+class PolicyData;
+}
+
 namespace chromeos {
 
 class InstallAttributes;
@@ -197,6 +201,9 @@
   std::unique_ptr<chromeos::attestation::AttestationFlow>
   CreateAttestationFlow();
 
+  // Returns the device policy data or nullptr if it does not exist.
+  const enterprise_management::PolicyData* GetDevicePolicy() const;
+
   // Components of the device cloud policy implementation.
   std::unique_ptr<ServerBackedStateKeysBroker> state_keys_broker_;
   std::unique_ptr<chromeos::InstallAttributes> install_attributes_;
diff --git a/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_decoder.cc b/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_decoder.cc
index f6cb64b6..1db876b 100644
--- a/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_decoder.cc
+++ b/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_decoder.cc
@@ -61,7 +61,8 @@
   int minutes = minutes_val->GetInt();
   int milliseconds =
       hours * kHour.InMilliseconds() + minutes * kMinute.InMilliseconds();
-  return WeeklyTime(day_of_week, milliseconds);
+  return WeeklyTime(day_of_week, milliseconds,
+                    base::nullopt /* timezone_offset */);
 }
 
 bool WeeklyTimeIntervalsFromListValue(
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 7e72027..b2165457 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -55,13 +55,6 @@
           GetEnterpriseOwnedInstallAttributesBlobForTesting(user_name));
 }
 
-// static
-void DevicePolicyCrosTestHelper::MarkAsActiveDirectoryEnterpriseOwned(
-    const std::string& realm) {
-  OverridePaths();
-  ASSERT_TRUE(chromeos::tpm_util::LockDeviceActiveDirectoryForTesting(realm));
-}
-
 void DevicePolicyCrosTestHelper::MarkAsEnterpriseOwned() {
   MarkAsEnterpriseOwnedBy(device_policy_.policy_data().username());
 }
@@ -90,11 +83,9 @@
 }
 
 DevicePolicyCrosBrowserTest::DevicePolicyCrosBrowserTest()
-    : fake_session_manager_client_(new chromeos::FakeSessionManagerClient) {
-}
+    : fake_session_manager_client_(new chromeos::FakeSessionManagerClient) {}
 
-DevicePolicyCrosBrowserTest::~DevicePolicyCrosBrowserTest() {
-}
+DevicePolicyCrosBrowserTest::~DevicePolicyCrosBrowserTest() = default;
 
 void DevicePolicyCrosBrowserTest::SetUp() {
   // Set some fake state keys to make surethey are not empty.
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
index 03000f28..c316f4c 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
@@ -28,8 +28,8 @@
   // policies apply Chrome-wide. If this is not called, device policies will
   // affect CrosSettings only.
   static void MarkAsEnterpriseOwnedBy(const std::string& user_name);
-  // Marks the device as Active Directory enterprise-owned.
-  static void MarkAsActiveDirectoryEnterpriseOwned(const std::string& realm);
+
+  // Calls MarkAsEnterpriseOwnedBy() with the user from |device_policy_|.
   void MarkAsEnterpriseOwned();
 
   // Writes the owner key to disk. To be called before installing a policy.
diff --git a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
index 07542dbc..9057ed43 100644
--- a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
+++ b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
@@ -106,7 +106,7 @@
     base::Optional<std::string> timezone = ExtractTimezoneFromProto(container);
     if (timezone) {
       off_hours_intervals = weekly_time_utils::ConvertIntervalsToGmt(
-          ExtractWeeklyTimeIntervalsFromProto(container), clock_, *timezone);
+          ExtractWeeklyTimeIntervalsFromProto(container, *timezone, clock_));
     }
   }
   off_hours_intervals_.swap(off_hours_intervals);
@@ -141,7 +141,7 @@
     SetOffHoursMode(false);
     return;
   }
-  WeeklyTime current_time = WeeklyTime::GetCurrentWeeklyTime(clock_);
+  WeeklyTime current_time = WeeklyTime::GetCurrentGmtWeeklyTime(clock_);
   for (const auto& interval : off_hours_intervals_) {
     if (interval.Contains(current_time)) {
       base::TimeDelta remaining_off_hours_duration =
diff --git a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
index 9785aa6c8..322e8fcb 100644
--- a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
+++ b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
@@ -200,13 +200,14 @@
                    .guest_mode_enabled());
   int current_day_of_week = ExtractDayOfWeek(base::Time::Now());
   SetOffHoursPolicyToProto(
-      &proto, OffHoursPolicy(
-                  kUtcTimezone,
-                  {WeeklyTimeInterval(
-                      WeeklyTime(NextDayOfWeek(current_day_of_week),
-                                 TimeDelta::FromHours(10).InMilliseconds()),
-                      WeeklyTime(NextDayOfWeek(current_day_of_week),
-                                 TimeDelta::FromHours(15).InMilliseconds()))}));
+      &proto,
+      OffHoursPolicy(
+          kUtcTimezone,
+          {WeeklyTimeInterval(
+              WeeklyTime(NextDayOfWeek(current_day_of_week),
+                         TimeDelta::FromHours(10).InMilliseconds(), 0),
+              WeeklyTime(NextDayOfWeek(current_day_of_week),
+                         TimeDelta::FromHours(15).InMilliseconds(), 0))}));
   UpdateDeviceSettings();
   EXPECT_FALSE(device_settings_service_.device_settings()
                    ->guest_mode_enabled()
@@ -224,12 +225,13 @@
                    .guest_mode_enabled());
   int current_day_of_week = ExtractDayOfWeek(base::Time::Now());
   SetOffHoursPolicyToProto(
-      &proto, OffHoursPolicy(
-                  kUtcTimezone,
-                  {WeeklyTimeInterval(
-                      WeeklyTime(current_day_of_week, 0),
-                      WeeklyTime(NextDayOfWeek(current_day_of_week),
-                                 TimeDelta::FromHours(10).InMilliseconds()))}));
+      &proto,
+      OffHoursPolicy(
+          kUtcTimezone,
+          {WeeklyTimeInterval(
+              WeeklyTime(current_day_of_week, 0, 0),
+              WeeklyTime(NextDayOfWeek(current_day_of_week),
+                         TimeDelta::FromHours(10).InMilliseconds(), 0))}));
   UpdateDeviceSettings();
   EXPECT_TRUE(device_settings_service_.device_settings()
                   ->guest_mode_enabled()
@@ -247,12 +249,13 @@
                    .guest_mode_enabled());
   int current_day_of_week = ExtractDayOfWeek(base::Time::Now());
   SetOffHoursPolicyToProto(
-      &proto, OffHoursPolicy(
-                  kUtcTimezone,
-                  {WeeklyTimeInterval(
-                      WeeklyTime(current_day_of_week, 0),
-                      WeeklyTime(NextDayOfWeek(current_day_of_week),
-                                 TimeDelta::FromHours(10).InMilliseconds()))}));
+      &proto,
+      OffHoursPolicy(
+          kUtcTimezone,
+          {WeeklyTimeInterval(
+              WeeklyTime(current_day_of_week, 0, 0),
+              WeeklyTime(NextDayOfWeek(current_day_of_week),
+                         TimeDelta::FromHours(10).InMilliseconds(), 0))}));
   EXPECT_FALSE(device_settings_service_.device_settings()
                    ->guest_mode_enabled()
                    .guest_mode_enabled());
@@ -273,12 +276,13 @@
   proto.mutable_guest_mode_enabled()->set_guest_mode_enabled(false);
   int current_day_of_week = ExtractDayOfWeek(base::Time::Now());
   SetOffHoursPolicyToProto(
-      &proto, OffHoursPolicy(
-                  kUtcTimezone,
-                  {WeeklyTimeInterval(
-                      WeeklyTime(current_day_of_week, 0),
-                      WeeklyTime(NextDayOfWeek(current_day_of_week),
-                                 TimeDelta::FromHours(10).InMilliseconds()))}));
+      &proto,
+      OffHoursPolicy(
+          kUtcTimezone,
+          {WeeklyTimeInterval(
+              WeeklyTime(current_day_of_week, 0, 0),
+              WeeklyTime(NextDayOfWeek(current_day_of_week),
+                         TimeDelta::FromHours(10).InMilliseconds(), 0))}));
   UpdateDeviceSettings();
 
   EXPECT_FALSE(
@@ -326,13 +330,14 @@
   int current_day_of_week = ExtractDayOfWeek(clock()->Now());
   em::ChromeDeviceSettingsProto& proto(device_policy_.payload());
   SetOffHoursPolicyToProto(
-      &proto, OffHoursPolicy(
-                  kUtcTimezone,
-                  {WeeklyTimeInterval(
-                      WeeklyTime(current_day_of_week,
-                                 TimeDelta::FromHours(14).InMilliseconds()),
-                      WeeklyTime(current_day_of_week,
-                                 TimeDelta::FromHours(15).InMilliseconds()))}));
+      &proto,
+      OffHoursPolicy(
+          kUtcTimezone,
+          {WeeklyTimeInterval(
+              WeeklyTime(current_day_of_week,
+                         TimeDelta::FromHours(14).InMilliseconds(), 0),
+              WeeklyTime(current_day_of_week,
+                         TimeDelta::FromHours(15).InMilliseconds(), 0))}));
   AdvanceTestClock(TimeDelta::FromHours(14));
   UpdateDeviceSettings();
   EXPECT_TRUE(device_off_hours_controller()->is_off_hours_mode());
@@ -347,11 +352,11 @@
   em::ChromeDeviceSettingsProto& proto(device_policy_.payload());
   SetOffHoursPolicyToProto(
       &proto,
-      OffHoursPolicy(
-          kUtcTimezone,
-          {WeeklyTimeInterval(WeeklyTime(NextDayOfWeek(current_day_of_week), 0),
-                              WeeklyTime(NextDayOfWeek(current_day_of_week),
-                                         kHour.InMilliseconds()))}));
+      OffHoursPolicy(kUtcTimezone,
+                     {WeeklyTimeInterval(
+                         WeeklyTime(NextDayOfWeek(current_day_of_week), 0, 0),
+                         WeeklyTime(NextDayOfWeek(current_day_of_week),
+                                    kHour.InMilliseconds(), 0))}));
   UpdateDeviceSettings();
   EXPECT_FALSE(device_off_hours_controller()->is_off_hours_mode());
 
@@ -392,9 +397,11 @@
                 kUtcTimezone,
                 {WeeklyTimeInterval(
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(1).InMilliseconds()),
+                               TimeDelta::FromHours(1).InMilliseconds(),
+                               0),
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(2).InMilliseconds()))}),
+                               TimeDelta::FromHours(2).InMilliseconds(),
+                               0))}),
             kHour,
             true),
         std::make_tuple(
@@ -402,9 +409,11 @@
                 kUtcTimezone,
                 {WeeklyTimeInterval(
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(1).InMilliseconds()),
+                               TimeDelta::FromHours(1).InMilliseconds(),
+                               0),
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(2).InMilliseconds()))}),
+                               TimeDelta::FromHours(2).InMilliseconds(),
+                               0))}),
             kHour * 2,
             false),
         std::make_tuple(
@@ -412,9 +421,11 @@
                 kUtcTimezone,
                 {WeeklyTimeInterval(
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(1).InMilliseconds()),
+                               TimeDelta::FromHours(1).InMilliseconds(),
+                               0),
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(2).InMilliseconds()))}),
+                               TimeDelta::FromHours(2).InMilliseconds(),
+                               0))}),
             kHour * 1.5,
             true),
         std::make_tuple(
@@ -422,9 +433,11 @@
                 kUtcTimezone,
                 {WeeklyTimeInterval(
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(1).InMilliseconds()),
+                               TimeDelta::FromHours(1).InMilliseconds(),
+                               0),
                     WeeklyTime(em::WeeklyTimeProto::THURSDAY,
-                               TimeDelta::FromHours(2).InMilliseconds()))}),
+                               TimeDelta::FromHours(2).InMilliseconds(),
+                               0))}),
             kHour * 3,
             false)));
 
diff --git a/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.cc b/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.cc
index c9ba608..f933bf88b 100644
--- a/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.cc
+++ b/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.cc
@@ -5,7 +5,9 @@
 #include "chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h"
 
 #include "base/logging.h"
+#include "base/time/default_clock.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/policy/weekly_time/time_utils.h"
 
 namespace em = enterprise_management;
 
@@ -13,10 +15,17 @@
 namespace off_hours {
 
 std::vector<WeeklyTimeInterval> ExtractWeeklyTimeIntervalsFromProto(
-    const em::DeviceOffHoursProto& container) {
+    const em::DeviceOffHoursProto& container,
+    const std::string& timezone,
+    base::Clock* clock) {
+  int offset;
+  if (!weekly_time_utils::GetOffsetFromTimezoneToGmt(timezone, clock, &offset))
+    return {};
   std::vector<WeeklyTimeInterval> intervals;
   for (const auto& entry : container.intervals()) {
-    auto interval = WeeklyTimeInterval::ExtractFromProto(entry);
+    // The offset is to convert from |timezone| to GMT. Negate it to get the
+    // offset from GMT to |timezone|.
+    auto interval = WeeklyTimeInterval::ExtractFromProto(entry, -offset);
     if (interval)
       intervals.push_back(*interval);
   }
@@ -45,7 +54,8 @@
   auto off_hours = std::make_unique<base::DictionaryValue>();
   off_hours->SetString("timezone", *timezone);
   std::vector<WeeklyTimeInterval> intervals =
-      ExtractWeeklyTimeIntervalsFromProto(container);
+      ExtractWeeklyTimeIntervalsFromProto(container, *timezone,
+                                          base::DefaultClock::GetInstance());
   auto intervals_value = std::make_unique<base::ListValue>();
   for (const auto& interval : intervals)
     intervals_value->Append(interval.ToValue());
diff --git a/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h b/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h
index 17fcddd..88c136dd 100644
--- a/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h
+++ b/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser.h
@@ -15,12 +15,20 @@
 #include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 
+namespace base {
+class Clock;
+}
+
 namespace policy {
 namespace off_hours {
 
-// Return list of time intervals from DeviceOffHoursProto structure.
+// Return list of time intervals from DeviceOffHoursProto structure. Takes the
+// timezone into account, this is to be used for non-value conversion purposes,
+// i.e. if the intervals are going to be used in code.
 std::vector<WeeklyTimeInterval> ExtractWeeklyTimeIntervalsFromProto(
-    const enterprise_management::DeviceOffHoursProto& container);
+    const enterprise_management::DeviceOffHoursProto& container,
+    const std::string& timezone,
+    base::Clock* clock);
 
 // Return list of proto tags of ignored policies from DeviceOffHoursProto
 // structure.
diff --git a/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser_unittest.cc b/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser_unittest.cc
index e2e314f..e6b4538 100644
--- a/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser_unittest.cc
+++ b/chrome/browser/chromeos/policy/off_hours/off_hours_proto_parser_unittest.cc
@@ -95,8 +95,8 @@
 };
 
 TEST_F(ConvertOffHoursProtoToValueTest, Test) {
-  WeeklyTime start = WeeklyTime(1, kHour.InMilliseconds());
-  WeeklyTime end = WeeklyTime(3, kHour.InMilliseconds() * 2);
+  WeeklyTime start = WeeklyTime(1, kHour.InMilliseconds(), 0);
+  WeeklyTime end = WeeklyTime(3, kHour.InMilliseconds() * 2, 0);
   std::vector<WeeklyTimeInterval> intervals = {WeeklyTimeInterval(start, end)};
 
   em::ChromeDeviceSettingsProto proto;
diff --git a/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc b/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc
index 8b66e7e..0584f3a9 100644
--- a/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc
+++ b/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc
@@ -36,8 +36,8 @@
 constexpr char kAnotherAffiliationID[] = "another-affiliation-id";
 
 struct Params {
-  explicit Params(bool affiliated) : affiliated_(affiliated) {}
-  bool affiliated_;
+  explicit Params(bool _affiliated) : affiliated(_affiliated) {}
+  bool affiliated;
 };
 
 }  // namespace
@@ -62,22 +62,21 @@
 
   void SetUpInProcessBrowserTestFixture() override {
     DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
+
     UserPolicyBuilder user_policy;
     DevicePolicyCrosTestHelper test_helper;
 
-    std::set<std::string> device_affiliation_ids;
-    device_affiliation_ids.insert(kAffiliationID);
-    affiliation_test_helper::SetDeviceAffiliationID(
-        &test_helper, session_manager_client(), device_affiliation_ids);
+    const std::set<std::string> device_affiliation_ids = {kAffiliationID};
+    const std::set<std::string> user_affiliation_ids = {
+        GetParam().affiliated ? kAffiliationID : kAnotherAffiliationID};
 
-    std::set<std::string> user_affiliation_ids;
-    if (GetParam().affiliated_)
-      user_affiliation_ids.insert(kAffiliationID);
-    else
-      user_affiliation_ids.insert(kAnotherAffiliationID);
+    affiliation_test_helper::SetDeviceAffiliationIDs(
+        &test_helper, session_manager_client(),
+        nullptr /* fake_auth_policy_client */, device_affiliation_ids);
 
     affiliation_test_helper::SetUserAffiliationIDs(
-        &user_policy, session_manager_client(), affiliated_account_id_,
+        &user_policy, session_manager_client(),
+        nullptr /* fake_auth_policy_client */, affiliated_account_id_,
         user_affiliation_ids);
   }
 
@@ -125,7 +124,7 @@
       user_manager::UserManager::Get()->FindUser(affiliated_account_id_);
   const Profile* profile =
       chromeos::ProfileHelper::Get()->GetProfileByUser(user);
-  const bool affiliated = GetParam().affiliated_;
+  const bool affiliated = GetParam().affiliated;
 
   EXPECT_EQ(affiliated, user->IsAffiliated());
   EXPECT_TRUE(arc::IsArcAllowedForProfile(profile))
diff --git a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
index b04e105..a153550 100644
--- a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
@@ -8,7 +8,9 @@
 #include "base/callback_helpers.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/active_directory_test_helper.h"
 #include "chrome/browser/chromeos/policy/affiliation_test_helper.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/net/nss_context.h"
@@ -19,6 +21,8 @@
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #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 "components/account_id/account_id.h"
@@ -43,20 +47,30 @@
 
 constexpr char kAffiliatedUser[] = "affiliated-user@example.com";
 constexpr char kAffiliatedUserGaiaId[] = "1234567890";
+constexpr char kAffiliatedUserObjGuid[] =
+    "{11111111-1111-1111-1111-111111111111}";
 constexpr char kAffiliationID[] = "some-affiliation-id";
 constexpr char kAnotherAffiliationID[] = "another-affiliation-id";
 
 struct Params {
-  explicit Params(bool affiliated) : affiliated_(affiliated) {}
+  Params(bool affiliated, bool active_directory)
+      : affiliated(affiliated), active_directory(active_directory) {}
 
-  friend std::ostream& operator<<(std::ostream& os, const Params& p) {
-    os << "{ affiliated: " << p.affiliated_ << " }";
-    return os;
-  }
+  // Whether the user is expected to be affiliated.
+  bool affiliated;
 
-  bool affiliated_;
+  // Whether the user account is an Active Directory account.
+  bool active_directory;
 };
 
+// Must be a valid test name (no spaces etc.). Makes the test show up as e.g.
+// AffiliationCheck/U.A.B.T.Affiliated/NotAffiliated_NotActiveDirectory
+std::string PrintParam(testing::TestParamInfo<Params> param_info) {
+  return base::StringPrintf("%sAffiliated_%sActiveDirectory",
+                            param_info.param.affiliated ? "" : "Not",
+                            param_info.param.active_directory ? "" : "Not");
+}
+
 void CheckIsSystemSlotAvailableOnIOThreadWithCertDb(
     bool* out_system_slot_available,
     base::OnceClosure done_closure,
@@ -105,10 +119,16 @@
     : public InProcessBrowserTest,
       public ::testing::WithParamInterface<Params> {
  public:
-  UserAffiliationBrowserTest()
-      : account_id_(AccountId::FromUserEmailGaiaId(kAffiliatedUser,
-                                                   kAffiliatedUserGaiaId)) {
+  UserAffiliationBrowserTest() {
     set_exit_when_last_browser_closes(false);
+
+    if (GetParam().active_directory) {
+      account_id_ = AccountId::AdFromUserEmailObjGuid(kAffiliatedUser,
+                                                      kAffiliatedUserObjGuid);
+    } else {
+      account_id_ = AccountId::FromUserEmailGaiaId(kAffiliatedUser,
+                                                   kAffiliatedUserGaiaId);
+    }
   }
 
  protected:
@@ -138,23 +158,37 @@
         base::WrapUnique<chromeos::SessionManagerClient>(
             fake_session_manager_client));
 
-    UserPolicyBuilder user_policy;
-    DevicePolicyCrosTestHelper test_helper;
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient(
+        std::make_unique<chromeos::FakeCryptohomeClient>());
 
-    std::set<std::string> device_affiliation_ids;
-    device_affiliation_ids.insert(kAffiliationID);
-    affiliation_test_helper::SetDeviceAffiliationID(
-        &test_helper, fake_session_manager_client, device_affiliation_ids);
+    chromeos::FakeAuthPolicyClient* fake_auth_policy_client = nullptr;
+    if (GetParam().active_directory) {
+      auto fake_auth_policy_client_owned =
+          std::make_unique<chromeos::FakeAuthPolicyClient>();
+      fake_auth_policy_client = fake_auth_policy_client_owned.get();
+      fake_auth_policy_client->DisableOperationDelayForTesting();
+      chromeos::DBusThreadManager::GetSetterForTesting()->SetAuthPolicyClient(
+          std::move(fake_auth_policy_client_owned));
 
-    std::set<std::string> user_affiliation_ids;
-    if (GetParam().affiliated_) {
-      user_affiliation_ids.insert(kAffiliationID);
-    } else {
-      user_affiliation_ids.insert(kAnotherAffiliationID);
+      // PrepareLogin requires a message loop, which isn't available yet here.
+      base::MessageLoop message_loop;
+      chromeos::active_directory_test_helper::PrepareLogin(
+          account_id_.GetUserEmail());
     }
+
+    DevicePolicyCrosTestHelper test_helper;
+    UserPolicyBuilder user_policy;
+    const std::set<std::string> device_affiliation_ids = {kAffiliationID};
+    const std::set<std::string> user_affiliation_ids = {
+        GetParam().affiliated ? kAffiliationID : kAnotherAffiliationID};
+
+    affiliation_test_helper::SetDeviceAffiliationIDs(
+        &test_helper, fake_session_manager_client, fake_auth_policy_client,
+        device_affiliation_ids);
+
     affiliation_test_helper::SetUserAffiliationIDs(
-        &user_policy, fake_session_manager_client, account_id_,
-        user_affiliation_ids);
+        &user_policy, fake_session_manager_client, fake_auth_policy_client,
+        account_id_, user_affiliation_ids);
 
     // Set retry delay to prevent timeouts.
     policy::DeviceManagementService::SetRetryDelayForTesting(0);
@@ -182,7 +216,7 @@
     TearDownTestSystemSlot();
   }
 
-  const AccountId account_id_;
+  AccountId account_id_;
 
   void SetUpTestSystemSlot() {
     bool system_slot_constructed_successfully = false;
@@ -197,6 +231,20 @@
     ASSERT_TRUE(system_slot_constructed_successfully);
   }
 
+  void VerifyAffiliationExpectations() {
+    EXPECT_EQ(GetParam().affiliated, user_manager::UserManager::Get()
+                                         ->FindUser(account_id_)
+                                         ->IsAffiliated());
+
+    // Also test system slot availability, which is tied to user affiliation.
+    // This gives us additional information, because for the system slot to be
+    // available for an affiliated user, IsAffiliated() must already be
+    // returning true in the ProfileIOData constructor.
+    ASSERT_NO_FATAL_FAILURE(SetUpTestSystemSlot());
+    EXPECT_EQ(GetParam().affiliated,
+              IsSystemSlotAvailable(ProfileManager::GetPrimaryUserProfile()));
+  }
+
  private:
   void SetUpTestSystemSlotOnIO(bool* out_system_slot_constructed_successfully) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -225,50 +273,36 @@
   DISALLOW_COPY_AND_ASSIGN(UserAffiliationBrowserTest);
 };
 
-IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, PRE_PRE_Affiliated) {
+IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, PRE_PRE_TestAffiliation) {
   affiliation_test_helper::PreLoginUser(account_id_);
 }
 
 // This part of the test performs a regular sign-in through the login manager.
-IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, PRE_Affiliated) {
+IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, PRE_TestAffiliation) {
   affiliation_test_helper::LoginUser(account_id_);
-
-  EXPECT_EQ(
-      GetParam().affiliated_,
-      user_manager::UserManager::Get()->FindUser(account_id_)->IsAffiliated());
-
-  // Also test system slot availability, which is tied to user affiliation. This
-  // gives us additional information, because for the system slot to be
-  // available for an affiliated user, IsAffiliated() must already be returning
-  // true in the ProfileIOData constructor.
-  ASSERT_NO_FATAL_FAILURE(SetUpTestSystemSlot());
-  EXPECT_EQ(GetParam().affiliated_,
-            IsSystemSlotAvailable(ProfileManager::GetPrimaryUserProfile()));
+  ASSERT_NO_FATAL_FAILURE(VerifyAffiliationExpectations());
 }
 
 // This part of the test performs a direct sign-in into the user profile using
 // the --login-user command-line switch, simulating the restart after crash
 // behavior on Chrome OS.
 // See SetUpCommandLine for details.
-IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, Affiliated) {
+IN_PROC_BROWSER_TEST_P(UserAffiliationBrowserTest, TestAffiliation) {
   // Note: We don't log in the user, because the login has implicitly been
   // performed using a command-line flag (see SetUpCommandLine).
-
-  EXPECT_EQ(
-      GetParam().affiliated_,
-      user_manager::UserManager::Get()->FindUser(account_id_)->IsAffiliated());
-
-  // Also test system slot availability, which is tied to user affiliation. This
-  // gives us additional information, because for the system slot to be
-  // available for an affiliated user, IsAffiliated() must already be returning
-  // true in the ProfileIOData constructor.
-  ASSERT_NO_FATAL_FAILURE(SetUpTestSystemSlot());
-  EXPECT_EQ(GetParam().affiliated_,
-            IsSystemSlotAvailable(ProfileManager::GetPrimaryUserProfile()));
+  ASSERT_NO_FATAL_FAILURE(VerifyAffiliationExpectations());
 }
 
 INSTANTIATE_TEST_CASE_P(AffiliationCheck,
                         UserAffiliationBrowserTest,
-                        ::testing::Values(Params(true), Params(false)));
+                        //         affiliated            active_directory
+                        //              |                         |
+                        //              +----------+      ______  +---------+
+                        //                         |     /      \______     |
+                        ::testing::Values(Params(true, true),     //   \   /
+                                          Params(false, true),    //    \ /
+                                          Params(true, false),    //     X
+                                          Params(false, false)),  //    / \<--!
+                        PrintParam);                              //    \_/
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/weekly_time/time_utils.cc b/chrome/browser/chromeos/policy/weekly_time/time_utils.cc
index 14c524a..aa698b6 100644
--- a/chrome/browser/chromeos/policy/weekly_time/time_utils.cc
+++ b/chrome/browser/chromeos/policy/weekly_time/time_utils.cc
@@ -7,18 +7,22 @@
 #include <algorithm>
 #include <memory>
 
+#include "base/i18n/time_formatting.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/time/clock.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
+#include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
 #include "third_party/icu/source/common/unicode/unistr.h"
 #include "third_party/icu/source/common/unicode/utypes.h"
 #include "third_party/icu/source/i18n/unicode/gregocal.h"
-#include "third_party/icu/source/i18n/unicode/timezone.h"
 
 namespace policy {
 namespace weekly_time_utils {
 namespace {
 constexpr base::TimeDelta kWeek = base::TimeDelta::FromDays(7);
+const char* kFormatWeekdayHourMinute = "EEEE jj:mm a";
 }  // namespace
 
 bool GetOffsetFromTimezoneToGmt(const std::string& timezone,
@@ -35,7 +39,7 @@
 }
 
 bool GetOffsetFromTimezoneToGmt(const icu::TimeZone& timezone,
-                                const base::Clock* clock,
+                                base::Clock* clock,
                                 int* offset) {
   // Time in milliseconds which is added to GMT to get local time.
   int gmt_offset = timezone.getRawOffset();
@@ -70,20 +74,34 @@
   return true;
 }
 
+base::string16 WeeklyTimeToLocalizedString(const WeeklyTime& weekly_time,
+                                           base::Clock* clock) {
+  WeeklyTime result = weekly_time;
+  if (!weekly_time.timezone_offset()) {
+    // Get offset to convert the WeeklyTime
+    int offset;
+    if (!GetOffsetFromTimezoneToGmt(*icu::TimeZone::createDefault(), clock,
+                                    &offset)) {
+      LOG(ERROR) << "Unable to obtain offset for time agnostic timezone";
+      return base::string16();
+    }
+    result = weekly_time.ConvertToCustomTimezone(-offset);
+  }
+  // Clock with the current time.
+  WeeklyTime now_weekly_time = WeeklyTime::GetCurrentGmtWeeklyTime(clock);
+  // Offset the current time so that its day of the week and time match
+  // |day_of_week| and |milliseconds_|.
+  base::Time offset_time =
+      clock->Now() + now_weekly_time.GetDurationTo(result.ConvertToTimezone(0));
+  return base::TimeFormatWithPattern(offset_time, kFormatWeekdayHourMinute);
+}
+
 std::vector<WeeklyTimeInterval> ConvertIntervalsToGmt(
-    const std::vector<WeeklyTimeInterval>& intervals,
-    base::Clock* clock,
-    const std::string& timezone) {
-  int gmt_offset = 0;
-  bool no_offset_error =
-      GetOffsetFromTimezoneToGmt(timezone, clock, &gmt_offset);
-  if (!no_offset_error)
-    return {};
+    const std::vector<WeeklyTimeInterval>& intervals) {
   std::vector<WeeklyTimeInterval> gmt_intervals;
   for (const auto& interval : intervals) {
-    // |gmt_offset| is added to input time to get GMT time.
-    auto gmt_start = interval.start().AddMilliseconds(gmt_offset);
-    auto gmt_end = interval.end().AddMilliseconds(gmt_offset);
+    auto gmt_start = interval.start().ConvertToTimezone(0);
+    auto gmt_end = interval.end().ConvertToTimezone(0);
     gmt_intervals.push_back(WeeklyTimeInterval(gmt_start, gmt_end));
   }
   return gmt_intervals;
diff --git a/chrome/browser/chromeos/policy/weekly_time/time_utils.h b/chrome/browser/chromeos/policy/weekly_time/time_utils.h
index 800868c..17ccc6c4 100644
--- a/chrome/browser/chromeos/policy/weekly_time/time_utils.h
+++ b/chrome/browser/chromeos/policy/weekly_time/time_utils.h
@@ -9,11 +9,19 @@
 #include <string>
 #include <vector>
 
-#include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
-#include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
+#include "base/strings/string16.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 
+namespace base {
+class Clock;
+class TimeDelta;
+}  // namespace base
+
 namespace policy {
+
+class WeeklyTime;
+class WeeklyTimeInterval;
+
 namespace weekly_time_utils {
 
 // Put time in milliseconds which is added to local time to get GMT time to
@@ -24,14 +32,24 @@
                                 int* offset);
 
 bool GetOffsetFromTimezoneToGmt(const icu::TimeZone& timezone,
-                                const base::Clock* clock,
+                                base::Clock* clock,
                                 int* offset);
 
-// Convert time intervals from |timezone| to GMT timezone.
+// The output is in the format "EEEE jj:mm a".
+// Example: For a WeeklyTime(4 /* day_of_week */,
+//                           5 * 3600*1000 /* milliseconds */,
+//                           0 /* timezone_offset */)
+// the output should be "Thursday 5:00 AM" in an US locale in GMT timezone.
+// Similarly, the output will be "Donnerstag 05:00" in a German locale in a GMT
+// timezone (there may be slight changes in formatting due to different
+// standards in different locales).
+base::string16 WeeklyTimeToLocalizedString(const WeeklyTime& weekly_time,
+                                           base::Clock* clock);
+
+// Convert time intervals from |timezone| to GMT timezone. Timezone agnostic
+// intervals are not supported.
 std::vector<WeeklyTimeInterval> ConvertIntervalsToGmt(
-    const std::vector<WeeklyTimeInterval>& intervals,
-    base::Clock* clock,
-    const std::string& timezone);
+    const std::vector<WeeklyTimeInterval>& intervals);
 
 // Return duration till next weekly time interval.
 base::TimeDelta GetDeltaTillNextTimeInterval(
diff --git a/chrome/browser/chromeos/policy/weekly_time/time_utils_unittest.cc b/chrome/browser/chromeos/policy/weekly_time/time_utils_unittest.cc
new file mode 100644
index 0000000..13e07c8
--- /dev/null
+++ b/chrome/browser/chromeos/policy/weekly_time/time_utils_unittest.cc
@@ -0,0 +1,148 @@
+// 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/chromeos/policy/weekly_time/time_utils.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/i18n/rtl.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/icu_test_util.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
+#include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace em = enterprise_management;
+
+namespace policy {
+namespace weekly_time_utils {
+
+namespace {
+constexpr int kMinutesInHour = 60;
+constexpr base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1);
+constexpr base::TimeDelta kHour = base::TimeDelta::FromHours(1);
+}  // namespace
+
+class TimeUtilsTimezoneFunctionsTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Daylight savings are off by default
+    SetDaylightSavings(false);
+    timezone_.reset(icu::TimeZone::createDefault());
+    icu::TimeZone::adoptDefault(
+        icu::TimeZone::createTimeZone("America/New_York"));
+  }
+
+  void TearDown() override { icu::TimeZone::adoptDefault(timezone_.release()); }
+
+  void SetDaylightSavings(bool is_daylight_savings) {
+    if (is_daylight_savings) {
+      // Friday July 13th
+      base::Time::Exploded exploded_daylight{2018, 7, 5, 13, 0, 0, 0, 0};
+      base::Time test_time;
+      ASSERT_TRUE(base::Time::FromUTCExploded(exploded_daylight, &test_time));
+      test_clock_.SetNow(test_time);
+    } else {
+      // Sunday January 28
+      base::Time::Exploded exploded_standard{2018, 1, 0, 28, 0, 0, 0, 0};
+      base::Time test_time;
+      ASSERT_TRUE(base::Time::FromUTCExploded(exploded_standard, &test_time));
+      test_clock_.SetNow(test_time);
+    }
+  }
+
+  base::SimpleTestClock test_clock_;
+
+ private:
+  std::unique_ptr<icu::TimeZone> timezone_;
+};
+
+TEST_F(TimeUtilsTimezoneFunctionsTest, ToLocalizedStringDaylightSavings) {
+  base::test::ScopedRestoreICUDefaultLocale restore_locale;
+  SetDaylightSavings(true);
+
+  // 15:50 UTC, 8:50 PT, 11:50 PT
+  WeeklyTime test_weekly_time =
+      WeeklyTime(5, (15 * kMinutesInHour + 50) * kMinute.InMilliseconds(), 0);
+
+  base::i18n::SetICUDefaultLocale("en_US");
+  icu::TimeZone::adoptDefault(
+      icu::TimeZone::createTimeZone("America/Los_Angeles"));
+  EXPECT_EQ(base::UTF8ToUTF16("Friday 8:50 AM"),
+            WeeklyTimeToLocalizedString(test_weekly_time, &test_clock_));
+
+  base::i18n::SetICUDefaultLocale("de_DE");
+  EXPECT_EQ(base::UTF8ToUTF16("Freitag, 08:50"),
+            WeeklyTimeToLocalizedString(test_weekly_time, &test_clock_));
+
+  base::i18n::SetICUDefaultLocale("en_GB");
+  icu::TimeZone::adoptDefault(
+      icu::TimeZone::createTimeZone("America/New_York"));
+  EXPECT_EQ(base::UTF8ToUTF16("Friday 11:50"),
+            WeeklyTimeToLocalizedString(test_weekly_time, &test_clock_));
+}
+
+TEST_F(TimeUtilsTimezoneFunctionsTest, ToLocalizedStringNoDaylightSavings) {
+  base::test::ScopedRestoreICUDefaultLocale restore_locale;
+  SetDaylightSavings(false);
+
+  // 15:50 UTC, 7:50 PST
+  WeeklyTime test_weekly_time =
+      WeeklyTime(5, (15 * kMinutesInHour + 50) * kMinute.InMilliseconds(), 0);
+
+  base::i18n::SetICUDefaultLocale("en_US");
+  icu::TimeZone::adoptDefault(
+      icu::TimeZone::createTimeZone("America/Los_Angeles"));
+  EXPECT_EQ(base::UTF8ToUTF16("Friday 7:50 AM"),
+            WeeklyTimeToLocalizedString(test_weekly_time, &test_clock_));
+}
+
+TEST_F(TimeUtilsTimezoneFunctionsTest, GetOffsetFromTimezoneToGmt) {
+  // GMT + 7
+  auto zone = base::WrapUnique(icu::TimeZone::createTimeZone(
+      icu::UnicodeString::fromUTF8("Asia/Jakarta")));
+  int result;
+  GetOffsetFromTimezoneToGmt(*zone, &test_clock_, &result);
+  // Negative since it's a conversion from |timezone| to GMT.
+  EXPECT_EQ(result, -7 * kHour.InMilliseconds());
+  // Passing in the string should also work and yield the same result.
+  int result2;
+  GetOffsetFromTimezoneToGmt("Asia/Jakarta", &test_clock_, &result2);
+  EXPECT_EQ(result2, result);
+}
+
+TEST_F(TimeUtilsTimezoneFunctionsTest, GetOffsetFromTimezoneToGmtDaylight) {
+  SetDaylightSavings(true);
+  // GMT -7.
+  auto zone = base::WrapUnique(icu::TimeZone::createTimeZone(
+      icu::UnicodeString::fromUTF8("America/Los_Angeles")));
+  int result;
+  GetOffsetFromTimezoneToGmt(*zone, &test_clock_, &result);
+  EXPECT_EQ(result, 7 * kHour.InMilliseconds());
+  // Passing in the string should also work and yield the same result.
+  int result2;
+  GetOffsetFromTimezoneToGmt("America/Los_Angeles", &test_clock_, &result2);
+  EXPECT_EQ(result2, result);
+}
+
+TEST_F(TimeUtilsTimezoneFunctionsTest, GetOffsetFromTimezoneToGmtNoDaylight) {
+  SetDaylightSavings(false);
+  // GMT + 8.
+  auto zone = base::WrapUnique(icu::TimeZone::createTimeZone(
+      icu::UnicodeString::fromUTF8("America/Los_Angeles")));
+  int result;
+  GetOffsetFromTimezoneToGmt(*zone, &test_clock_, &result);
+  EXPECT_EQ(result, 8 * kHour.InMilliseconds());
+  // Passing in the string should also work and yield the same result.
+  int result2;
+  GetOffsetFromTimezoneToGmt("America/Los_Angeles", &test_clock_, &result2);
+  EXPECT_EQ(result2, result);
+}
+
+}  // namespace weekly_time_utils
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/weekly_time/weekly_time.cc b/chrome/browser/chromeos/policy/weekly_time/weekly_time.cc
index ce2be5d..cbacc8b 100644
--- a/chrome/browser/chromeos/policy/weekly_time/weekly_time.cc
+++ b/chrome/browser/chromeos/policy/weekly_time/weekly_time.cc
@@ -4,29 +4,39 @@
 
 #include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
 
-#include "base/i18n/time_formatting.h"
 #include "base/logging.h"
-#include "base/strings/string16.h"
-#include "base/time/default_clock.h"
 #include "base/time/time.h"
 
 namespace em = enterprise_management;
 
 namespace policy {
-namespace {
 
+namespace {
 constexpr base::TimeDelta kWeek = base::TimeDelta::FromDays(7);
 constexpr base::TimeDelta kDay = base::TimeDelta::FromDays(1);
 constexpr base::TimeDelta kHour = base::TimeDelta::FromHours(1);
 constexpr base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1);
 constexpr base::TimeDelta kSecond = base::TimeDelta::FromSeconds(1);
 
-const char* kFormatWeekdayHourMinute = "EEEE jj:mm a";
+WeeklyTime GetWeeklyTimeFromExploded(
+    const base::Time::Exploded& exploded,
+    const base::Optional<int> timezone_offset) {
+  int day_of_week = exploded.day_of_week == 0 ? 7 : exploded.day_of_week;
+  int milliseconds = exploded.hour * kHour.InMilliseconds() +
+                     exploded.minute * kMinute.InMilliseconds() +
+                     exploded.second * kSecond.InMilliseconds() +
+                     exploded.millisecond;
+  return WeeklyTime(day_of_week, milliseconds, timezone_offset);
+}
 
 }  // namespace
 
-WeeklyTime::WeeklyTime(int day_of_week, int milliseconds)
-    : day_of_week_(day_of_week), milliseconds_(milliseconds) {
+WeeklyTime::WeeklyTime(int day_of_week,
+                       int milliseconds,
+                       base::Optional<int> timezone_offset)
+    : day_of_week_(day_of_week),
+      milliseconds_(milliseconds),
+      timezone_offset_(timezone_offset) {
   DCHECK_GT(day_of_week, 0);
   DCHECK_LE(day_of_week, 7);
   DCHECK_GE(milliseconds, 0);
@@ -41,12 +51,21 @@
   auto weekly_time = std::make_unique<base::DictionaryValue>();
   weekly_time->SetInteger("day_of_week", day_of_week_);
   weekly_time->SetInteger("time", milliseconds_);
+  if (timezone_offset_)
+    weekly_time->SetInteger("timezone_offset", timezone_offset_.value());
   return weekly_time;
 }
 
 base::TimeDelta WeeklyTime::GetDurationTo(const WeeklyTime& other) const {
-  int duration = (other.day_of_week() - day_of_week_) * kDay.InMilliseconds() +
-                 other.milliseconds() - milliseconds_;
+  // Can't compare timezone agnostic intervals and non-timezone agnostic
+  // intervals.
+  DCHECK_EQ(timezone_offset_.has_value(), other.timezone_offset().has_value());
+  WeeklyTime other_converted =
+      timezone_offset_ ? other.ConvertToTimezone(timezone_offset_.value())
+                       : other;
+  int duration =
+      (other_converted.day_of_week() - day_of_week_) * kDay.InMilliseconds() +
+      other_converted.milliseconds() - milliseconds_;
   if (duration < 0)
     duration += kWeek.InMilliseconds();
   return base::TimeDelta::FromMilliseconds(duration);
@@ -64,35 +83,40 @@
   // Convert day of week considering week is cyclic. +/- 1 is
   // because day of week is from 1 to 7.
   int result_day_of_week = (day_of_week_ + day_offset - 1) % 7 + 1;
-  return WeeklyTime(result_day_of_week, result_milliseconds);
+  // AddMilliseconds should preserve the timezone.
+  return WeeklyTime(result_day_of_week, result_milliseconds, timezone_offset_);
 }
 
-base::string16 WeeklyTime::ToLocalizedString() const {
-  // Clock with the current time.
-  base::Clock* default_clock = base::DefaultClock::GetInstance();
-  WeeklyTime now_weekly_time = GetCurrentWeeklyTime(default_clock);
-  // Offset the current time so that its day of the week and time match
-  // |day_of_week| and |milliseconds_|.
-  base::Time offset_time =
-      default_clock->Now() + now_weekly_time.GetDurationTo(*this);
-  return base::TimeFormatWithPattern(offset_time, kFormatWeekdayHourMinute);
+WeeklyTime WeeklyTime::ConvertToTimezone(int timezone_offset) const {
+  DCHECK(timezone_offset_);
+  return WeeklyTime(day_of_week_, milliseconds_, timezone_offset)
+      .AddMilliseconds(timezone_offset - timezone_offset_.value());
+}
+
+WeeklyTime WeeklyTime::ConvertToCustomTimezone(int timezone_offset) const {
+  DCHECK(!timezone_offset_);
+  return WeeklyTime(day_of_week_, milliseconds_, timezone_offset);
 }
 
 // static
-WeeklyTime WeeklyTime::GetCurrentWeeklyTime(base::Clock* clock) {
+WeeklyTime WeeklyTime::GetCurrentGmtWeeklyTime(base::Clock* clock) {
   base::Time::Exploded exploded;
   clock->Now().UTCExplode(&exploded);
-  int day_of_week = exploded.day_of_week == 0 ? 7 : exploded.day_of_week;
-  int milliseconds = exploded.hour * kHour.InMilliseconds() +
-                     exploded.minute * kMinute.InMilliseconds() +
-                     exploded.second * kSecond.InMilliseconds() +
-                     exploded.millisecond;
-  return WeeklyTime(day_of_week, milliseconds);
+  return GetWeeklyTimeFromExploded(exploded, 0);
+}
+
+// static
+WeeklyTime WeeklyTime::GetCurrentLocalWeeklyTime(base::Clock* clock) {
+  base::Time::Exploded exploded;
+  clock->Now().LocalExplode(&exploded);
+  WeeklyTime result = GetWeeklyTimeFromExploded(exploded, base::nullopt);
+  return result;
 }
 
 // static
 std::unique_ptr<WeeklyTime> WeeklyTime::ExtractFromProto(
-    const em::WeeklyTimeProto& container) {
+    const em::WeeklyTimeProto& container,
+    base::Optional<int> timezone_offset) {
   if (!container.has_day_of_week() ||
       container.day_of_week() == em::WeeklyTimeProto::DAY_OF_WEEK_UNSPECIFIED) {
     LOG(ERROR) << "Day of week is absent or unspecified.";
@@ -109,7 +133,8 @@
                << ").";
     return nullptr;
   }
-  return std::make_unique<WeeklyTime>(container.day_of_week(), time_of_day);
+  return std::make_unique<WeeklyTime>(container.day_of_week(), time_of_day,
+                                      timezone_offset);
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/weekly_time/weekly_time.h b/chrome/browser/chromeos/policy/weekly_time/weekly_time.h
index f5dd4ea..7c93392f 100644
--- a/chrome/browser/chromeos/policy/weekly_time/weekly_time.h
+++ b/chrome/browser/chromeos/policy/weekly_time/weekly_time.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "base/strings/string16.h"
+#include "base/optional.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -17,11 +17,12 @@
 
 // WeeklyTime class contains day of week and time. Day of week is number from 1
 // to 7 (1 = Monday, 2 = Tuesday, etc.) Time is in milliseconds from the
-// beginning of the day. WeeklyTime's timezone should be interpreted to be in
-// UTC.
+// beginning of the day.
 class WeeklyTime {
  public:
-  WeeklyTime(int day_of_week, int milliseconds);
+  WeeklyTime(int day_of_week,
+             int milliseconds,
+             base::Optional<int> timezone_offset);
 
   WeeklyTime(const WeeklyTime& rhs);
 
@@ -38,30 +39,42 @@
 
   int milliseconds() const { return milliseconds_; }
 
+  base::Optional<int> timezone_offset() const { return timezone_offset_; }
+
   // Return duration from |start| till |end| week times. |end| time
   // is always after |start| time. It's possible because week time is cyclic.
   // (i.e. [Friday 17:00, Monday 9:00) )
+  // Both WeeklyTimes have to have the same kind of timezone (timezone agnostic
+  // or set timezone).
   base::TimeDelta GetDurationTo(const WeeklyTime& other) const;
 
   // Add milliseconds to WeeklyTime.
   WeeklyTime AddMilliseconds(int milliseconds) const;
 
-  // Convert WeeklyTime to a string that is in local time and localized to the
-  // system's language and time display settings. The output is in the format
-  // "EEEE jj:mm a" E.g. for |day_of_week_| = 4 and |milliseconds_| = 5 hours
-  // (in ms) then the output should be "Thursday 5:00 AM" in an US locale in UTC
-  // timezone. Similarly, the output will be "Donnerstag 05:00" in a german
-  // locale in UTC timezone (there may be slight changes due to different
-  // standards in different locales).
-  base::string16 ToLocalizedString() const;
+  // Creates a new WeeklyTime from the current one that has
+  // |timezone_offset_| set to |timezone_offset|. Furthermore, the new
+  // WeeklyTime is offset based on the difference between the timezones. This
+  // function should only take in WeeklyTimes with a defined timezone (i.e. not
+  // nullopt).
+  WeeklyTime ConvertToTimezone(int timezone_offset) const;
+
+  // Creates a new WeeklyTime that has |timezone_offset_| set to
+  // |timezone_offset|. This function is to be used to set the timezone of
+  // timezone agnostic WeeklyTime objects, i.e. objects where |timezone_offset_|
+  // == nullopt.
+  WeeklyTime ConvertToCustomTimezone(int timezone_offset) const;
 
   // Return WeeklyTime structure from WeeklyTimeProto. Return nullptr if
   // WeeklyTime structure isn't correct.
   static std::unique_ptr<WeeklyTime> ExtractFromProto(
-      const enterprise_management::WeeklyTimeProto& container);
+      const enterprise_management::WeeklyTimeProto& container,
+      base::Optional<int> timezone_offset);
 
-  // Return current time in WeeklyTime structure.
-  static WeeklyTime GetCurrentWeeklyTime(base::Clock* clock);
+  // Return the current time in GMT in WeeklyTime structure.
+  static WeeklyTime GetCurrentGmtWeeklyTime(base::Clock* clock);
+
+  // Return the current time in the system's local time in WeeklyTime structure.
+  static WeeklyTime GetCurrentLocalWeeklyTime(base::Clock* clock);
 
  private:
   // Number of weekday (1 = Monday, 2 = Tuesday, etc.)
@@ -69,6 +82,14 @@
 
   // Time of day in milliseconds from the beginning of the day.
   int milliseconds_;
+
+  // Offset from GMT in milliseconds for the timezone that the Weekly Time is
+  // in. If |timezone_offset_| is 0 then it the WeeklyTime will be considered to
+  // be in GMT. If |timezone_offset_| is non-zero, then the WeeklyTime will be
+  // considered to be in the timezone corresponding to that offset. If
+  // |timezone_offset_| is |nullopt|, then it will be interpreted to be in the
+  // system's local timezone.
+  base::Optional<int> timezone_offset_;
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.cc b/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.cc
index 3c2f86f..0b822004 100644
--- a/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.cc
+++ b/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h"
+
 #include "base/logging.h"
 #include "base/time/time.h"
 
@@ -14,6 +15,7 @@
                                        const WeeklyTime& end)
     : start_(start), end_(end) {
   DCHECK_GT(start.GetDurationTo(end), base::TimeDelta());
+  DCHECK(start.timezone_offset() == end.timezone_offset());
 }
 
 WeeklyTimeInterval::WeeklyTimeInterval(const WeeklyTimeInterval& rhs) = default;
@@ -29,6 +31,8 @@
 }
 
 bool WeeklyTimeInterval::Contains(const WeeklyTime& w) const {
+  DCHECK_EQ(start_.timezone_offset().has_value(),
+            w.timezone_offset().has_value());
   if (w.GetDurationTo(end_).is_zero())
     return false;
   base::TimeDelta interval_duration = start_.GetDurationTo(end_);
@@ -37,13 +41,14 @@
 
 // static
 std::unique_ptr<WeeklyTimeInterval> WeeklyTimeInterval::ExtractFromProto(
-    const em::WeeklyTimeIntervalProto& container) {
+    const em::WeeklyTimeIntervalProto& container,
+    base::Optional<int> timezone_offset) {
   if (!container.has_start() || !container.has_end()) {
     LOG(WARNING) << "Interval without start or/and end.";
     return nullptr;
   }
-  auto start = WeeklyTime::ExtractFromProto(container.start());
-  auto end = WeeklyTime::ExtractFromProto(container.end());
+  auto start = WeeklyTime::ExtractFromProto(container.start(), timezone_offset);
+  auto end = WeeklyTime::ExtractFromProto(container.end(), timezone_offset);
   if (!start || !end)
     return nullptr;
   return std::make_unique<WeeklyTimeInterval>(*start, *end);
diff --git a/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h b/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h
index 909887e0..3985dad 100644
--- a/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h
+++ b/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/optional.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
@@ -16,6 +17,7 @@
 // Represents non-empty time interval [start, end) between two weekly times.
 // Interval can be wrapped across the end of the week.
 // Interval is empty if start = end. Empty intervals aren't allowed.
+// Both WeeklyTimes need to have the same timezone_offset.
 class WeeklyTimeInterval {
  public:
   WeeklyTimeInterval(const WeeklyTime& start, const WeeklyTime& end);
@@ -31,18 +33,27 @@
   // { "day_of_week" : int # value is from 1 to 7 (1 = Monday, 2 = Tuesday,
   // etc.)
   //   "time" : int # in milliseconds from the beginning of the day.
+  //   "timezone_offset" : int # in milliseconds, how much time ahead of GMT.
   // }
   std::unique_ptr<base::DictionaryValue> ToValue() const;
 
   // Check if |w| is in [WeeklyTimeIntervall.start, WeeklyTimeInterval.end).
   // |end| time is always after |start| time. It's possible because week time is
   // cyclic. (i.e. [Friday 17:00, Monday 9:00) )
+  // |w| must be in the same type of timezone as the interval (timezone agnostic
+  // or in a set timezone).
   bool Contains(const WeeklyTime& w) const;
 
+  // Returns the timezone_offset that |start_| and |end_| have.
+  base::Optional<int> GetIntervalOffset(int timezone_offset) const {
+    return start_.timezone_offset();
+  }
+
   // Return time interval made from WeeklyTimeIntervalProto structure. Return
   // nullptr if the proto contains an invalid interval.
   static std::unique_ptr<WeeklyTimeInterval> ExtractFromProto(
-      const enterprise_management::WeeklyTimeIntervalProto& container);
+      const enterprise_management::WeeklyTimeIntervalProto& container,
+      base::Optional<int> timezone_offset);
 
   WeeklyTime start() const { return start_; }
 
diff --git a/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval_unittest.cc b/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval_unittest.cc
index e3b1b708..bcd0051 100644
--- a/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval_unittest.cc
+++ b/chrome/browser/chromeos/policy/weekly_time/weekly_time_interval_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/policy/weekly_time/weekly_time.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -53,10 +54,10 @@
 };
 
 TEST_P(SingleWeeklyTimeIntervalTest, Constructor) {
-  WeeklyTime start =
-      WeeklyTime(start_day_of_week(), start_time() * kMinute.InMilliseconds());
+  WeeklyTime start = WeeklyTime(start_day_of_week(),
+                                start_time() * kMinute.InMilliseconds(), 0);
   WeeklyTime end =
-      WeeklyTime(end_day_of_week(), end_time() * kMinute.InMilliseconds());
+      WeeklyTime(end_day_of_week(), end_time() * kMinute.InMilliseconds(), 0);
   WeeklyTimeInterval interval = WeeklyTimeInterval(start, end);
   EXPECT_EQ(interval.start().day_of_week(), start_day_of_week());
   EXPECT_EQ(interval.start().milliseconds(),
@@ -64,11 +65,14 @@
   EXPECT_EQ(interval.end().day_of_week(), end_day_of_week());
   EXPECT_EQ(interval.end().milliseconds(),
             end_time() * kMinute.InMilliseconds());
+  EXPECT_EQ(interval.start().timezone_offset(),
+            interval.end().timezone_offset());
+  EXPECT_EQ(interval.start().timezone_offset(), 0);
 }
 
 TEST_P(SingleWeeklyTimeIntervalTest, ToValue) {
-  WeeklyTime start = WeeklyTime(start_day_of_week(), start_time());
-  WeeklyTime end = WeeklyTime(end_day_of_week(), end_time());
+  WeeklyTime start = WeeklyTime(start_day_of_week(), start_time(), 0);
+  WeeklyTime end = WeeklyTime(end_day_of_week(), end_time(), 0);
   WeeklyTimeInterval interval = WeeklyTimeInterval(start, end);
   std::unique_ptr<base::DictionaryValue> interval_value = interval.ToValue();
   base::DictionaryValue expected_interval_value;
@@ -79,7 +83,7 @@
 
 TEST_P(SingleWeeklyTimeIntervalTest, ExtractFromProto_Empty) {
   em::WeeklyTimeIntervalProto interval_proto;
-  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto);
+  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto, 0);
   ASSERT_FALSE(result);
 }
 
@@ -88,7 +92,7 @@
   em::WeeklyTimeProto* start = interval_proto.mutable_start();
   start->set_day_of_week(kWeekdays[start_day_of_week()]);
   start->set_time(start_time());
-  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto);
+  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto, 0);
   ASSERT_FALSE(result);
 }
 
@@ -97,7 +101,7 @@
   em::WeeklyTimeProto* end = interval_proto.mutable_end();
   end->set_day_of_week(kWeekdays[end_day_of_week()]);
   end->set_time(end_time());
-  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto);
+  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto, 0);
   ASSERT_FALSE(result);
 }
 
@@ -109,7 +113,7 @@
   start->set_time(start_time());
   end->set_day_of_week(kWeekdays[end_day_of_week()]);
   end->set_time(end_time());
-  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto);
+  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto, 0);
   ASSERT_FALSE(result);
 }
 
@@ -121,7 +125,7 @@
   start->set_time(start_time());
   end->set_day_of_week(kWeekdays[0]);
   end->set_time(end_time());
-  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto);
+  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto, 0);
   ASSERT_FALSE(result);
 }
 
@@ -133,12 +137,13 @@
   start->set_time(start_time());
   end->set_day_of_week(kWeekdays[end_day_of_week()]);
   end->set_time(end_time());
-  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto);
+  auto result = WeeklyTimeInterval::ExtractFromProto(interval_proto, 0);
   ASSERT_TRUE(result);
   EXPECT_EQ(result->start().day_of_week(), start_day_of_week());
   EXPECT_EQ(result->start().milliseconds(), start_time());
   EXPECT_EQ(result->end().day_of_week(), end_day_of_week());
   EXPECT_EQ(result->end().milliseconds(), end_time());
+  EXPECT_EQ(result->start().timezone_offset(), 0);
 }
 
 INSTANTIATE_TEST_CASE_P(OneMinuteInterval,
@@ -175,13 +180,13 @@
 };
 
 TEST_P(WeeklyTimeIntervalAndWeeklyTimeTest, Contains) {
-  WeeklyTime start =
-      WeeklyTime(start_day_of_week(), start_time() * kMinute.InMilliseconds());
+  WeeklyTime start = WeeklyTime(start_day_of_week(),
+                                start_time() * kMinute.InMilliseconds(), 0);
   WeeklyTime end =
-      WeeklyTime(end_day_of_week(), end_time() * kMinute.InMilliseconds());
+      WeeklyTime(end_day_of_week(), end_time() * kMinute.InMilliseconds(), 0);
   WeeklyTimeInterval interval = WeeklyTimeInterval(start, end);
   WeeklyTime weekly_time = WeeklyTime(
-      current_day_of_week(), current_time() * kMinute.InMilliseconds());
+      current_day_of_week(), current_time() * kMinute.InMilliseconds(), 0);
   EXPECT_EQ(interval.Contains(weekly_time), expected_contains());
 }
 
diff --git a/chrome/browser/chromeos/policy/weekly_time/weekly_time_unittest.cc b/chrome/browser/chromeos/policy/weekly_time/weekly_time_unittest.cc
index c78d968..b2cb69a2 100644
--- a/chrome/browser/chromeos/policy/weekly_time/weekly_time_unittest.cc
+++ b/chrome/browser/chromeos/policy/weekly_time/weekly_time_unittest.cc
@@ -11,8 +11,10 @@
 #include "base/callback_helpers.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/ptr_util.h"
+#include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/icu_test_util.h"
+#include "base/test/simple_test_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
@@ -45,8 +47,8 @@
     em::WeeklyTimeProto::SATURDAY,
     em::WeeklyTimeProto::SUNDAY};
 
-const int kMinutesInHour = 60;
-
+constexpr int kMinutesInHour = 60;
+constexpr int kMillisecondsInHour = 3600000;
 constexpr base::TimeDelta kMinute = base::TimeDelta::FromMinutes(1);
 constexpr base::TimeDelta kHour = base::TimeDelta::FromHours(1);
 constexpr base::TimeDelta kWeek = base::TimeDelta::FromDays(7);
@@ -54,27 +56,35 @@
 }  // namespace
 
 class SingleWeeklyTimeTest
-    : public testing::TestWithParam<std::tuple<int, int>> {
+    : public testing::TestWithParam<std::tuple<int, int, base::Optional<int>>> {
  public:
   int day_of_week() const { return std::get<0>(GetParam()); }
   int minutes() const { return std::get<1>(GetParam()); }
+  base::Optional<int> timezone_offset() const {
+    return std::get<2>(GetParam());
+  }
 };
 
 TEST_P(SingleWeeklyTimeTest, Constructor) {
-  WeeklyTime weekly_time =
-      WeeklyTime(day_of_week(), minutes() * kMinute.InMilliseconds());
+  WeeklyTime weekly_time = WeeklyTime(
+      day_of_week(), minutes() * kMinute.InMilliseconds(), timezone_offset());
   EXPECT_EQ(weekly_time.day_of_week(), day_of_week());
   EXPECT_EQ(weekly_time.milliseconds(), minutes() * kMinute.InMilliseconds());
+  EXPECT_EQ(weekly_time.timezone_offset(), timezone_offset());
 }
 
 TEST_P(SingleWeeklyTimeTest, ToValue) {
-  WeeklyTime weekly_time =
-      WeeklyTime(day_of_week(), minutes() * kMinute.InMilliseconds());
+  WeeklyTime weekly_time = WeeklyTime(
+      day_of_week(), minutes() * kMinute.InMilliseconds(), timezone_offset());
   std::unique_ptr<base::DictionaryValue> weekly_time_value =
       weekly_time.ToValue();
   base::DictionaryValue expected_weekly_time;
   expected_weekly_time.SetInteger("day_of_week", day_of_week());
   expected_weekly_time.SetInteger("time", minutes() * kMinute.InMilliseconds());
+  if (timezone_offset()) {
+    expected_weekly_time.SetInteger("timezone_offset",
+                                    timezone_offset().value());
+  }
   EXPECT_EQ(*weekly_time_value, expected_weekly_time);
 }
 
@@ -83,7 +93,7 @@
   em::WeeklyTimeProto proto;
   proto.set_day_of_week(kWeekdays[0]);
   proto.set_time(milliseconds);
-  auto result = WeeklyTime::ExtractFromProto(proto);
+  auto result = WeeklyTime::ExtractFromProto(proto, timezone_offset());
   ASSERT_FALSE(result);
 }
 
@@ -91,7 +101,7 @@
   em::WeeklyTimeProto proto;
   proto.set_day_of_week(kWeekdays[day_of_week()]);
   proto.set_time(-1);
-  auto result = WeeklyTime::ExtractFromProto(proto);
+  auto result = WeeklyTime::ExtractFromProto(proto, timezone_offset());
   ASSERT_FALSE(result);
 }
 
@@ -100,25 +110,27 @@
   em::WeeklyTimeProto proto;
   proto.set_day_of_week(kWeekdays[day_of_week()]);
   proto.set_time(milliseconds);
-  auto result = WeeklyTime::ExtractFromProto(proto);
+  auto result = WeeklyTime::ExtractFromProto(proto, timezone_offset());
   ASSERT_TRUE(result);
   EXPECT_EQ(result->day_of_week(), day_of_week());
   EXPECT_EQ(result->milliseconds(), milliseconds);
+  EXPECT_EQ(result->timezone_offset(), timezone_offset());
 }
 
-INSTANTIATE_TEST_CASE_P(TheSmallestCase,
-                        SingleWeeklyTimeTest,
-                        testing::Values(std::make_tuple(kMonday, 0)));
+INSTANTIATE_TEST_CASE_P(
+    TheSmallestCase,
+    SingleWeeklyTimeTest,
+    testing::Values(std::make_tuple(kMonday, 0, base::nullopt)));
 
 INSTANTIATE_TEST_CASE_P(
     TheBiggestCase,
     SingleWeeklyTimeTest,
-    testing::Values(std::make_tuple(kSunday, 24 * kMinutesInHour - 1)));
+    testing::Values(std::make_tuple(kSunday, 24 * kMinutesInHour - 1, 0)));
 
 INSTANTIATE_TEST_CASE_P(
     RandomCase,
     SingleWeeklyTimeTest,
-    testing::Values(std::make_tuple(kWednesday, 15 * kMinutesInHour + 30)));
+    testing::Values(std::make_tuple(kWednesday, 15 * kMinutesInHour + 30, 10)));
 
 class TwoWeeklyTimesAndDurationTest
     : public testing::TestWithParam<
@@ -133,9 +145,9 @@
 
 TEST_P(TwoWeeklyTimesAndDurationTest, GetDuration) {
   WeeklyTime weekly_time1 =
-      WeeklyTime(day1(), minutes1() * kMinute.InMilliseconds());
+      WeeklyTime(day1(), minutes1() * kMinute.InMilliseconds(), 0);
   WeeklyTime weekly_time2 =
-      WeeklyTime(day2(), minutes2() * kMinute.InMilliseconds());
+      WeeklyTime(day2(), minutes2() * kMinute.InMilliseconds(), 0);
   EXPECT_EQ(weekly_time1.GetDurationTo(weekly_time2), expected_duration());
 }
 
@@ -169,6 +181,65 @@
                             base::TimeDelta::FromHours(2) +
                             base::TimeDelta::FromMinutes(15))));
 
+class TwoWeeklyTimesAndDurationInDifferentTimezonesTest
+    : public testing::TestWithParam<std::tuple<int,
+                                               int,
+                                               base::Optional<int>,
+                                               int,
+                                               int,
+                                               base::Optional<int>,
+                                               base::TimeDelta>> {
+ public:
+  int day1() const { return std::get<0>(GetParam()); }
+  int minutes1() const { return std::get<1>(GetParam()); }
+  base::Optional<int> offset1() const { return std::get<2>(GetParam()); }
+  int day2() const { return std::get<3>(GetParam()); }
+  int minutes2() const { return std::get<4>(GetParam()); }
+  base::Optional<int> offset2() const { return std::get<5>(GetParam()); }
+  base::TimeDelta expected_duration() const { return std::get<6>(GetParam()); }
+};
+
+TEST_P(TwoWeeklyTimesAndDurationInDifferentTimezonesTest, ConvertToTimezone) {
+  WeeklyTime weekly_time1 =
+      WeeklyTime(day1(), minutes1() * kMinute.InMilliseconds(), offset1());
+  WeeklyTime weekly_time2 =
+      WeeklyTime(day2(), minutes2() * kMinute.InMilliseconds(), offset2());
+  EXPECT_EQ(weekly_time1.GetDurationTo(weekly_time2), expected_duration());
+}
+
+INSTANTIATE_TEST_CASE_P(
+    DifferentTimezones,
+    TwoWeeklyTimesAndDurationInDifferentTimezonesTest,
+    testing::Values(std::make_tuple(kMonday,
+                                    kMinutesInHour,
+                                    kMillisecondsInHour,
+                                    kMonday,
+                                    kMinutesInHour,
+                                    5 * kMillisecondsInHour,
+                                    kWeek - base::TimeDelta::FromHours(4))));
+
+INSTANTIATE_TEST_CASE_P(
+    TimezoneMakesDurationWrapAround,
+    TwoWeeklyTimesAndDurationInDifferentTimezonesTest,
+    testing::Values(std::make_tuple(kMonday,
+                                    kMinutesInHour,
+                                    5 * kMillisecondsInHour,
+                                    kMonday,
+                                    kMinutesInHour,
+                                    4 * kMillisecondsInHour,
+                                    base::TimeDelta::FromHours(1))));
+
+INSTANTIATE_TEST_CASE_P(
+    TwoAgnosticTimezones,
+    TwoWeeklyTimesAndDurationInDifferentTimezonesTest,
+    testing::Values(std::make_tuple(kMonday,
+                                    10 * kMinutesInHour,
+                                    base::nullopt,
+                                    kTuesday,
+                                    5 * kMinutesInHour,
+                                    base::nullopt,
+                                    base::TimeDelta::FromHours(19))));
+
 class TwoWeeklyTimesAndOffsetTest
     : public testing::TestWithParam<std::tuple<int, int, int, int, int>> {
  public:
@@ -181,12 +252,14 @@
 
 TEST_P(TwoWeeklyTimesAndOffsetTest, AddMilliseconds) {
   WeeklyTime weekly_time =
-      WeeklyTime(day_of_week(), minutes() * kMinute.InMilliseconds());
+      WeeklyTime(day_of_week(), minutes() * kMinute.InMilliseconds(), 10);
   WeeklyTime result_weekly_time =
       weekly_time.AddMilliseconds(offset_minutes() * kMinute.InMilliseconds());
   EXPECT_EQ(result_weekly_time.day_of_week(), expected_day());
   EXPECT_EQ(result_weekly_time.milliseconds(),
             expected_minutes() * kMinute.InMilliseconds());
+  EXPECT_EQ(result_weekly_time.timezone_offset(),
+            weekly_time.timezone_offset());
 }
 
 INSTANTIATE_TEST_CASE_P(
@@ -245,35 +318,63 @@
                                     kThursday,
                                     15 * kMinutesInHour + 24)));
 
-TEST(WeeklyTimeStringTest, ToLocalizedString) {
-  base::test::ScopedRestoreICUDefaultLocale restore_locale;
+class WeeklyTimeTimezoneConversionTest
+    : public testing::TestWithParam<std::tuple<int, int, int, int, int, int>> {
+ public:
+  int day() { return std::get<0>(GetParam()); }
+  int minutes() { return std::get<1>(GetParam()); }
+  int timezone_offset() { return std::get<2>(GetParam()); }
+  int result_day() { return std::get<3>(GetParam()); }
+  int result_minutes() { return std::get<4>(GetParam()); }
+  int result_offset() { return std::get<5>(GetParam()); }
+};
 
-  // 15:50 UTC, 8:50 PT, 11:50 PT
-  WeeklyTime test_weekly_time =
-      WeeklyTime(5, (15 * kMinutesInHour + 50) * kMinute.InMilliseconds());
-
-  // Save original timezone
-  base::ScopedClosureRunner reset_timezone(base::BindOnce(
-      [](std::unique_ptr<icu::TimeZone> original_timezone) {
-        icu::TimeZone::adoptDefault(original_timezone.release());
-      },
-      base::WrapUnique<icu::TimeZone>(icu::TimeZone::createDefault())));
-
-  base::i18n::SetICUDefaultLocale("en_US");
-  icu::TimeZone::adoptDefault(
-      icu::TimeZone::createTimeZone("America/Los_Angeles"));
-  EXPECT_EQ(base::UTF8ToUTF16("Friday 8:50 AM"),
-            test_weekly_time.ToLocalizedString());
-
-  base::i18n::SetICUDefaultLocale("de_DE");
-  EXPECT_EQ(base::UTF8ToUTF16("Freitag, 08:50"),
-            test_weekly_time.ToLocalizedString());
-
-  base::i18n::SetICUDefaultLocale("en_GB");
-  icu::TimeZone::adoptDefault(
-      icu::TimeZone::createTimeZone("America/New_York"));
-  EXPECT_EQ(base::UTF8ToUTF16("Friday 11:50"),
-            test_weekly_time.ToLocalizedString());
+TEST_P(WeeklyTimeTimezoneConversionTest, ConvertToTimezone) {
+  WeeklyTime weekly_time = WeeklyTime(
+      day(), minutes() * kMinute.InMilliseconds(), timezone_offset());
+  WeeklyTime result = weekly_time.ConvertToTimezone(result_offset());
+  EXPECT_EQ(result.day_of_week(), result_day());
+  EXPECT_EQ(result.milliseconds(), result_minutes() * kMinute.InMilliseconds());
+  EXPECT_EQ(result.timezone_offset().value(), result_offset());
 }
 
+INSTANTIATE_TEST_CASE_P(
+    ConversionToABiggerTimezone,
+    WeeklyTimeTimezoneConversionTest,
+    testing::Values(std::make_tuple(kMonday,
+                                    10 * kMinutesInHour,
+                                    2 * kMillisecondsInHour,
+                                    kMonday,
+                                    15 * kMinutesInHour,
+                                    7 * kMillisecondsInHour)));
+
+INSTANTIATE_TEST_CASE_P(ConversionToASmallerTimezone,
+                        WeeklyTimeTimezoneConversionTest,
+                        testing::Values(std::make_tuple(kMonday,
+                                                        10 * kMinutesInHour,
+                                                        4 * kMillisecondsInHour,
+                                                        kMonday,
+                                                        6 * kMinutesInHour,
+                                                        0)));
+
+INSTANTIATE_TEST_CASE_P(
+    ConversionToTheSameTimezone,
+    WeeklyTimeTimezoneConversionTest,
+    testing::Values(std::make_tuple(kMonday,
+                                    10 * kMinutesInHour,
+                                    4 * kMillisecondsInHour,
+                                    kMonday,
+                                    10 * kMinutesInHour,
+                                    4 * kMillisecondsInHour)));
+
+INSTANTIATE_TEST_CASE_P(
+    ConversionToANegativeTimezone,
+    WeeklyTimeTimezoneConversionTest,
+    testing::Values(std::make_tuple(kMonday,
+                                    15 * kMinutesInHour,
+                                    2 * kMillisecondsInHour,
+                                    kMonday,
+                                    9 * kMinutesInHour,
+                                    -4 * kMillisecondsInHour)));
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index 32194a9b..da1f5895 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -6,10 +6,13 @@
 
 #include <cmath>
 
+#include "ash/public/cpp/ash_pref_names.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chromeos/power/ml/real_boot_clock.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/resource_coordinator/tab_metrics_logger.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -235,7 +238,16 @@
   screen_off_occurred_ = false;
   screen_lock_occurred_ = false;
   ExtractFeatures(activity_data);
-  if (base::FeatureList::IsEnabled(features::kUserActivityPrediction) &&
+  // Default is to enable smart dim, unless user profile specifically says
+  // otherwise.
+  bool smart_dim_enabled = true;
+  const Profile* const profile = ProfileManager::GetActiveUserProfile();
+  if (profile) {
+    smart_dim_enabled =
+        profile->GetPrefs()->GetBoolean(ash::prefs::kPowerSmartDimEnabled);
+  }
+  if (smart_dim_enabled &&
+      base::FeatureList::IsEnabled(features::kUserActivityPrediction) &&
       smart_dim_model_) {
     // Decide whether to defer the imminent screen dim.
     UserActivityEvent::ModelPrediction model_prediction =
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index 8272a83..80260780 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -47,9 +47,12 @@
 };
 
 const ComponentConfig* FindConfig(const std::string& name) {
-  return std::find_if(
+  const ComponentConfig* config = std::find_if(
       std::begin(kConfigs), std::end(kConfigs),
       [&name](const ComponentConfig& config) { return config.name == name; });
+  if (config == std::end(kConfigs))
+    return nullptr;
+  return config;
 }
 
 // TODO(xiaochu): add metrics for component usage (https://crbug.com/793052).
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
index b646d71..90503a0 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.cc
@@ -156,10 +156,13 @@
     ModuleDatabaseEventSource* module_database_event_source,
     const CertificateInfo& exe_certificate_info,
     scoped_refptr<ModuleListFilter> module_list_filter,
+    const std::vector<third_party_dlls::PackedListModule>&
+        initial_blacklisted_modules,
     OnCacheUpdatedCallback on_cache_updated_callback)
     : module_database_event_source_(module_database_event_source),
       exe_certificate_info_(exe_certificate_info),
       module_list_filter_(std::move(module_list_filter)),
+      initial_blacklisted_modules_(initial_blacklisted_modules),
       on_cache_updated_callback_(std::move(on_cache_updated_callback)),
       background_sequence_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
@@ -283,13 +286,27 @@
     return;
   }
 
-  // Now it has been determined that the module should be blocked.
+  // Now it has been determined that the module should be blocked. So make sure
+  // it gets added to the blacklist cache.
+  InsertPackedListModule(module_key, &newly_blacklisted_modules_);
+
+  // Check if a blacklisted module was able to bypass the blocking.
+  if (std::binary_search(std::begin(initial_blacklisted_modules_),
+                         std::end(initial_blacklisted_modules_),
+                         newly_blacklisted_modules_.back(),
+                         internal::ModuleLess())) {
+    module_blocking_decisions_[module_key.module_id] =
+        ModuleBlockingDecision::kBypassedBlocking;
+
+    // Return here and don't notify the ModuleDatabase that the module was added
+    // to the blacklist so that it can trigger an incompatible applications
+    // warning.
+    return;
+  }
+
   module_blocking_decisions_[module_key.module_id] =
       ModuleBlockingDecision::kBlacklisted;
 
-  // Insert the blacklisted module.
-  InsertPackedListModule(module_key, &newly_blacklisted_modules_);
-
   // Signal the module database that this module will be added to the cache.
   // Note that observers that care about this information should register to
   // the Module Database's observer interface after the ModuleBlacklistCache
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
index 846cd9f2..ad9c05d 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win.h
@@ -100,6 +100,8 @@
     kBlacklisted,
     // The module was blocked from loading into the process.
     kBlocked,
+    // This module should have been blocked but wasn't.
+    kBypassedBlocking,
   };
 
   struct CacheUpdateResult {
@@ -123,6 +125,8 @@
       ModuleDatabaseEventSource* module_database_event_source,
       const CertificateInfo& exe_certificate_info,
       scoped_refptr<ModuleListFilter> module_list_filter,
+      const std::vector<third_party_dlls::PackedListModule>&
+          initial_blacklisted_modules,
       OnCacheUpdatedCallback on_cache_updated_callback);
   ~ModuleBlacklistCacheUpdater() override;
 
@@ -161,6 +165,8 @@
 
   const CertificateInfo& exe_certificate_info_;
   scoped_refptr<ModuleListFilter> module_list_filter_;
+  const std::vector<third_party_dlls::PackedListModule>&
+      initial_blacklisted_modules_;
 
   OnCacheUpdatedCallback on_cache_updated_callback_;
 
diff --git a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
index c8a662f..9ed72f2 100644
--- a/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
+++ b/chrome/browser/conflicts/module_blacklist_cache_updater_win_unittest.cc
@@ -117,6 +117,7 @@
   CreateModuleBlacklistCacheUpdater() {
     return std::make_unique<ModuleBlacklistCacheUpdater>(
         this, exe_certificate_info_, module_list_filter_,
+        initial_blacklisted_modules_,
         base::BindRepeating(
             &ModuleBlacklistCacheUpdaterTest::OnModuleBlacklistCacheUpdated,
             base::Unretained(this)));
@@ -184,6 +185,7 @@
 
   CertificateInfo exe_certificate_info_;
   scoped_refptr<ModuleListFilter> module_list_filter_;
+  std::vector<third_party_dlls::PackedListModule> initial_blacklisted_modules_;
 
   base::FilePath module_blacklist_cache_path_;
 
diff --git a/chrome/browser/conflicts/third_party_conflicts_manager_win.cc b/chrome/browser/conflicts/third_party_conflicts_manager_win.cc
index 5784dfc..ff05dcb6 100644
--- a/chrome/browser/conflicts/third_party_conflicts_manager_win.cc
+++ b/chrome/browser/conflicts/third_party_conflicts_manager_win.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/conflicts/incompatible_applications_updater_win.h"
 #include "chrome/browser/conflicts/installed_applications_win.h"
 #include "chrome/browser/conflicts/module_blacklist_cache_updater_win.h"
+#include "chrome/browser/conflicts/module_blacklist_cache_util_win.h"
 #include "chrome/browser/conflicts/module_info_util_win.h"
 #include "chrome/browser/conflicts/module_list_filter_win.h"
 #include "chrome/common/chrome_features.h"
@@ -53,6 +54,26 @@
   return module_list_filter;
 }
 
+std::unique_ptr<std::vector<third_party_dlls::PackedListModule>>
+ReadInitialBlacklistedModules() {
+  base::FilePath path =
+      ModuleBlacklistCacheUpdater::GetModuleBlacklistCachePath();
+
+  third_party_dlls::PackedListMetadata metadata;
+  std::vector<third_party_dlls::PackedListModule> blacklisted_modules;
+  base::MD5Digest md5_digest;
+  ReadResult read_result = ReadModuleBlacklistCache(
+      path, &metadata, &blacklisted_modules, &md5_digest);
+
+  // Return an empty vector on failure.
+  auto initial_blacklisted_modules =
+      std::make_unique<std::vector<third_party_dlls::PackedListModule>>();
+  if (read_result == ReadResult::kSuccess)
+    *initial_blacklisted_modules = std::move(blacklisted_modules);
+
+  return initial_blacklisted_modules;
+}
+
 }  // namespace
 
 ThirdPartyConflictsManager::ThirdPartyConflictsManager(
@@ -123,16 +144,26 @@
 
   // The InstalledApplications instance is only needed for the incompatible
   // applications warning.
-  if (!IncompatibleApplicationsUpdater::IsWarningEnabled())
-    return;
+  if (IncompatibleApplicationsUpdater::IsWarningEnabled()) {
+    base::PostTaskAndReplyWithResult(
+        background_sequence_.get(), FROM_HERE, base::BindOnce([]() {
+          return std::make_unique<InstalledApplications>();
+        }),
+        base::BindOnce(
+            &ThirdPartyConflictsManager::OnInstalledApplicationsCreated,
+            weak_ptr_factory_.GetWeakPtr()));
+  }
 
-  base::PostTaskAndReplyWithResult(
-      background_sequence_.get(), FROM_HERE, base::BindOnce([]() {
-        return std::make_unique<InstalledApplications>();
-      }),
-      base::BindOnce(
-          &ThirdPartyConflictsManager::OnInstalledApplicationsCreated,
-          weak_ptr_factory_.GetWeakPtr()));
+  // And the initial blacklisted modules are only needed for the third-party
+  // modules blocking.
+  if (base::FeatureList::IsEnabled(features::kThirdPartyModulesBlocking)) {
+    base::PostTaskAndReplyWithResult(
+        background_sequence_.get(), FROM_HERE,
+        base::BindOnce(&ReadInitialBlacklistedModules),
+        base::BindOnce(
+            &ThirdPartyConflictsManager::OnInitialBlacklistedModulesRead,
+            weak_ptr_factory_.GetWeakPtr()));
+  }
 }
 
 void ThirdPartyConflictsManager::OnModuleListComponentRegistered(
@@ -270,23 +301,43 @@
   InitializeIfReady();
 }
 
+void ThirdPartyConflictsManager::OnInitialBlacklistedModulesRead(
+    std::unique_ptr<std::vector<third_party_dlls::PackedListModule>>
+        initial_blacklisted_modules) {
+  initial_blacklisted_modules_ = std::move(initial_blacklisted_modules);
+
+  InitializeIfReady();
+}
+
 void ThirdPartyConflictsManager::InitializeIfReady() {
   DCHECK(!terminal_state_.has_value());
 
-  // Check if this instance is ready to initialize.
-  if (!exe_certificate_info_ || !module_list_filter_ ||
-      (!installed_applications_ &&
-       IncompatibleApplicationsUpdater::IsWarningEnabled())) {
+  // Check if this instance is ready to initialize. First look at dependencies
+  // that both features need.
+  if (!exe_certificate_info_ || !module_list_filter_)
+    return;
+
+  // Then look at the dependency needed only for the
+  // IncompatibleApplicationsWarning feature.
+  if (IncompatibleApplicationsUpdater::IsWarningEnabled() &&
+      !installed_applications_) {
     return;
   }
 
+  // And the dependency needed only for the ThirdPartyModulesBlocking feature.
+  if (base::FeatureList::IsEnabled(features::kThirdPartyModulesBlocking) &&
+      !initial_blacklisted_modules_) {
+    return;
+  }
+
+  // Now both features are ready to be initialized.
   if (base::FeatureList::IsEnabled(features::kThirdPartyModulesBlocking)) {
     // It is safe to use base::Unretained() since the callback will not be
     // invoked if the updater is freed.
     module_blacklist_cache_updater_ =
         std::make_unique<ModuleBlacklistCacheUpdater>(
             module_database_event_source_, *exe_certificate_info_,
-            module_list_filter_,
+            module_list_filter_, *initial_blacklisted_modules_,
             base::BindRepeating(
                 &ThirdPartyConflictsManager::OnModuleBlacklistCacheUpdated,
                 base::Unretained(this)));
diff --git a/chrome/browser/conflicts/third_party_conflicts_manager_win.h b/chrome/browser/conflicts/third_party_conflicts_manager_win.h
index 73d98cb..d6b89c9c 100644
--- a/chrome/browser/conflicts/third_party_conflicts_manager_win.h
+++ b/chrome/browser/conflicts/third_party_conflicts_manager_win.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -17,6 +18,7 @@
 #include "base/strings/string_piece_forward.h"
 #include "chrome/browser/conflicts/module_blacklist_cache_updater_win.h"
 #include "chrome/browser/conflicts/module_database_observer_win.h"
+#include "chrome_elf/third_party_dlls/packed_list_format.h"
 #include "components/component_updater/component_updater_service.h"
 
 class IncompatibleApplicationsUpdater;
@@ -31,12 +33,31 @@
 class TaskRunner;
 }
 
-// This class owns all the third-party conflicts-related classes and is
-// responsible for their initialization.
+// This class is responsible for the initialization of the
+// IncompatibleApplicationsWarning and ThirdPartyModulesBlocking features. Each
+// feature requires a set of dependencies to be initialized on a background
+// sequence because their main class can be created
+// (IncompatibleApplicationsUpdater and ModuleBlacklistCacheUpdater
+// respectively).
 //
-// The Module List component is received from the component update service,
-// which invokes OnModuleListComponentRegister() and LoadModuleList() when
-// appropriate.
+// Dependencies list
+// For both features:
+// 1. |exe_certificate_info_| contains info about the certificate of the current
+//    executable.
+// 2. |module_list_filter_| is used to determine if a module should be blocked
+//    or allowed. The Module List component is received from the component
+//    update service, which invokes OnModuleListComponentRegister() and
+//    LoadModuleList() when appropriate.
+//
+// For the IncompatibleApplicationsWarning feature only:
+// 3. |installed_applications_| allows to tie a loaded module to an application
+//    installed on the computer.
+//
+// For the ThirdPartyModulesBlocking feature only:
+// 4. |initial_blacklisted_modules_| contains the list of modules that were
+//    blacklisted at the time the browser was launched. Modifications to that
+//    list do not take effect until a restart.
+//
 class ThirdPartyConflictsManager
     : public ModuleDatabaseObserver,
       public component_updater::ComponentUpdateService::Observer {
@@ -130,6 +151,11 @@
   void OnInstalledApplicationsCreated(
       std::unique_ptr<InstalledApplications> installed_applications);
 
+  // Called when |initial_blacklisted_modules_| finishes its initialization.
+  void OnInitialBlacklistedModulesRead(
+      std::unique_ptr<std::vector<third_party_dlls::PackedListModule>>
+          initial_blacklisted_modules);
+
   // Initializes either or both |incompatible_applications_updater_| and
   // |module_blacklist_cache_updater_| when the exe_certificate_info_, the
   // module_list_filter_ and the installed_applications_ are available.
@@ -185,6 +211,11 @@
   // use it on a background sequence.
   scoped_refptr<ModuleListFilter> module_list_filter_;
 
+  // The blacklisted modules contained in the cache used to initialize the
+  // blocking in chrome_elf.
+  std::unique_ptr<std::vector<third_party_dlls::PackedListModule>>
+      initial_blacklisted_modules_;
+
   // Retrieves the list of installed applications.
   std::unique_ptr<InstalledApplications> installed_applications_;
 
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
index 3ca66f7..eebdbb4 100644
--- a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
@@ -60,6 +60,8 @@
       }
     }
   } else {
+    ++unsigned_module_count_;
+
     // Put unsigned modules into the crash keys.
     if (module_data.module_properties & ModuleInfoData::kPropertyLoadedModule)
       AddUnsignedModuleToCrashkeys(module_data.inspection_result->basename);
@@ -85,6 +87,8 @@
                                  catalog_module_count_, 1, 500, 50);
   base::UmaHistogramCustomCounts("ThirdPartyModules.Modules.Total",
                                  module_count_, 1, 500, 50);
+  base::UmaHistogramCustomCounts("ThirdPartyModules.Modules.Unsigned",
+                                 unsigned_module_count_, 1, 500, 50);
 }
 
 void ThirdPartyMetricsRecorder::AddUnsignedModuleToCrashkeys(
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.h b/chrome/browser/conflicts/third_party_metrics_recorder_win.h
index 8200b70a5..8088cb2f 100644
--- a/chrome/browser/conflicts/third_party_metrics_recorder_win.h
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.h
@@ -47,6 +47,7 @@
 
   // Counters for different types of modules.
   size_t module_count_ = 0;
+  size_t unsigned_module_count_ = 0;
   size_t signed_module_count_ = 0;
   size_t catalog_module_count_ = 0;
   size_t microsoft_module_count_ = 0;
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.cc b/chrome/browser/content_settings/sound_content_setting_observer.cc
index 9926955..d9572565 100644
--- a/chrome/browser/content_settings/sound_content_setting_observer.cc
+++ b/chrome/browser/content_settings/sound_content_setting_observer.cc
@@ -8,9 +8,12 @@
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/prefs/pref_service.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/common/url_constants.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 
@@ -23,9 +26,20 @@
     : content::WebContentsObserver(contents),
       logged_site_muted_ukm_(false),
       observer_(this) {
-  host_content_settings_map_ = HostContentSettingsMapFactory::GetForProfile(
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+  host_content_settings_map_ =
+      HostContentSettingsMapFactory::GetForProfile(profile);
   observer_.Add(host_content_settings_map_);
+
+#if !defined(OS_ANDROID)
+  // Listen to changes of the block autoplay pref.
+  pref_change_registrar_.Init(profile->GetPrefs());
+  pref_change_registrar_.Add(
+      prefs::kBlockAutoplayEnabled,
+      base::BindRepeating(&SoundContentSettingObserver::UpdateAutoplayPolicy,
+                          base::Unretained(this)));
+#endif
 }
 
 SoundContentSettingObserver::~SoundContentSettingObserver() = default;
@@ -48,10 +62,19 @@
     const ContentSettingsPattern& secondary_pattern,
     ContentSettingsType content_type,
     const std::string& resource_identifier) {
-  if (content_type == CONTENT_SETTINGS_TYPE_SOUND) {
-    MuteOrUnmuteIfNecessary();
-    CheckSoundBlocked(web_contents()->IsCurrentlyAudible());
+  if (content_type != CONTENT_SETTINGS_TYPE_SOUND)
+    return;
+
+#if !defined(OS_ANDROID)
+  if (primary_pattern == ContentSettingsPattern() &&
+      secondary_pattern == ContentSettingsPattern() &&
+      resource_identifier.empty()) {
+    UpdateAutoplayPolicy();
   }
+#endif
+
+  MuteOrUnmuteIfNecessary();
+  CheckSoundBlocked(web_contents()->IsCurrentlyAudible());
 }
 
 void SoundContentSettingObserver::MuteOrUnmuteIfNecessary() {
@@ -137,3 +160,10 @@
   }
   return MuteReason::kSiteException;
 }
+
+#if !defined(OS_ANDROID)
+void SoundContentSettingObserver::UpdateAutoplayPolicy() {
+  // Force a WebkitPreferences update to update the autoplay policy.
+  web_contents()->GetRenderViewHost()->OnWebkitPreferencesChanged();
+}
+#endif
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.h b/chrome/browser/content_settings/sound_content_setting_observer.h
index 3989f42..d289115 100644
--- a/chrome/browser/content_settings/sound_content_setting_observer.h
+++ b/chrome/browser/content_settings/sound_content_setting_observer.h
@@ -6,8 +6,10 @@
 #define CHROME_BROWSER_CONTENT_SETTINGS_SOUND_CONTENT_SETTING_OBSERVER_H_
 
 #include "base/scoped_observer.h"
+#include "build/build_config.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/common/content_settings.h"
+#include "components/prefs/pref_change_registrar.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
@@ -55,6 +57,14 @@
   // Determine the reason why audio was blocked on the page.
   MuteReason GetSiteMutedReason();
 
+#if !defined(OS_ANDROID)
+  // Update the autoplay policy on the attached |WebContents|.
+  void UpdateAutoplayPolicy();
+
+  // Manages registration of pref change observers.
+  PrefChangeRegistrar pref_change_registrar_;
+#endif
+
   // True if we have already logged a SiteMuted UKM event since last navigation.
   bool logged_site_muted_ukm_;
 
diff --git a/chrome/browser/devtools/devtools_eye_dropper.cc b/chrome/browser/devtools/devtools_eye_dropper.cc
index b82f19a..317cb1e 100644
--- a/chrome/browser/devtools/devtools_eye_dropper.cc
+++ b/chrome/browser/devtools/devtools_eye_dropper.cc
@@ -33,18 +33,12 @@
       last_cursor_x_(-1),
       last_cursor_y_(-1),
       host_(nullptr),
-      use_video_capture_api_(
-          base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
-          base::FeatureList::IsEnabled(
-              features::kUseVideoCaptureApiForDevToolsSnapshots)),
       weak_factory_(this) {
   mouse_event_callback_ =
       base::Bind(&DevToolsEyeDropper::HandleMouseEvent, base::Unretained(this));
   content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
-  if (rvh) {
+  if (rvh)
     AttachToHost(rvh->GetWidget());
-    UpdateFrame();
-  }
 }
 
 DevToolsEyeDropper::~DevToolsEyeDropper() {
@@ -55,9 +49,6 @@
   host_ = host;
   host_->AddMouseEventCallback(mouse_event_callback_);
 
-  if (!use_video_capture_api_)
-    return;
-
   // The view can be null if the renderer process has crashed.
   // (https://crbug.com/847363)
   if (!host_->GetView())
@@ -94,10 +85,8 @@
 }
 
 void DevToolsEyeDropper::RenderViewCreated(content::RenderViewHost* host) {
-  if (!host_) {
+  if (!host_)
     AttachToHost(host->GetWidget());
-    UpdateFrame();
-  }
 }
 
 void DevToolsEyeDropper::RenderViewDeleted(content::RenderViewHost* host) {
@@ -113,43 +102,15 @@
   if ((old_host && old_host->GetWidget() == host_) || (!old_host && !host_)) {
     DetachFromHost();
     AttachToHost(new_host->GetWidget());
-    UpdateFrame();
   }
 }
 
-void DevToolsEyeDropper::DidReceiveCompositorFrame() {
-  UpdateFrame();
-}
-
-void DevToolsEyeDropper::UpdateFrame() {
-  if (use_video_capture_api_ || !host_ || !host_->GetView())
-    return;
-
-  // TODO(miu): This is the wrong size. It's the size of the view on-screen, and
-  // not the rendering size of the view. The latter is what is wanted here, so
-  // that the resulting bitmap's pixel coordinates line-up with the
-  // blink::WebMouseEvent coordinates. http://crbug.com/73362
-  gfx::Size should_be_rendering_size = host_->GetView()->GetViewBounds().size();
-  host_->GetView()->CopyFromSurface(
-      gfx::Rect(), should_be_rendering_size,
-      base::BindOnce(&DevToolsEyeDropper::FrameUpdated,
-                     weak_factory_.GetWeakPtr()));
-}
-
 void DevToolsEyeDropper::ResetFrame() {
   frame_.reset();
   last_cursor_x_ = -1;
   last_cursor_y_ = -1;
 }
 
-void DevToolsEyeDropper::FrameUpdated(const SkBitmap& bitmap) {
-  DCHECK(!use_video_capture_api_);
-  if (bitmap.drawsNothing())
-    return;
-  frame_ = bitmap;
-  UpdateCursor();
-}
-
 bool DevToolsEyeDropper::HandleMouseEvent(const blink::WebMouseEvent& event) {
   last_cursor_x_ = event.PositionInWidget().x;
   last_cursor_y_ = event.PositionInWidget().y;
diff --git a/chrome/browser/devtools/devtools_eye_dropper.h b/chrome/browser/devtools/devtools_eye_dropper.h
index 0dde971e..a767aba 100644
--- a/chrome/browser/devtools/devtools_eye_dropper.h
+++ b/chrome/browser/devtools/devtools_eye_dropper.h
@@ -34,13 +34,11 @@
   void DetachFromHost();
 
   // content::WebContentsObserver.
-  void DidReceiveCompositorFrame() override;
   void RenderViewCreated(content::RenderViewHost* host) override;
   void RenderViewDeleted(content::RenderViewHost* host) override;
   void RenderViewHostChanged(content::RenderViewHost* old_host,
                              content::RenderViewHost* new_host) override;
 
-  void UpdateFrame();
   void ResetFrame();
   void FrameUpdated(const SkBitmap&);
   bool HandleMouseEvent(const blink::WebMouseEvent& event);
@@ -70,7 +68,6 @@
   content::RenderWidgetHost::MouseEventCallback mouse_event_callback_;
   content::RenderWidgetHost* host_;
   std::unique_ptr<viz::ClientFrameSinkVideoCapturer> video_capturer_;
-  const bool use_video_capture_api_;
   media::PaintCanvasVideoRenderer video_renderer_;
   base::WeakPtrFactory<DevToolsEyeDropper> weak_factory_;
 
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc
index 0b024cb..cbc480e2 100644
--- a/chrome/browser/download/download_history.cc
+++ b/chrome/browser/download/download_history.cc
@@ -31,12 +31,11 @@
 
 #include <utility>
 
-#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/download/download_crx_util.h"
-#include "components/download/database/switches.h"
+#include "components/download/public/common/download_features.h"
 #include "components/download/public/common/download_item.h"
 #include "components/history/content/browser/download_conversions.h"
 #include "components/history/core/browser/download_database.h"
@@ -566,8 +565,8 @@
 
   // When download DB is enabled, only completed download should be added to or
   // updated in history DB.
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             download::switches::kEnableDownloadDB) ||
+  return !base::FeatureList::IsEnabled(
+             download::features::kDownloadDBForNewDownloads) ||
          item->IsSavePackageDownload() ||
          item->GetState() == download::DownloadItem::COMPLETE;
 }
diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc
index 10a05acb..f6b0e58 100644
--- a/chrome/browser/download/download_history_unittest.cc
+++ b/chrome/browser/download/download_history_unittest.cc
@@ -14,7 +14,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/rand_util.h"
 #include "base/stl_util.h"
-#include "components/download/database/switches.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/download/public/common/download_features.h"
 #include "components/download/public/common/mock_download_item.h"
 #include "components/history/content/browser/download_conversions.h"
 #include "components/history/core/browser/download_constants.h"
@@ -910,8 +911,9 @@
 // Test creating and updating an item with DownloadDB enabled.
 TEST_F(DownloadHistoryTest, CreateWithDownloadDB) {
   // Enable download DB.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      download::switches::kEnableDownloadDB);
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      download::features::kDownloadDBForNewDownloads);
 
   // Create a fresh item not from download DB
   CreateDownloadHistory(std::unique_ptr<InfoVector>(new InfoVector()));
@@ -935,8 +937,9 @@
 // Test creating history download item that exists in DownloadDB.
 TEST_F(DownloadHistoryTest, CreateHistoryItemInDownloadDB) {
   // Enable download DB.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      download::switches::kEnableDownloadDB);
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      download::features::kDownloadDBForNewDownloads);
 
   history::DownloadRow info;
   InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc
index 9c737a82..2a612f1 100644
--- a/chrome/browser/download/download_offline_content_provider.cc
+++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -120,7 +120,7 @@
 
 void DownloadOfflineContentProvider::GetVisualsForItem(
     const ContentId& id,
-    const VisualsCallback& callback) {
+    VisualsCallback callback) {
   // TODO(crbug.com/855330) Supply thumbnail if item is visible.
   DownloadItem* item = manager_->GetDownloadByGuid(id.id);
   if (!item)
@@ -132,7 +132,7 @@
   auto request = std::make_unique<ImageThumbnailRequest>(
       icon_size,
       base::BindOnce(&DownloadOfflineContentProvider::OnThumbnailRetrieved,
-                     weak_ptr_factory_.GetWeakPtr(), id, callback));
+                     weak_ptr_factory_.GetWeakPtr(), id, std::move(callback)));
   request->Start(item->GetTargetFilePath());
 
   // Dropping ownership of |request| here because it will clean itself up once
@@ -140,9 +140,13 @@
   request.release();
 }
 
+void DownloadOfflineContentProvider::GetShareInfoForItem(
+    const ContentId& id,
+    ShareCallback callback) {}
+
 void DownloadOfflineContentProvider::OnThumbnailRetrieved(
     const ContentId& id,
-    const VisualsCallback& callback,
+    VisualsCallback callback,
     const SkBitmap& bitmap) {
   auto visuals = std::make_unique<OfflineItemVisuals>();
   visuals->icon = gfx::Image::CreateFrom1xBitmap(bitmap);
diff --git a/chrome/browser/download/download_offline_content_provider.h b/chrome/browser/download/download_offline_content_provider.h
index c47ffe4..9b9bda6 100644
--- a/chrome/browser/download/download_offline_content_provider.h
+++ b/chrome/browser/download/download_offline_content_provider.h
@@ -45,7 +45,9 @@
       OfflineContentProvider::MultipleItemCallback callback) override;
   void GetVisualsForItem(
       const ContentId& id,
-      const OfflineContentProvider::VisualsCallback& callback) override;
+      OfflineContentProvider::VisualsCallback callback) override;
+  void GetShareInfoForItem(const ContentId& id,
+                           ShareCallback callback) override;
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
@@ -55,7 +57,7 @@
   void OnDownloadRemoved(DownloadManager* manager, DownloadItem* item) override;
 
   void OnThumbnailRetrieved(const ContentId& id,
-                            const VisualsCallback& callback,
+                            VisualsCallback callback,
                             const SkBitmap& bitmap);
 
   DownloadManager* manager_;
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 c923b2d6..916c086 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
@@ -55,10 +55,17 @@
 constexpr char kTestExtensionID[] = "nbiliclbejdndfpchgkbmfoppjplbdok";
 
 struct Params {
-  explicit Params(bool affiliated) : affiliated_(affiliated) {}
-  bool affiliated_;
+  explicit Params(bool affiliated) : affiliated(affiliated) {}
+  bool affiliated;
 };
 
+// Must be a valid test name (no spaces etc.). Makes the test show up as e.g.
+// AffiliationCheck/U.A.B.T.Affiliated/NotAffiliated_NotActiveDirectory
+std::string PrintParam(testing::TestParamInfo<Params> param_info) {
+  return base::StringPrintf("%sAffiliated",
+                            param_info.param.affiliated ? "" : "Not");
+}
+
 base::Value BuildCustomArg(const std::string& expected_directory_device_id,
                            const std::string& expected_serial_number,
                            const std::string& expected_asset_id,
@@ -78,9 +85,9 @@
 
 namespace extensions {
 
-class EnterpriseDeviceAttributesTest :
-    public ExtensionApiTest,
-    public ::testing::WithParamInterface<Params> {
+class EnterpriseDeviceAttributesTest
+    : public ExtensionApiTest,
+      public ::testing::WithParamInterface<Params> {
  public:
   EnterpriseDeviceAttributesTest() {
     fake_statistics_provider_.SetMachineStatistic(
@@ -93,8 +100,8 @@
   // ExtensionApiTest
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ExtensionApiTest::SetUpCommandLine(command_line);
-    policy::affiliation_test_helper::
-      AppendCommandLineSwitchesForLoginManager(command_line);
+    policy::affiliation_test_helper::AppendCommandLineSwitchesForLoginManager(
+        command_line);
   }
 
   void SetUpInProcessBrowserTestFixture() override {
@@ -108,18 +115,20 @@
 
     std::set<std::string> device_affiliation_ids;
     device_affiliation_ids.insert(kAffiliationID);
-    policy::affiliation_test_helper::SetDeviceAffiliationID(
-        &test_helper_, fake_session_manager_client, device_affiliation_ids);
+    policy::affiliation_test_helper::SetDeviceAffiliationIDs(
+        &test_helper_, fake_session_manager_client,
+        nullptr /* fake_auth_policy_client */, device_affiliation_ids);
 
     std::set<std::string> user_affiliation_ids;
-    if (GetParam().affiliated_) {
+    if (GetParam().affiliated) {
       user_affiliation_ids.insert(kAffiliationID);
     } else {
       user_affiliation_ids.insert(kAnotherAffiliationID);
     }
     policy::UserPolicyBuilder user_policy;
     policy::affiliation_test_helper::SetUserAffiliationIDs(
-        &user_policy, fake_session_manager_client, affiliated_account_id_,
+        &user_policy, fake_session_manager_client,
+        nullptr /* fake_auth_policy_client */, affiliated_account_id_,
         user_affiliation_ids);
 
     // Set up fake install attributes.
@@ -237,17 +246,18 @@
 
   SetPolicy();
 
-  EXPECT_EQ(GetParam().affiliated_, user_manager::UserManager::Get()->
-      FindUser(affiliated_account_id_)->IsAffiliated());
+  EXPECT_EQ(GetParam().affiliated, user_manager::UserManager::Get()
+                                       ->FindUser(affiliated_account_id_)
+                                       ->IsAffiliated());
 
   // Device attributes are available only for affiliated user.
   std::string expected_directory_device_id =
-      GetParam().affiliated_ ? kDeviceId : "";
+      GetParam().affiliated ? kDeviceId : "";
   std::string expected_serial_number =
-      GetParam().affiliated_ ? kSerialNumber : "";
-  std::string expected_asset_id = GetParam().affiliated_ ? kAssetId : "";
+      GetParam().affiliated ? kSerialNumber : "";
+  std::string expected_asset_id = GetParam().affiliated ? kAssetId : "";
   std::string expected_annotated_location =
-      GetParam().affiliated_ ? kAnnotatedLocation : "";
+      GetParam().affiliated ? kAnnotatedLocation : "";
 
   // Pass the expected value (device_id) to test.
   ASSERT_TRUE(TestExtension(
@@ -284,6 +294,8 @@
 
 // Both cases of affiliated and non-affiliated on the device user are tested.
 INSTANTIATE_TEST_CASE_P(AffiliationCheck,
-                          EnterpriseDeviceAttributesTest,
-                        ::testing::Values(Params(true), Params(false)));
+                        EnterpriseDeviceAttributesTest,
+                        ::testing::Values(Params(true /* affiliated */),
+                                          Params(false /* affiliated */)),
+                        PrintParam);
 }  //  namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 574f1a83..70d0771 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -65,6 +65,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -169,7 +170,7 @@
   TestHangOAuth2MintTokenFlow()
       : OAuth2MintTokenFlow(NULL, OAuth2MintTokenFlow::Parameters()) {}
 
-  void Start(net::URLRequestContextGetter* context,
+  void Start(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
              const std::string& access_token) override {
     // Do nothing, simulating a hanging network call.
   }
@@ -191,7 +192,7 @@
         result_(result),
         delegate_(delegate) {}
 
-  void Start(net::URLRequestContextGetter* context,
+  void Start(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
              const std::string& access_token) override {
     switch (result_) {
       case ISSUE_ADVICE_SUCCESS: {
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
index 2549540..f486c53 100644
--- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
+++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -684,7 +684,7 @@
     const std::string& login_access_token) {
   DCHECK(!login_access_token.empty());
   mint_token_flow_.reset(CreateMintTokenFlow());
-  mint_token_flow_->Start(GetProfile()->GetRequestContext(),
+  mint_token_flow_->Start(GetProfile()->GetURLLoaderFactory(),
                           login_access_token);
 }
 
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 24934f6a..8ba53b9 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
@@ -102,9 +102,9 @@
   if (enrollment_status() == EnrollmentStatus::ENROLLED) {
     std::set<std::string> device_affiliation_ids;
     device_affiliation_ids.insert(kAffiliationID);
-    policy::affiliation_test_helper::SetDeviceAffiliationID(
+    policy::affiliation_test_helper::SetDeviceAffiliationIDs(
         &device_policy_test_helper_, fake_session_manager_client,
-        device_affiliation_ids);
+        nullptr /* fake_auth_policy_client */, device_affiliation_ids);
   }
 
   if (user_status() == UserStatus::MANAGED_AFFILIATED_DOMAIN) {
@@ -112,7 +112,8 @@
     user_affiliation_ids.insert(kAffiliationID);
     policy::UserPolicyBuilder user_policy;
     policy::affiliation_test_helper::SetUserAffiliationIDs(
-        &user_policy, fake_session_manager_client, account_id_,
+        &user_policy, fake_session_manager_client,
+        nullptr /* fake_auth_policy_client */, account_id_,
         user_affiliation_ids);
   }
 
diff --git a/chrome/browser/extensions/api/preference/preference_api.cc b/chrome/browser/extensions/api/preference/preference_api.cc
index e73bbbc5..f37081dc 100644
--- a/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chrome/browser/extensions/api/preference/preference_api.cc
@@ -96,6 +96,10 @@
      APIPermission::kPrivacy, APIPermission::kPrivacy},
     {"autofillEnabled", autofill::prefs::kAutofillEnabled,
      APIPermission::kPrivacy, APIPermission::kPrivacy},
+    {"autofillAddressEnabled", autofill::prefs::kAutofillProfileEnabled,
+     APIPermission::kPrivacy, APIPermission::kPrivacy},
+    {"autofillCreditCardEnabled", autofill::prefs::kAutofillCreditCardEnabled,
+     APIPermission::kPrivacy, APIPermission::kPrivacy},
     {"hyperlinkAuditingEnabled", prefs::kEnableHyperlinkAuditing,
      APIPermission::kPrivacy, APIPermission::kPrivacy},
     {"networkPredictionEnabled", prefs::kNetworkPredictionOptions,
diff --git a/chrome/browser/extensions/api/preference/preference_apitest.cc b/chrome/browser/extensions/api/preference/preference_apitest.cc
index a639daa..77e77dc 100644
--- a/chrome/browser/extensions/api/preference/preference_apitest.cc
+++ b/chrome/browser/extensions/api/preference/preference_apitest.cc
@@ -47,6 +47,8 @@
     EXPECT_TRUE(pref->IsExtensionControlled());
     EXPECT_TRUE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
     EXPECT_TRUE(prefs->GetBoolean(autofill::prefs::kAutofillEnabled));
+    EXPECT_TRUE(prefs->GetBoolean(autofill::prefs::kAutofillCreditCardEnabled));
+    EXPECT_TRUE(prefs->GetBoolean(autofill::prefs::kAutofillProfileEnabled));
     EXPECT_FALSE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
     EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableHyperlinkAuditing));
     EXPECT_TRUE(prefs->GetBoolean(prefs::kEnableReferrers));
@@ -67,6 +69,9 @@
     EXPECT_FALSE(pref->IsExtensionControlled());
     EXPECT_FALSE(prefs->GetBoolean(prefs::kAlternateErrorPagesEnabled));
     EXPECT_FALSE(prefs->GetBoolean(autofill::prefs::kAutofillEnabled));
+    EXPECT_FALSE(
+        prefs->GetBoolean(autofill::prefs::kAutofillCreditCardEnabled));
+    EXPECT_FALSE(prefs->GetBoolean(autofill::prefs::kAutofillProfileEnabled));
     EXPECT_TRUE(prefs->GetBoolean(prefs::kBlockThirdPartyCookies));
     EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableHyperlinkAuditing));
     EXPECT_FALSE(prefs->GetBoolean(prefs::kEnableReferrers));
@@ -118,6 +123,8 @@
   PrefService* prefs = profile_->GetPrefs();
   prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false);
   prefs->SetBoolean(autofill::prefs::kAutofillEnabled, false);
+  prefs->SetBoolean(autofill::prefs::kAutofillCreditCardEnabled, false);
+  prefs->SetBoolean(autofill::prefs::kAutofillProfileEnabled, false);
   prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);
   prefs->SetBoolean(prefs::kEnableHyperlinkAuditing, false);
   prefs->SetBoolean(prefs::kEnableReferrers, false);
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index 631489e..ff3c53b 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -52,6 +52,7 @@
 #include "ppapi/buildflags/buildflags.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/extensions/arc_apps_private_api.h"
 #include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h"
 #include "chrome/browser/chromeos/extensions/input_method_api.h"
 #include "chrome/browser/chromeos/extensions/media_player_api.h"
@@ -74,6 +75,9 @@
 void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
   extensions::ActivityLog::GetFactoryInstance();
   extensions::ActivityLogAPI::GetFactoryInstance();
+#if defined(OS_CHROMEOS)
+  extensions::ArcAppsPrivateAPI::GetFactoryInstance();
+#endif
   extensions::AutofillPrivateEventRouterFactory::GetInstance();
   extensions::BluetoothLowEnergyAPI::GetFactoryInstance();
   extensions::BookmarksAPI::GetFactoryInstance();
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index c40364ce..c602d40c 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <set>
+#include <vector>
 
 #include "base/command_line.h"
 #include "base/debug/alias.h"
@@ -30,6 +31,7 @@
 #include "chrome/common/url_constants.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/guest_view/browser/guest_view_message_filter.h"
+#include "components/rappor/public/rappor_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/browser_url_handler.h"
 #include "content/public/browser/child_process_security_policy.h"
@@ -780,6 +782,44 @@
 }
 
 // static
+void ChromeContentBrowserClientExtensionsPart::
+    LogInitiatorSchemeBypassingDocumentBlocking(
+        const url::Origin& initiator_origin,
+        int render_process_id,
+        content::ResourceType resource_type) {
+  // Return early if the RenderProcessHost can't be found.  This can happen if
+  // the process goes away for some reason during the IO -> UI thread hop
+  // required for calling LogInitiatorSchemeBypassingDocumentBlocking.
+  content::RenderProcessHost* process_host =
+      content::RenderProcessHost::FromID(render_process_id);
+  if (!process_host)
+    return;
+  content::BrowserContext* browser_context = process_host->GetBrowserContext();
+
+  // Assert that |initiator_origin| corresponds to an extension and extract the
+  // |extension_id|.
+  DCHECK_EQ(kExtensionScheme, initiator_origin.scheme());
+  const std::string& extension_id = initiator_origin.host();
+  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
+  DCHECK(registry);
+  DCHECK(registry->enabled_extensions().GetByID(extension_id));
+
+  // Don't log anything if the request was initiated by an extension process
+  // (we're only interested in requests initiated by content scripts).
+  ProcessMap* process_map = ProcessMap::Get(browser_context);
+  if (process_map->Contains(extension_id, render_process_id))
+    return;
+
+  // Log that CORB would have blocked in a meaningful way a request that was
+  // initiated by a content script.
+  UMA_HISTOGRAM_ENUMERATION("SiteIsolation.XSD.Browser.Allowed.ContentScript",
+                            resource_type, content::RESOURCE_TYPE_LAST_TYPE);
+  rappor::SampleString(rappor::GetDefaultService(),
+                       "Extensions.CrossOriginFetchFromContentScript",
+                       rappor::UMA_RAPPOR_TYPE, extension_id);
+}
+
+// static
 void ChromeContentBrowserClientExtensionsPart::RecordShouldAllowOpenURLFailure(
     ShouldAllowOpenURLFailureReason reason,
     const GURL& site_url) {
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
index 23fbe8e3..4cda9e87 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
@@ -5,9 +5,12 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_CHROME_CONTENT_BROWSER_CLIENT_EXTENSIONS_PART_H_
 #define CHROME_BROWSER_EXTENSIONS_CHROME_CONTENT_BROWSER_CLIENT_EXTENSIONS_PART_H_
 
+#include <memory>
+
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/chrome_content_browser_client_parts.h"
+#include "content/public/common/resource_type.h"
 #include "ui/base/page_transition_types.h"
 
 namespace content {
@@ -79,6 +82,11 @@
       const GURL& url,
       content::SiteInstance* parent_site_instance);
 
+  static void LogInitiatorSchemeBypassingDocumentBlocking(
+      const url::Origin& initiator_origin,
+      int render_process_id,
+      content::ResourceType resource_type);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ChromeContentBrowserClientExtensionsPartTest,
                            ShouldAllowOpenURLMetricsForEmptySiteURL);
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
index a90f753..9cea81a 100644
--- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
+++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/json/json_reader.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
@@ -22,6 +23,8 @@
 #include "extensions/test/test_extension_dir.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/network/public/cpp/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -64,26 +67,31 @@
   // https://developer.chrome.com/extensions/content_scripts#programmatic.
   std::string FetchViaContentScript(const GURL& url,
                                     content::WebContents* web_contents) {
-    content::DOMMessageQueue message_queue;
+    return FetchHelper(
+        url, base::BindOnce(
+                 &CrossOriginReadBlockingExtensionTest::ExecuteContentScript,
+                 base::Unretained(this), base::Unretained(web_contents)));
+  }
 
-    // Inject a content script that performs a cross-origin XHR to bar.com.
-    const char kXhrScriptTemplate[] = R"(
-      fetch($1)
-        .then(response => response.text())
-        .then(text => domAutomationController.send(text))
-        .catch(err => domAutomationController.send("error: " + err));
-    )";
-    std::string xhr_script = content::JsReplace(kXhrScriptTemplate, url.spec());
-    EXPECT_TRUE(ExecuteContentScript(web_contents, xhr_script));
+  // Performs a fetch of |url| from the background page of the test extension.
+  // Returns the body of the response.
+  std::string FetchViaBackgroundPage(GURL url) {
+    return FetchHelper(
+        url, base::BindOnce(
+                 &browsertest_util::ExecuteScriptInBackgroundPageNoWait,
+                 base::Unretained(browser()->profile()), extension_->id()));
+  }
 
-    // Wait until the message comes back and extract result from the message.
-    std::string json;
-    EXPECT_TRUE(message_queue.WaitForMessage(&json));
-    base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
-    std::unique_ptr<base::Value> value = reader.ReadToValue(json);
-    std::string result;
-    EXPECT_TRUE(value->GetAsString(&result));
-    return result;
+  void VerifyContentScriptHistogramIsPresent(
+      const base::HistogramTester& histograms,
+      content::ResourceType resource_type) {
+    VerifyContentScriptHistogram(
+        histograms, testing::ElementsAre(base::Bucket(resource_type, 1)));
+  }
+
+  void VerifyContentScriptHistogramIsMissing(
+      const base::HistogramTester& histograms) {
+    VerifyContentScriptHistogram(histograms, testing::IsEmpty());
   }
 
  private:
@@ -98,6 +106,51 @@
         browser()->profile(), extension_->id(), background_script);
   }
 
+  using FetchCallback =
+      base::OnceCallback<bool(const std::string& fetch_script)>;
+  std::string FetchHelper(GURL url, FetchCallback fetch_callback) {
+    content::DOMMessageQueue message_queue;
+
+    // Inject a content script that performs a cross-origin XHR to bar.com.
+    const char kXhrScriptTemplate[] = R"(
+      fetch($1)
+        .then(response => response.text())
+        .then(text => domAutomationController.send(text))
+        .catch(err => domAutomationController.send("error: " + err));
+    )";
+    EXPECT_TRUE(std::move(fetch_callback)
+                    .Run(content::JsReplace(kXhrScriptTemplate, url.spec())));
+
+    // Wait until the message comes back and extract result from the message.
+    std::string json;
+    EXPECT_TRUE(message_queue.WaitForMessage(&json));
+    base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
+    std::unique_ptr<base::Value> value = reader.ReadToValue(json);
+    std::string result;
+    EXPECT_TRUE(value->GetAsString(&result));
+    return result;
+  }
+
+  void VerifyContentScriptHistogram(
+      const base::HistogramTester& histograms,
+      testing::Matcher<std::vector<base::Bucket>> matcher) {
+    // LogInitiatorSchemeBypassingDocumentBlocking is only implemented in the
+    // pre-NetworkService CrossSiteDocumentResourceHandler, because we hope to
+    // gather enough data before NetworkService ships.  Logging in
+    // NetworkService world should be possible but would require an extra IPC
+    // from NetworkService to the Browser process which seems like unnecessary
+    // complexity, given that the metrics gathered won't be needed in the
+    // long-term.
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+      return;
+
+    // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early
+    // for a request that wasn't from a content script.
+    EXPECT_THAT(histograms.GetAllSamples(
+                    "SiteIsolation.XSD.Browser.Allowed.ContentScript"),
+                matcher);
+  }
+
   TestExtensionDir dir_;
   const Extension* extension_ = nullptr;
 
@@ -108,7 +161,9 @@
 // behavior) where an extension that has permission to inject a content script
 // to any page can also XHR (without CORS!) any cross-origin resource.
 // See also https://crbug.com/846346.
-IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, SimpleTest) {
+IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
+                       FromContentScript_NoSniffXml) {
+  // Load the test extension.
   InstallExtension();
 
   // Navigate to a foo.com page.
@@ -121,12 +176,108 @@
             web_contents->GetMainFrame()->GetLastCommittedOrigin());
 
   // Inject a content script that performs a cross-origin XHR to bar.com.
-  // Verify that it returned the right response (one that wasn't blocked by
-  // CORB).
+  base::HistogramTester histograms;
   GURL cross_site_resource(
       embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
   EXPECT_EQ("nosniff.xml - body\n",
             FetchViaContentScript(cross_site_resource, web_contents));
+
+  // Verify that no blocking occurred.
+  EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
+              testing::IsEmpty());
+
+  // Verify that LogInitiatorSchemeBypassingDocumentBlocking was called.
+  VerifyContentScriptHistogramIsPresent(histograms, content::RESOURCE_TYPE_XHR);
+}
+
+// Test that responses that would have been allowed by CORB anyway are not
+// reported to LogInitiatorSchemeBypassingDocumentBlocking.
+IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
+                       FromContentScript_AllowedTextResource) {
+  // Load the test extension.
+  InstallExtension();
+
+  // Navigate to a foo.com page.
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  ui_test_utils::NavigateToURL(browser(), page_url);
+  EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL());
+  EXPECT_EQ(url::Origin::Create(page_url),
+            web_contents->GetMainFrame()->GetLastCommittedOrigin());
+
+  // Inject a content script that performs a cross-origin XHR to bar.com.
+  //
+  // StartsWith (rather than equality) is used in the verification step to
+  // account for \n VS \r\n difference on Windows.
+  base::HistogramTester histograms;
+  GURL cross_site_resource(
+      embedded_test_server()->GetURL("bar.com", "/save_page/text.txt"));
+  EXPECT_THAT(FetchViaContentScript(cross_site_resource, web_contents),
+              ::testing::StartsWith(
+                  "text-object.txt: ae52dd09-9746-4b7e-86a6-6ada5e2680c2"));
+
+  // Verify that no blocking occurred.
+  EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
+              testing::IsEmpty());
+
+  // Verify that we didn't call LogInitiatorSchemeBypassingDocumentBlocking
+  // for a response that would have been allowed by CORB anyway.
+  VerifyContentScriptHistogramIsMissing(histograms);
+}
+
+// Test that responses are blocked by CORB, but have empty response body are not
+// reported to LogInitiatorSchemeBypassingDocumentBlocking.
+IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
+                       FromContentScript_EmptyAndBlocked) {
+  // Load the test extension.
+  InstallExtension();
+
+  // Navigate to a foo.com page.
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  ui_test_utils::NavigateToURL(browser(), page_url);
+  EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL());
+  EXPECT_EQ(url::Origin::Create(page_url),
+            web_contents->GetMainFrame()->GetLastCommittedOrigin());
+
+  // Inject a content script that performs a cross-origin XHR to bar.com.
+  base::HistogramTester histograms;
+  GURL cross_site_resource(
+      embedded_test_server()->GetURL("bar.com", "/nosniff.empty"));
+  EXPECT_EQ("", FetchViaContentScript(cross_site_resource, web_contents));
+
+  // Verify that no blocking occurred.
+  EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
+              testing::IsEmpty());
+
+  // Verify that we didn't call LogInitiatorSchemeBypassingDocumentBlocking
+  // for a response that would have been blocked by CORB, but was empty.
+  VerifyContentScriptHistogramIsMissing(histograms);
+}
+
+// Test that LogInitiatorSchemeBypassingDocumentBlocking exits early for
+// requests that aren't from content scripts.
+IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
+                       FromBackgroundPage_NoSniffXml) {
+  // Load the test extension.
+  InstallExtension();
+
+  // Performs a cross-origin XHR from the background page.
+  base::HistogramTester histograms;
+  GURL cross_site_resource(
+      embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
+  EXPECT_EQ("nosniff.xml - body\n",
+            FetchViaBackgroundPage(cross_site_resource));
+
+  // Verify that no blocking occurred.
+  EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
+              testing::IsEmpty());
+
+  // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early
+  // for a request that wasn't from a content script.
+  VerifyContentScriptHistogramIsMissing(histograms);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
index 5e3f77d..61f92d7 100644
--- a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
+++ b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
@@ -16,20 +16,23 @@
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/update_client/update_query_params.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/common/service_manager_connection.h"
 #include "extensions/browser/updater/extension_downloader.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 using extensions::ExtensionDownloader;
 using extensions::ExtensionDownloaderDelegate;
 using update_client::UpdateQueryParams;
 
 std::unique_ptr<ExtensionDownloader>
-ChromeExtensionDownloaderFactory::CreateForRequestContext(
-    net::URLRequestContextGetter* request_context,
+ChromeExtensionDownloaderFactory::CreateForURLLoaderFactory(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     ExtensionDownloaderDelegate* delegate,
-    service_manager::Connector* connector) {
-  std::unique_ptr<ExtensionDownloader> downloader(
-      new ExtensionDownloader(delegate, request_context, connector));
+    service_manager::Connector* connector,
+    const base::FilePath& profile_path) {
+  std::unique_ptr<ExtensionDownloader> downloader(new ExtensionDownloader(
+      delegate, std::move(url_loader_factory), connector, profile_path));
 #if defined(GOOGLE_CHROME_BUILD)
   std::string brand;
   google_brand::GetBrand(&brand);
@@ -54,9 +57,10 @@
     ExtensionDownloaderDelegate* delegate) {
   service_manager::Connector* connector =
       content::ServiceManagerConnection::GetForProcess()->GetConnector();
-  std::unique_ptr<ExtensionDownloader> downloader =
-      CreateForRequestContext(profile->GetRequestContext(), delegate,
-        connector);
+  std::unique_ptr<ExtensionDownloader> downloader = CreateForURLLoaderFactory(
+      content::BrowserContext::GetDefaultStoragePartition(profile)
+          ->GetURLLoaderFactoryForBrowserProcess(),
+      delegate, connector, profile->GetPath());
 
   // NOTE: It is not obvious why it is OK to pass raw pointers to the token
   // service and signin manager here. The logic is as follows:
diff --git a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.h b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.h
index 4426256b..247d670 100644
--- a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.h
+++ b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_EXTENSIONS_UPDATER_CHROME_EXTENSION_DOWNLOADER_FACTORY_H_
 
 #include <memory>
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
 
 class Profile;
 
@@ -14,9 +16,9 @@
 class ExtensionDownloaderDelegate;
 }
 
-namespace net {
-class URLRequestContextGetter;
-}
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
 
 namespace service_manager {
 class Connector;
@@ -26,12 +28,22 @@
 // ExtensionDownloader suitable for use from within Chrome.
 class ChromeExtensionDownloaderFactory {
  public:
-  // Creates a downloader with the given request context. No profile identity
-  // is associated with this downloader.
+  // Creates a downloader with a given "global" url loader factory instance.
+  // No profile identity is associated with this downloader, which means:
+  //
+  // - when this method is called directly, |file_path| is empty.
+  // - when this method is called through CreateForProfile, |profile_path| is
+  //   non-empty.
+  //
+  // |profile_path| is used exclusely to support download of extensions through
+  // the file:// protocol. In practice, it whitelists specific directories the
+  // the browser has access to.
   static std::unique_ptr<extensions::ExtensionDownloader>
-  CreateForRequestContext(net::URLRequestContextGetter* request_context,
-                          extensions::ExtensionDownloaderDelegate* delegate,
-                          service_manager::Connector* connector);
+  CreateForURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      extensions::ExtensionDownloaderDelegate* delegate,
+      service_manager::Connector* connector,
+      const base::FilePath& profile_path = base::FilePath());
 
   // Creates a downloader for a given Profile. This downloader will be able
   // to authenticate as the signed-in user in the event that it's asked to
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 5fccd4d9..f47bcd4 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -27,6 +27,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -60,6 +61,7 @@
 #include "extensions/browser/pref_names.h"
 #include "extensions/browser/updater/extension_downloader.h"
 #include "extensions/browser/updater/extension_downloader_delegate.h"
+#include "extensions/browser/updater/extension_downloader_test_delegate.h"
 #include "extensions/browser/updater/manifest_fetch_data.h"
 #include "extensions/browser/updater/request_queue_impl.h"
 #include "extensions/common/extension.h"
@@ -70,9 +72,11 @@
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_request_headers.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_status.h"
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/third_party/mozilla/url_parse.h"
@@ -162,6 +166,7 @@
                     const PingResult&,
                     const std::set<int>&,
                     const InstallCallback&));
+  MOCK_METHOD0(OnExtensionDownloadRetryForTests, void());
   MOCK_METHOD2(GetPingDataForExtension,
                bool(const std::string&, ManifestFetchData::PingData*));
   MOCK_METHOD1(GetUpdateUrlData, std::string(const std::string&));
@@ -189,6 +194,10 @@
         .WillByDefault(
             Invoke(delegate,
                    &ExtensionDownloaderDelegate::OnExtensionDownloadFinished));
+    ON_CALL(*this, OnExtensionDownloadRetryForTests())
+        .WillByDefault(Invoke(
+            delegate,
+            &ExtensionDownloaderDelegate::OnExtensionDownloadRetryForTests));
     ON_CALL(*this, GetPingDataForExtension(_, _))
         .WillByDefault(Invoke(delegate,
             &ExtensionDownloaderDelegate::GetPingDataForExtension));
@@ -299,11 +308,14 @@
 // Base class for further specialized test classes.
 class MockService : public TestExtensionService {
  public:
-  explicit MockService(TestExtensionPrefs* prefs)
+  explicit MockService(
+      TestExtensionPrefs* prefs,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
       : prefs_(prefs),
         pending_extension_manager_(prefs->profile()),
         fake_account_id_("bobloblaw@lawblog.example.com"),
-        downloader_delegate_override_(NULL) {}
+        downloader_delegate_override_(NULL),
+        test_shared_url_loader_factory_(url_loader_factory) {}
 
   ~MockService() override {}
 
@@ -315,8 +327,8 @@
 
   Profile* profile() { return prefs_->profile(); }
 
-  net::URLRequestContextGetter* request_context() {
-    return profile()->GetRequestContext();
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory() {
+    return test_shared_url_loader_factory_;
   }
 
   ExtensionPrefs* extension_prefs() { return prefs_->prefs(); }
@@ -375,10 +387,10 @@
   std::unique_ptr<ExtensionDownloader> CreateExtensionDownloader(
       ExtensionDownloaderDelegate* delegate) {
     std::unique_ptr<ExtensionDownloader> downloader =
-        ChromeExtensionDownloaderFactory::CreateForRequestContext(
-            request_context(), downloader_delegate_override_
-                                   ? downloader_delegate_override_
-                                   : delegate,
+        ChromeExtensionDownloaderFactory::CreateForURLLoaderFactory(
+            url_loader_factory(),
+            downloader_delegate_override_ ? downloader_delegate_override_
+                                          : delegate,
             /*connector=*/nullptr);
     return downloader;
   }
@@ -402,6 +414,9 @@
 
   ExtensionDownloaderDelegate* downloader_delegate_override_;
 
+  scoped_refptr<network::SharedURLLoaderFactory>
+      test_shared_url_loader_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(MockService);
 };
 
@@ -448,10 +463,11 @@
 
 class ServiceForManifestTests : public MockService {
  public:
-  explicit ServiceForManifestTests(TestExtensionPrefs* prefs)
-      : MockService(prefs),
-        registry_(ExtensionRegistry::Get(profile())) {
-  }
+  explicit ServiceForManifestTests(
+      TestExtensionPrefs* prefs,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      : MockService(prefs, url_loader_factory),
+        registry_(ExtensionRegistry::Get(profile())) {}
 
   ~ServiceForManifestTests() override {}
 
@@ -495,9 +511,10 @@
 
 class ServiceForDownloadTests : public MockService {
  public:
-  explicit ServiceForDownloadTests(TestExtensionPrefs* prefs)
-      : MockService(prefs) {
-  }
+  explicit ServiceForDownloadTests(
+      TestExtensionPrefs* prefs,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      : MockService(prefs, url_loader_factory) {}
 
   // Add a fake crx installer to be returned by a call to UpdateExtension()
   // with a specific ID.  Caller keeps ownership of |crx_installer|.
@@ -649,10 +666,11 @@
 class ExtensionUpdaterTest : public testing::Test {
  public:
   ExtensionUpdaterTest()
-      : thread_bundle_(
-            content::TestBrowserThreadBundle::IO_MAINLOOP),
-        testing_local_state_(TestingBrowserProcess::GetGlobal()) {
-  }
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        test_shared_url_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)),
+        testing_local_state_(TestingBrowserProcess::GetGlobal()) {}
 
   void SetUp() override {
     prefs_.reset(new TestExtensionPrefs(base::ThreadTaskRunnerHandle::Get()));
@@ -697,12 +715,13 @@
 
   size_t ManifestFetchersCount(ExtensionDownloader* downloader) {
     return downloader->manifests_queue_.size() +
-           (downloader->manifest_fetcher_.get() ? 1 : 0);
+           (downloader->manifest_loader_.get() ? 1 : 0);
   }
 
   void TestExtensionUpdateCheckRequests(bool pending) {
     // Create an extension with an update_url.
-    ServiceForManifestTests service(prefs_.get());
+    ServiceForManifestTests service(prefs_.get(),
+                                    test_shared_url_loader_factory_);
     std::string update_url("http://foo.com/bar");
     ExtensionList extensions;
     NotificationsObserver observer;
@@ -718,7 +737,6 @@
     }
 
     // Set up and start the updater.
-    net::TestURLFetcherFactory factory;
     ExtensionUpdater updater(&service,
                              service.extension_prefs(),
                              service.pref_service(),
@@ -733,10 +751,12 @@
     SimulateTimerFired(&updater);
     EXPECT_EQ(1u, observer.StartedCount());
 
-    // Get the url our mock fetcher was asked to fetch.
-    net::TestURLFetcher* fetcher =
-        factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    const GURL& url = fetcher->GetOriginalURL();
+    // Get the url our loader was asked to fetch.
+    const ManifestFetchData& fetch =
+        *updater.downloader_->manifests_queue_.active_request();
+
+    const GURL& url = fetch.full_url();
+
     EXPECT_FALSE(url.is_empty());
     EXPECT_TRUE(url.is_valid());
     EXPECT_TRUE(url.SchemeIs("http"));
@@ -818,11 +838,9 @@
       ManifestFetchData::FetchPriority fetch_priority,
       int num_extensions,
       bool should_include_traffic_management_headers) {
-    net::TestURLFetcherFactory factory;
-
-    MockService service(prefs_.get());
+    MockService service(prefs_.get(), test_shared_url_loader_factory_);
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, service.request_context(),
+    ExtensionDownloader downloader(&delegate, service.url_loader_factory(),
                                    data_decoder_service_connector());
     ExtensionList extensions;
 
@@ -836,20 +854,32 @@
       downloader.AddExtension(*extensions[i], 0, fetch_priority);
     }
 
+    // Get the headers our loader was asked to fetch.
+    base::RunLoop loop;
+    net::HttpRequestHeaders last_request_headers;
+    test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
+        [&](const network::ResourceRequest& request) {
+          last_request_headers = request.headers;
+          loop.Quit();
+        }));
+
     downloader.StartAllPending(NULL);
-    net::TestURLFetcher* fetcher =
-        factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    ASSERT_TRUE(fetcher);
+    EXPECT_TRUE(downloader.manifest_loader_);
+
+    loop.Run();
+
     // Make sure that extensions that update from the gallery ignore any
     // update URL data.
-    const std::string& fetcher_url = fetcher->GetOriginalURL().spec();
+    const ManifestFetchData& fetch =
+        *downloader.manifests_queue_.active_request();
+    const std::string& fetcher_url = fetch.full_url().spec();
     std::string::size_type x = fetcher_url.find("x=");
     EXPECT_NE(std::string::npos, x);
     std::string::size_type ap = fetcher_url.find("ap%3D", x);
     EXPECT_EQ(std::string::npos, ap);
 
     net::HttpRequestHeaders fetch_headers;
-    fetcher->GetExtraRequestHeaders(&fetch_headers);
+    std::swap(fetch_headers, last_request_headers);
     EXPECT_EQ(should_include_traffic_management_headers,
               fetch_headers.HasHeader(
                   ExtensionDownloader::kUpdateInteractivityHeader));
@@ -928,9 +958,8 @@
   }
 
   void TestDetermineUpdates() {
-    TestingProfile profile;
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, profile.GetRequestContext(),
+    ExtensionDownloader downloader(&delegate, test_shared_url_loader_factory_,
                                    data_decoder_service_connector());
 
     // Check passing an empty list of parse results to DetermineUpdates
@@ -980,9 +1009,8 @@
   }
 
   void TestDetermineUpdatesError() {
-    TestingProfile profile;
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, profile.GetRequestContext(),
+    ExtensionDownloader downloader(&delegate, test_shared_url_loader_factory_,
                                    data_decoder_service_connector());
 
     std::unique_ptr<ManifestFetchData> fetch_data(
@@ -1060,14 +1088,14 @@
 
   void TestDetermineUpdatesPending() {
     // Create a set of test extensions
-    ServiceForManifestTests service(prefs_.get());
+    ServiceForManifestTests service(prefs_.get(),
+                                    test_shared_url_loader_factory_);
     PendingExtensionManager* pending_extension_manager =
         service.pending_extension_manager();
     SetupPendingExtensionManagerForTest(3, GURL(), pending_extension_manager);
 
-    TestingProfile profile;
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, profile.GetRequestContext(),
+    ExtensionDownloader downloader(&delegate, test_shared_url_loader_factory_,
                                    data_decoder_service_connector());
 
     std::unique_ptr<ManifestFetchData> fetch_data(
@@ -1102,9 +1130,8 @@
 
   void TestDetermineUpdatesDuplicates() {
     base::HistogramTester histogram_tester;
-    TestingProfile profile;
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, profile.GetRequestContext(),
+    ExtensionDownloader downloader(&delegate, test_shared_url_loader_factory_,
                                    data_decoder_service_connector());
 
     const std::string id1 = crx_file::id_util::GenerateId("1");
@@ -1183,12 +1210,9 @@
   }
 
   void TestMultipleManifestDownloading() {
-    net::TestURLFetcherFactory factory;
-    factory.set_remove_fetcher_on_delete(true);
-    net::TestURLFetcher* fetcher = NULL;
-    MockService service(prefs_.get());
+    MockService service(prefs_.get(), test_shared_url_loader_factory_);
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, service.request_context(),
+    ExtensionDownloader downloader(&delegate, service.url_loader_factory(),
                                    data_decoder_service_connector());
     downloader.manifests_queue_.set_backoff_policy(&kNoBackoffPolicy);
 
@@ -1229,115 +1253,113 @@
     downloader.StartUpdateCheck(std::move(fetch4));
     RunUntilIdle();
 
-    for (int i = 0; i < 4; ++i) {
-      fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-      ASSERT_TRUE(fetcher);
-      ASSERT_TRUE(fetcher->delegate());
-      EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
-      EXPECT_FALSE(fetcher->GetOriginalURL().is_empty());
+    // fetch1_url
+    {
+      test_url_loader_factory_.AddResponse(fetch1_url.spec(), "",
+                                           net::HTTP_BAD_REQUEST);
+      EXPECT_CALL(
+          delegate,
+          OnExtensionDownloadFailed(
+              "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _))
+          .WillOnce(InvokeWithoutArgs(&delegate,
+                                      &MockExtensionDownloaderDelegate::Quit));
+      delegate.Wait();
+      Mock::VerifyAndClearExpectations(&delegate);
+      fetch1_url = GURL();
 
-      if (fetcher->GetOriginalURL() == fetch1_url) {
-        // The first fetch will fail.
-        EXPECT_CALL(delegate, OnExtensionDownloadFailed(
-            "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _));
-        fetcher->set_url(kUpdateUrl);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(400);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        RunUntilIdle();
-        Mock::VerifyAndClearExpectations(&delegate);
-        fetch1_url = GURL();
-      } else if (fetcher->GetOriginalURL() == fetch2_url) {
-        // The second fetch gets invalid data.
-        const std::string kInvalidXml = "invalid xml";
-        EXPECT_CALL(delegate, OnExtensionDownloadFailed(
-            "2222", ExtensionDownloaderDelegate::MANIFEST_INVALID, _, _))
-            .WillOnce(InvokeWithoutArgs(
-                &delegate,
-                &MockExtensionDownloaderDelegate::Quit));
-        fetcher->set_url(kUpdateUrl);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(200);
-        fetcher->SetResponseString(kInvalidXml);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        delegate.Wait();
-        Mock::VerifyAndClearExpectations(&delegate);
-        fetch2_url = GURL();
-      } else if (fetcher->GetOriginalURL() == fetch3_url) {
-        // The third fetcher doesn't have an update available.
-        const std::string kNoUpdate =
-            "<?xml version='1.0' encoding='UTF-8'?>"
-            "<gupdate xmlns='http://www.google.com/update2/response'"
-            "                protocol='2.0'>"
-            " <app appid='3333'>"
-            "  <updatecheck codebase='http://example.com/extension_3.0.0.0.crx'"
-            "               version='3.0.0.0' prodversionmin='3.0.0.0' />"
-            " </app>"
-            "</gupdate>";
-        EXPECT_CALL(delegate, IsExtensionPending("3333"))
-            .WillOnce(Return(false));
-        EXPECT_CALL(delegate, GetExtensionExistingVersion("3333", _))
-            .WillOnce(DoAll(SetArgPointee<1>("3.0.0.0"),
-                            Return(true)));
-        EXPECT_CALL(delegate, OnExtensionDownloadFailed(
-            "3333", ExtensionDownloaderDelegate::NO_UPDATE_AVAILABLE, _, _))
-            .WillOnce(InvokeWithoutArgs(
-                &delegate,
-                &MockExtensionDownloaderDelegate::Quit));
-        fetcher->set_url(kUpdateUrl);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(200);
-        fetcher->SetResponseString(kNoUpdate);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        delegate.Wait();
-        Mock::VerifyAndClearExpectations(&delegate);
-        fetch3_url = GURL();
-      } else if (fetcher->GetOriginalURL() == fetch4_url) {
-        // The last fetcher has an update.
-        NotificationsObserver observer;
-        const std::string kUpdateAvailable =
-            "<?xml version='1.0' encoding='UTF-8'?>"
-            "<gupdate xmlns='http://www.google.com/update2/response'"
-            "                protocol='2.0'>"
-            " <app appid='4444'>"
-            "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
-            "               version='4.0.42.0' prodversionmin='4.0.42.0' />"
-            " </app>"
-            "</gupdate>";
-        EXPECT_CALL(delegate, IsExtensionPending("4444"))
-            .WillOnce(Return(false));
-        EXPECT_CALL(delegate, GetExtensionExistingVersion("4444", _))
-            .WillOnce(DoAll(SetArgPointee<1>("4.0.0.0"),
-                            Return(true)));
-        fetcher->set_url(kUpdateUrl);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(200);
-        fetcher->SetResponseString(kUpdateAvailable);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        observer.Wait();
-        Mock::VerifyAndClearExpectations(&delegate);
-
-        // Verify that the downloader decided to update this extension.
-        EXPECT_EQ(1u, observer.UpdatedCount());
-        EXPECT_TRUE(observer.Updated("4444"));
-        fetch4_url = GURL();
-      } else {
-        ADD_FAILURE() << "Unexpected fetch: " << fetcher->GetOriginalURL();
-      }
+      RunUntilIdle();
     }
 
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    if (fetcher)
-      ADD_FAILURE() << "Unexpected fetch: " << fetcher->GetOriginalURL();
+    // fetch2_url
+    {
+      const std::string kInvalidXml = "invalid xml";
+      test_url_loader_factory_.AddResponse(fetch2_url.spec(), kInvalidXml,
+                                           net::HTTP_OK);
+      EXPECT_CALL(
+          delegate,
+          OnExtensionDownloadFailed(
+              "2222", ExtensionDownloaderDelegate::MANIFEST_INVALID, _, _))
+          .WillOnce(InvokeWithoutArgs(&delegate,
+                                      &MockExtensionDownloaderDelegate::Quit));
+      delegate.Wait();
+      Mock::VerifyAndClearExpectations(&delegate);
+      fetch2_url = GURL();
+
+      RunUntilIdle();
+    }
+
+    // fetch3_url
+    {
+      const std::string kNoUpdate =
+          "<?xml version='1.0' encoding='UTF-8'?>"
+          "<gupdate xmlns='http://www.google.com/update2/response'"
+          "                protocol='2.0'>"
+          " <app appid='3333'>"
+          "  <updatecheck codebase='http://example.com/extension_3.0.0.0.crx'"
+          "               version='3.0.0.0' prodversionmin='3.0.0.0' />"
+          " </app>"
+          "</gupdate>";
+      test_url_loader_factory_.AddResponse(fetch3_url.spec(), kNoUpdate,
+                                           net::HTTP_OK);
+      // The third fetcher doesn't have an update available.
+      EXPECT_CALL(delegate, IsExtensionPending("3333")).WillOnce(Return(false));
+      EXPECT_CALL(delegate, GetExtensionExistingVersion("3333", _))
+          .WillOnce(DoAll(SetArgPointee<1>("3.0.0.0"), Return(true)));
+      EXPECT_CALL(
+          delegate,
+          OnExtensionDownloadFailed(
+              "3333", ExtensionDownloaderDelegate::NO_UPDATE_AVAILABLE, _, _))
+          .WillOnce(InvokeWithoutArgs(&delegate,
+                                      &MockExtensionDownloaderDelegate::Quit));
+      delegate.Wait();
+      Mock::VerifyAndClearExpectations(&delegate);
+      fetch3_url = GURL();
+
+      RunUntilIdle();
+    }
+
+    // fetch4_url
+    {
+      // The last fetcher has an update.
+      NotificationsObserver observer;
+      const std::string kUpdateAvailable =
+          "<?xml version='1.0' encoding='UTF-8'?>"
+          "<gupdate xmlns='http://www.google.com/update2/response'"
+          "                protocol='2.0'>"
+          " <app appid='4444'>"
+          "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
+          "               version='4.0.42.0' prodversionmin='4.0.42.0' />"
+          " </app>"
+          "</gupdate>";
+      test_url_loader_factory_.AddResponse(fetch4_url.spec(), kUpdateAvailable,
+                                           net::HTTP_OK);
+      EXPECT_CALL(delegate, IsExtensionPending("4444")).WillOnce(Return(false));
+      EXPECT_CALL(delegate, GetExtensionExistingVersion("4444", _))
+          .WillOnce(DoAll(SetArgPointee<1>("4.0.0.0"), Return(true)));
+      observer.Wait();
+      Mock::VerifyAndClearExpectations(&delegate);
+
+      // Verify that the downloader decided to update this extension.
+      EXPECT_EQ(1u, observer.UpdatedCount());
+      EXPECT_TRUE(observer.Updated("4444"));
+      fetch4_url = GURL();
+    }
+    if (downloader.manifest_loader_)
+      ADD_FAILURE() << "Unexpected load";
+  }
+
+  network::TestURLLoaderFactory::PendingRequest* GetPendingRequest(
+      size_t index = 0) {
+    if (index >= test_url_loader_factory_.pending_requests()->size())
+      return nullptr;
+    return &(*test_url_loader_factory_.pending_requests())[index];
   }
 
   void TestManifestRetryDownloading() {
-    net::TestURLFetcherFactory factory;
-    net::TestURLFetcher* fetcher = NULL;
     NotificationsObserver observer;
-    MockService service(prefs_.get());
+    MockService service(prefs_.get(), test_shared_url_loader_factory_);
     MockExtensionDownloaderDelegate delegate;
-    ExtensionDownloader downloader(&delegate, service.request_context(),
+    ExtensionDownloader downloader(&delegate, service.url_loader_factory(),
                                    data_decoder_service_connector());
     downloader.manifests_queue_.set_backoff_policy(&kNoBackoffPolicy);
 
@@ -1357,21 +1379,22 @@
     // ExtensionDownloader should retry kMaxRetries times and then fail.
     EXPECT_CALL(delegate, OnExtensionDownloadFailed(
         "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _));
+    test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
+        [&](const network::ResourceRequest& request) {
+          EXPECT_TRUE(request.load_flags == kExpectedLoadFlags);
+        }));
     for (int i = 0; i <= ExtensionDownloader::kMaxRetries; ++i) {
       // All fetches will fail.
-      fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-      EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-      EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
-      fetcher->set_url(kUpdateUrl);
-      fetcher->set_status(net::URLRequestStatus());
+      auto* request = GetPendingRequest(0);
       // Code 5xx causes ExtensionDownloader to retry.
-      fetcher->set_response_code(500);
-      fetcher->delegate()->OnURLFetchComplete(fetcher);
+      test_url_loader_factory_.SimulateResponseForPendingRequest(
+          request->request.url, network::URLLoaderCompletionStatus(net::OK),
+          network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+          "");
       RunUntilIdle();
     }
     Mock::VerifyAndClearExpectations(&delegate);
 
-
     // For response codes that are not in the 5xx range ExtensionDownloader
     // should not retry.
     fetch.reset(CreateManifestFetchData(kUpdateUrl));
@@ -1385,35 +1408,34 @@
 
     EXPECT_CALL(delegate, OnExtensionDownloadFailed(
         "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _));
+
     // The first fetch will fail, and require retrying.
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
-    fetcher->set_url(kUpdateUrl);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(500);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    {
+      auto* request = GetPendingRequest(0);
+      test_url_loader_factory_.SimulateResponseForPendingRequest(
+          request->request.url, network::URLLoaderCompletionStatus(net::OK),
+          network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+          "");
+    }
     RunUntilIdle();
 
     // The second fetch will fail with response 400 and should not cause
     // ExtensionDownloader to retry.
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
-    fetcher->set_url(kUpdateUrl);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(400);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    {
+      auto* request = GetPendingRequest(0);
+      test_url_loader_factory_.SimulateResponseForPendingRequest(
+          request->request.url, network::URLLoaderCompletionStatus(net::OK),
+          network::CreateResourceResponseHead(net::HTTP_BAD_REQUEST), "");
+    }
     RunUntilIdle();
 
     Mock::VerifyAndClearExpectations(&delegate);
   }
 
   void TestSingleExtensionDownloading(bool pending, bool retry, bool fail) {
-    net::TestURLFetcherFactory factory;
-    net::TestURLFetcher* fetcher = NULL;
     std::unique_ptr<ServiceForDownloadTests> service(
-        new ServiceForDownloadTests(prefs_.get()));
+        new ServiceForDownloadTests(prefs_.get(),
+                                    test_shared_url_loader_factory_));
     ExtensionUpdater updater(service.get(),
                              service->extension_prefs(),
                              service->pref_service(),
@@ -1433,6 +1455,7 @@
 
     const std::string id(32, 'a');
     std::string hash;
+    CRXFileInfo crx_file_info;
     base::Version version("0.0.1");
     std::set<int> requests;
     requests.insert(0);
@@ -1460,41 +1483,44 @@
                                kRemoteInstall));
     }
 
-    // Call back the ExtensionUpdater with a 200 response and some test data
-    base::FilePath extension_file_path(FILE_PATH_LITERAL("/whatever"));
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
-
     if (retry) {
-      // Reply with response code 500 to cause ExtensionDownloader to retry
-      fetcher->set_url(test_url);
-      fetcher->set_status(net::URLRequestStatus());
-      fetcher->set_response_code(500);
-      fetcher->delegate()->OnURLFetchComplete(fetcher);
-
-      RunUntilIdle();
-      fetcher = factory.GetFetcherByID(
-          ExtensionDownloader::kExtensionFetcherId);
-      EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-      EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
+      EXPECT_CALL(delegate, OnExtensionDownloadRetryForTests())
+          .WillOnce(DoAll(
+              InvokeWithoutArgs(&delegate,
+                                &MockExtensionDownloaderDelegate::Quit),
+              InvokeWithoutArgs(
+                  this,
+                  &ExtensionUpdaterTest::ClearURLLoaderFactoryResponses)));
+      test_url_loader_factory_.AddResponse(test_url.spec(), "",
+                                           net::HTTP_INTERNAL_SERVER_ERROR);
+      delegate.Wait();
+      EXPECT_TRUE(updater.downloader_->extension_loader_);
     }
 
-    fetcher->set_url(test_url);
-    fetcher->set_status(net::URLRequestStatus());
     if (fail) {
-      fetcher->set_response_code(404);
-      EXPECT_CALL(delegate, OnExtensionDownloadFailed(id, _, _, requests));
+      EXPECT_CALL(delegate, OnExtensionDownloadFailed(id, _, _, requests))
+          .WillOnce(DoAll(
+              InvokeWithoutArgs(&delegate,
+                                &MockExtensionDownloaderDelegate::Quit),
+              InvokeWithoutArgs(
+                  this,
+                  &ExtensionUpdaterTest::ClearURLLoaderFactoryResponses)));
+      test_url_loader_factory_.AddResponse(test_url.spec(),
+                                           "Any content. It is irrelevant.",
+                                           net::HTTP_NOT_FOUND);
+      delegate.Wait();
     } else {
-      fetcher->set_response_code(200);
-      fetcher->SetResponseFilePath(extension_file_path);
+      EXPECT_TRUE(updater.downloader_->extension_loader_);
       EXPECT_CALL(delegate, OnExtensionDownloadFinished(
-                                CRXFileInfo(id, extension_file_path, hash), _,
-                                _, version.GetString(), _, requests, _));
+                                _, _, _, version.GetString(), _, requests, _))
+          .WillOnce(
+              DoAll(testing::SaveArg<0>(&crx_file_info),
+                    InvokeWithoutArgs(&delegate,
+                                      &MockExtensionDownloaderDelegate::Quit)));
+      test_url_loader_factory_.AddResponse(test_url.spec(),
+                                           "Any content. It is irrelevant.");
+      delegate.Wait();
     }
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
-
-    RunUntilIdle();
 
     if (fail) {
       // Don't expect any extension to have been installed.
@@ -1502,13 +1528,16 @@
     } else {
       // Expect that ExtensionUpdater asked the mock extensions service to
       // install a file with the test data for the right id.
-      EXPECT_EQ(id, service->extension_id());
-      base::FilePath tmpfile_path = service->install_path();
+      EXPECT_EQ(id, crx_file_info.extension_id);
+      base::FilePath tmpfile_path = crx_file_info.path;
       EXPECT_FALSE(tmpfile_path.empty());
-      EXPECT_EQ(extension_file_path, tmpfile_path);
     }
   }
 
+  void ClearURLLoaderFactoryResponses() {
+    test_url_loader_factory_.ClearResponses();
+  }
+
   // Update a single extension in an environment where the download request
   // initially responds with a 403 status. If |identity_provider| is not NULL,
   // this will first expect a request which includes an Authorization header
@@ -1520,10 +1549,9 @@
       bool succeed_with_oauth2,
       int valid_authuser,
       int max_authuser) {
-    net::TestURLFetcherFactory factory;
-    net::TestURLFetcher* fetcher = NULL;
     std::unique_ptr<ServiceForDownloadTests> service(
-        new ServiceForDownloadTests(prefs_.get()));
+        new ServiceForDownloadTests(prefs_.get(),
+                                    test_shared_url_loader_factory_));
     const ExtensionDownloader::Factory& downloader_factory =
         enable_oauth2 ? service->GetAuthenticatedDownloaderFactory()
             : service->GetDownloaderFactory();
@@ -1535,12 +1563,18 @@
         kUpdateFrequencySecs,
         NULL,
         downloader_factory);
+
+    MockExtensionDownloaderDelegate delegate;
+    delegate.DelegateTo(&updater);
+    service->OverrideDownloaderDelegate(&delegate);
+
     updater.Start();
     updater.EnsureDownloaderCreated();
     updater.downloader_->extensions_queue_.set_backoff_policy(
         &kNoBackoffPolicy);
 
     GURL test_url(base::StringPrintf("%s/extension.crx", url_prefix.c_str()));
+
     const std::string id(32, 'a');
     std::string hash;
     base::Version version("0.0.1");
@@ -1551,36 +1585,43 @@
                                                 version.GetString(), requests));
     updater.downloader_->FetchUpdatedExtension(std::move(fetch));
 
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    EXPECT_EQ(kExpectedLoadFlags, fetcher->GetLoadFlags());
+    EXPECT_EQ(
+        kExpectedLoadFlags,
+        updater.downloader_->last_extension_loader_load_flags_for_testing_);
 
     // Fake a 403 response.
-    fetcher->set_url(test_url);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(403);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    EXPECT_CALL(delegate, OnExtensionDownloadRetryForTests())
+        .WillOnce(DoAll(
+            InvokeWithoutArgs(&delegate,
+                              &MockExtensionDownloaderDelegate::Quit),
+            InvokeWithoutArgs(
+                this, &ExtensionUpdaterTest::ClearURLLoaderFactoryResponses)));
+    test_url_loader_factory_.AddResponse(test_url.spec(), "",
+                                         net::HTTP_FORBIDDEN);
+    delegate.Wait();
 
     if (service->fake_token_service()) {
       service->fake_token_service()->IssueAllTokensForAccount(
           service->fake_account_id(), kFakeOAuth2Token, base::Time::Now());
     }
-    RunUntilIdle();
 
     bool using_oauth2 = false;
     int expected_load_flags = kExpectedLoadFlags;
+
     // Verify that the fetch has had its credentials properly incremented.
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    net::HttpRequestHeaders fetch_headers;
-    fetcher->GetExtraRequestHeaders(&fetch_headers);
+    EXPECT_TRUE(updater.downloader_->extension_loader_);
+    net::HttpRequestHeaders fetch_headers =
+        updater.downloader_
+            ->last_extension_loader_resource_request_headers_for_testing_;
     // If the download URL is not https, no credentials should be provided.
     if (!test_url.SchemeIsCryptographic()) {
       // No cookies.
-      EXPECT_EQ(kExpectedLoadFlags, fetcher->GetLoadFlags());
+      EXPECT_EQ(
+          kExpectedLoadFlags,
+          updater.downloader_->last_extension_loader_load_flags_for_testing_);
       // No Authorization header.
-      EXPECT_FALSE(fetch_headers.HasHeader(
-          net::HttpRequestHeaders::kAuthorization));
+      EXPECT_FALSE(
+          fetch_headers.HasHeader(net::HttpRequestHeaders::kAuthorization));
       expected_load_flags = kExpectedLoadFlags;
     } else {
       // HTTPS is in use, so credentials are allowed.
@@ -1602,8 +1643,9 @@
         // an Authorization header.
         EXPECT_FALSE(fetch_headers.HasHeader(
             net::HttpRequestHeaders::kAuthorization));
-        EXPECT_EQ(kExpectedLoadFlagsForDownloadWithCookies,
-            fetcher->GetLoadFlags());
+        EXPECT_EQ(
+            kExpectedLoadFlagsForDownloadWithCookies,
+            updater.downloader_->last_extension_loader_load_flags_for_testing_);
         expected_load_flags = kExpectedLoadFlagsForDownloadWithCookies;
       }
     }
@@ -1614,11 +1656,16 @@
         success = true;
       } else {
         // Simulate OAuth2 failure and ensure that we fall back on cookies.
-        fetcher->set_url(test_url);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(403);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        RunUntilIdle();
+        EXPECT_CALL(delegate, OnExtensionDownloadRetryForTests())
+            .WillOnce(DoAll(
+                InvokeWithoutArgs(&delegate,
+                                  &MockExtensionDownloaderDelegate::Quit),
+                InvokeWithoutArgs(
+                    this,
+                    &ExtensionUpdaterTest::ClearURLLoaderFactoryResponses)));
+        test_url_loader_factory_.AddResponse(test_url.spec(), "",
+                                             net::HTTP_FORBIDDEN);
+        delegate.Wait();
 
         const ExtensionDownloader::ExtensionFetch& fetch =
             *updater.downloader_->extensions_queue_.active_request();
@@ -1626,14 +1673,15 @@
         EXPECT_EQ(ExtensionDownloader::ExtensionFetch::CREDENTIALS_COOKIES,
                   fetch.credentials);
 
-        fetcher = factory.GetFetcherByID(
-            ExtensionDownloader::kExtensionFetcherId);
-        EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-        fetcher->GetExtraRequestHeaders(&fetch_headers);
-        EXPECT_FALSE(fetch_headers.HasHeader(
-            net::HttpRequestHeaders::kAuthorization));
-        EXPECT_EQ(kExpectedLoadFlagsForDownloadWithCookies,
-            fetcher->GetLoadFlags());
+        EXPECT_TRUE(updater.downloader_->extension_loader_);
+        fetch_headers =
+            updater.downloader_
+                ->last_extension_loader_resource_request_headers_for_testing_;
+        EXPECT_FALSE(
+            fetch_headers.HasHeader(net::HttpRequestHeaders::kAuthorization));
+        EXPECT_EQ(
+            kExpectedLoadFlagsForDownloadWithCookies,
+            updater.downloader_->last_extension_loader_load_flags_for_testing_);
         expected_load_flags = kExpectedLoadFlagsForDownloadWithCookies;
       }
     }
@@ -1653,50 +1701,55 @@
         }
         // Simulate an authorization failure which should elicit an increment
         // of the authuser value.
-        fetcher =
-            factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-        EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-        EXPECT_EQ(expected_load_flags, fetcher->GetLoadFlags());
-        fetcher->set_url(fetch.url);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(403);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        RunUntilIdle();
+        EXPECT_TRUE(updater.downloader_->extension_loader_);
+        EXPECT_EQ(
+            expected_load_flags,
+            updater.downloader_->last_extension_loader_load_flags_for_testing_);
+        EXPECT_CALL(delegate, OnExtensionDownloadRetryForTests())
+            .WillOnce(DoAll(
+                InvokeWithoutArgs(&delegate,
+                                  &MockExtensionDownloaderDelegate::Quit),
+                InvokeWithoutArgs(
+                    this,
+                    &ExtensionUpdaterTest::ClearURLLoaderFactoryResponses)));
+        test_url_loader_factory_.AddResponse(fetch.url.spec(), "whatever",
+                                             net::HTTP_FORBIDDEN);
+        delegate.Wait();
       }
 
       // Simulate exhaustion of all available authusers.
       if (!success && user_index > max_authuser) {
         const ExtensionDownloader::ExtensionFetch& fetch =
             *updater.downloader_->extensions_queue_.active_request();
-        fetcher =
-            factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-        EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-        fetcher->set_url(fetch.url);
-        fetcher->set_status(net::URLRequestStatus());
-        fetcher->set_response_code(401);
-        fetcher->delegate()->OnURLFetchComplete(fetcher);
-        RunUntilIdle();
+        EXPECT_TRUE(updater.downloader_->extension_loader_);
+        test_url_loader_factory_.AddResponse(fetch.url.spec(), std::string(),
+                                             net::HTTP_UNAUTHORIZED);
+        EXPECT_CALL(delegate, OnExtensionDownloadFailed(_, _, _, _))
+            .WillOnce(InvokeWithoutArgs(
+                &delegate, &MockExtensionDownloaderDelegate::Quit));
+        delegate.Wait();
       }
     }
 
     // Simulate successful authorization with a 200 response.
     if (success) {
-      fetcher =
-          factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-      EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-      base::FilePath extension_file_path(FILE_PATH_LITERAL("/whatever"));
-      fetcher->set_url(test_url);
-      fetcher->set_status(net::URLRequestStatus());
-      fetcher->set_response_code(200);
-      fetcher->SetResponseFilePath(extension_file_path);
-      fetcher->delegate()->OnURLFetchComplete(fetcher);
-      RunUntilIdle();
+      EXPECT_TRUE(updater.downloader_->extension_loader_);
+      const ExtensionDownloader::ExtensionFetch& fetch =
+          *updater.downloader_->extensions_queue_.active_request();
+
+      CRXFileInfo crx_file_info;
+      EXPECT_CALL(delegate, OnExtensionDownloadFinished(_, _, _, _, _, _, _))
+          .WillOnce(
+              DoAll(testing::SaveArg<0>(&crx_file_info),
+                    InvokeWithoutArgs(&delegate,
+                                      &MockExtensionDownloaderDelegate::Quit)));
+      test_url_loader_factory_.AddResponse(fetch.url.spec(), "whatever");
+      delegate.Wait();
 
       // Verify installation would proceed as normal.
-      EXPECT_EQ(id, service->extension_id());
-      base::FilePath tmpfile_path = service->install_path();
+      EXPECT_EQ(id, crx_file_info.extension_id);
+      base::FilePath tmpfile_path = crx_file_info.path;
       EXPECT_FALSE(tmpfile_path.empty());
-      EXPECT_EQ(extension_file_path, tmpfile_path);
     }
   }
 
@@ -1705,9 +1758,8 @@
   // the test is responsible for creating fake CrxInstallers.  Otherwise,
   // UpdateExtension() returns false, signaling install failures.
   void TestMultipleExtensionDownloading(bool updates_start_running) {
-    net::TestURLFetcherFactory factory;
-    net::TestURLFetcher* fetcher = NULL;
-    ServiceForDownloadTests service(prefs_.get());
+    ServiceForDownloadTests service(prefs_.get(),
+                                    test_shared_url_loader_factory_);
     ExtensionUpdater updater(&service,
                              service.extension_prefs(),
                              service.pref_service(),
@@ -1746,11 +1798,10 @@
     updater.downloader_->FetchUpdatedExtension(std::move(fetch2));
 
     // Make the first fetch complete.
-    base::FilePath extension_file_path(FILE_PATH_LITERAL("/whatever"));
-
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
+    EXPECT_TRUE(updater.downloader_->extension_loader_);
+    EXPECT_EQ(
+        kExpectedLoadFlags,
+        updater.downloader_->last_extension_loader_load_flags_for_testing_);
 
     // We need some CrxInstallers, and CrxInstallers require a real
     // ExtensionService.  Create one on the testing profile.  Any action
@@ -1778,12 +1829,8 @@
       // starting the install.
     }
 
-    fetcher->set_url(url1);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(200);
-    fetcher->SetResponseFilePath(extension_file_path);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
-
+    test_url_loader_factory_.AddResponse(
+        url1.spec(), "Any content. This is irrelevant.", net::HTTP_OK);
     RunUntilIdle();
 
     // Expect that the service was asked to do an install with the right data.
@@ -1794,17 +1841,14 @@
 
     // Make sure the second fetch finished and asked the service to do an
     // update.
-    base::FilePath extension_file_path2(FILE_PATH_LITERAL("/whatever2"));
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags);
+    EXPECT_TRUE(updater.downloader_->extension_loader_);
+    EXPECT_EQ(
+        kExpectedLoadFlags,
+        updater.downloader_->last_extension_loader_load_flags_for_testing_);
 
-    fetcher->set_url(url2);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(200);
-    fetcher->SetResponseFilePath(extension_file_path2);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
-    RunUntilIdle();
+    test_url_loader_factory_.AddResponse(
+        url2.spec(), "Any other content. This is irrelevant.", net::HTTP_OK);
+    content::RunAllTasksUntilIdle();
 
     if (updates_start_running) {
       EXPECT_TRUE(updater.crx_install_is_running_);
@@ -1824,9 +1868,6 @@
     EXPECT_EQ(id2, service.extension_id());
     EXPECT_FALSE(service.install_path().empty());
 
-    // Make sure the correct crx contents were passed for the update call.
-    EXPECT_EQ(extension_file_path2, service.install_path());
-
     if (updates_start_running) {
       EXPECT_TRUE(updater.crx_install_is_running_);
       fake_crx2->NotifyCrxInstallComplete(CrxInstallError(
@@ -1878,12 +1919,11 @@
                            int active_ping_days,
                            bool active_bit,
                            bool expect_brand_code) {
-    net::TestURLFetcherFactory factory;
-
     // Set up 2 mock extensions, one with a google.com update url and one
     // without.
     prefs_.reset(new TestExtensionPrefs(base::ThreadTaskRunnerHandle::Get()));
-    ServiceForManifestTests service(prefs_.get());
+    ServiceForManifestTests service(prefs_.get(),
+                                    test_shared_url_loader_factory_);
     ExtensionList tmp;
     GURL url1("http://clients2.google.com/service/update2/crx");
     GURL url2("http://www.somewebsite.com");
@@ -1931,19 +1971,17 @@
     // Make the updater do manifest fetching, and note the urls it tries to
     // fetch.
     std::vector<GURL> fetched_urls;
-    net::TestURLFetcher* fetcher =
-      factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL);
-    fetched_urls.push_back(fetcher->GetOriginalURL());
+    ASSERT_TRUE(updater.downloader_->manifest_loader_);
+    const ManifestFetchData& fetch =
+        *updater.downloader_->manifests_queue_.active_request();
+    fetched_urls.push_back(fetch.full_url());
+    test_url_loader_factory_.AddResponse(fetched_urls[0].spec(), std::string(),
+                                         net::HTTP_INTERNAL_SERVER_ERROR);
+    RunUntilIdle();
 
-    fetcher->set_url(fetched_urls[0]);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(500);
-    fetcher->SetResponseString(std::string());
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
-
-    fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    fetched_urls.push_back(fetcher->GetOriginalURL());
+    const ManifestFetchData& fetch2 =
+        *updater.downloader_->manifests_queue_.active_request();
+    fetched_urls.push_back(fetch2.full_url());
 
     // The urls could have been fetched in either order, so use the host to
     // tell them apart and note the query each used.
@@ -2017,7 +2055,8 @@
   // the first time we fetched the extension, or 2) We sent a ping value of
   // >= 1 day for the extension.
   void TestHandleManifestResults() {
-    ServiceForManifestTests service(prefs_.get());
+    ServiceForManifestTests service(prefs_.get(),
+                                    test_shared_url_loader_factory_);
     GURL update_url("http://www.google.com/manifest");
     ExtensionList tmp;
     service.CreateTestExtensions(1, 1, &tmp, &update_url.spec(),
@@ -2061,7 +2100,8 @@
   // disabled extension we want.
   void TestPingMetrics(int num_enabled,
                        const std::vector<int>& disabled) {
-    ServiceForManifestTests service(prefs_.get());
+    ServiceForManifestTests service(prefs_.get(),
+                                    test_shared_url_loader_factory_);
     ExtensionList enabled_extensions;
     ExtensionList disabled_extensions;
 
@@ -2085,7 +2125,6 @@
 
     // Create the extension updater, make it issue an update, and capture the
     // URL that it tried to fetch.
-    net::TestURLFetcherFactory factory;
     ExtensionUpdater updater(&service,
                              service.extension_prefs(),
                              service.pref_service(),
@@ -2095,10 +2134,10 @@
                              service.GetDownloaderFactory());
     updater.Start();
     SimulateTimerFired(&updater);
-    net::TestURLFetcher* fetcher =
-        factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-    ASSERT_NE(nullptr, fetcher);
-    const GURL& url = fetcher->GetOriginalURL();
+    ASSERT_NE(nullptr, updater.downloader_->manifest_loader_);
+    const ManifestFetchData& fetch =
+        *updater.downloader_->manifests_queue_.active_request();
+    const GURL& url = fetch.full_url();
     EXPECT_FALSE(url.is_empty());
     EXPECT_TRUE(url.is_valid());
     EXPECT_TRUE(url.has_query());
@@ -2180,6 +2219,10 @@
 
  protected:
   std::unique_ptr<TestExtensionPrefs> prefs_;
+  content::TestBrowserThreadBundle thread_bundle_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory>
+      test_shared_url_loader_factory_;
 
   ManifestFetchData* CreateManifestFetchData(
       const GURL& update_url,
@@ -2199,8 +2242,8 @@
   }
 
  private:
-  content::TestBrowserThreadBundle thread_bundle_;
   content::InProcessUtilityThreadHelper in_process_utility_thread_helper_;
+
   ScopedTestingLocalState testing_local_state_;
   data_decoder::TestDataDecoderService test_data_decoder_service_;
 
@@ -2375,8 +2418,8 @@
 }
 
 TEST_F(ExtensionUpdaterTest, TestNonAutoUpdateableLocations) {
-  net::TestURLFetcherFactory factory;
-  ServiceForManifestTests service(prefs_.get());
+  ServiceForManifestTests service(prefs_.get(),
+                                  test_shared_url_loader_factory_);
   ExtensionUpdater updater(&service,
                            service.extension_prefs(),
                            service.pref_service(),
@@ -2407,8 +2450,8 @@
 }
 
 TEST_F(ExtensionUpdaterTest, TestUpdatingDisabledExtensions) {
-  net::TestURLFetcherFactory factory;
-  ServiceForManifestTests service(prefs_.get());
+  ServiceForManifestTests service(prefs_.get(),
+                                  test_shared_url_loader_factory_);
   ExtensionUpdater updater(&service,
                            service.extension_prefs(),
                            service.pref_service(),
@@ -2444,11 +2487,11 @@
 }
 
 TEST_F(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
-  net::TestURLFetcherFactory factory;
-  MockService service(prefs_.get());
+  MockService service(prefs_.get(), test_shared_url_loader_factory_);
   MockExtensionDownloaderDelegate delegate;
-  std::unique_ptr<ExtensionDownloader> downloader(new ExtensionDownloader(
-      &delegate, service.request_context(), data_decoder_service_connector()));
+  std::unique_ptr<ExtensionDownloader> downloader(
+      new ExtensionDownloader(&delegate, service.url_loader_factory(),
+                              data_decoder_service_connector()));
   EXPECT_EQ(0u, ManifestFetchersCount(downloader.get()));
 
   // First, verify that adding valid extensions does invoke the callbacks on
@@ -2481,7 +2524,8 @@
   // converted from user scripts are rejected.
 
   // Reset the ExtensionDownloader so that it drops the current fetcher.
-  downloader.reset(new ExtensionDownloader(&delegate, service.request_context(),
+  downloader.reset(new ExtensionDownloader(&delegate,
+                                           service.url_loader_factory(),
                                            data_decoder_service_connector()));
   EXPECT_EQ(0u, ManifestFetchersCount(downloader.get()));
 
@@ -2495,17 +2539,16 @@
   downloader->StartAllPending(NULL);
   EXPECT_EQ(1u, ManifestFetchersCount(downloader.get()));
 
-  net::TestURLFetcher* fetcher =
-      factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId);
-  ASSERT_TRUE(fetcher);
-  EXPECT_FALSE(fetcher->GetOriginalURL().is_empty());
+  RunUntilIdle();
+  auto* request = &(*test_url_loader_factory_.pending_requests())[1];
+  ASSERT_TRUE(request);
+  EXPECT_FALSE(request->request.url.is_empty());
 }
 
 TEST_F(ExtensionUpdaterTest, TestStartUpdateCheckMemory) {
-  net::TestURLFetcherFactory factory;
-  MockService service(prefs_.get());
+  MockService service(prefs_.get(), test_shared_url_loader_factory_);
   MockExtensionDownloaderDelegate delegate;
-  ExtensionDownloader downloader(&delegate, service.request_context(),
+  ExtensionDownloader downloader(&delegate, service.url_loader_factory(),
                                  data_decoder_service_connector());
 
   StartUpdateCheck(&downloader,
@@ -2520,8 +2563,8 @@
 }
 
 TEST_F(ExtensionUpdaterTest, TestCheckSoon) {
-  ServiceForManifestTests service(prefs_.get());
-  net::TestURLFetcherFactory factory;
+  ServiceForManifestTests service(prefs_.get(),
+                                  test_shared_url_loader_factory_);
   ExtensionUpdater updater(&service,
                            service.extension_prefs(),
                            service.pref_service(),
@@ -2564,7 +2607,8 @@
 }
 
 TEST_F(ExtensionUpdaterTest, TestUninstallWhileUpdateCheck) {
-  ServiceForManifestTests service(prefs_.get());
+  ServiceForManifestTests service(prefs_.get(),
+                                  test_shared_url_loader_factory_);
   ExtensionList tmp;
   service.CreateTestExtensions(1, 1, &tmp, nullptr, Manifest::INTERNAL);
   service.set_extensions(tmp, ExtensionList());
@@ -2596,7 +2640,8 @@
       base::Time::Now() + base::TimeDelta::FromMilliseconds(500);
   prefs_->pref_service()->SetInt64(pref_names::kNextUpdateCheck,
                                    next_check_time.ToInternalValue());
-  ServiceForManifestTests service(prefs_.get());
+  ServiceForManifestTests service(prefs_.get(),
+                                  test_shared_url_loader_factory_);
   ExtensionUpdater updater(&service, service.extension_prefs(),
                            service.pref_service(), service.profile(),
                            kDefaultUpdateFrequencySeconds, nullptr,
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index 8bf2f13..c0a4d14 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -35,7 +35,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/shell_integration.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
@@ -51,7 +50,6 @@
 #include "chrome/installer/util/master_preferences_constants.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9f11d40..99567696 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -52,9 +52,6 @@
     "Enable the display of Progressive Web App banners, which prompt a user to "
     "add a web app to their shelf, or other platform-specific equivalent.";
 
-const char kAshSidebarName[] = "Sidebar";
-const char kAshSidebarDescription[] = "Enable the experimental sidebar.";
-
 const char kAutomaticPasswordGenerationName[] = "Automatic password generation";
 const char kAutomaticPasswordGenerationDescription[] =
     "Allow Chrome to offer to generate passwords when it detects account "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e61b7639..da903110 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -58,9 +58,6 @@
 extern const char kAppBannersName[];
 extern const char kAppBannersDescription[];
 
-extern const char kAshSidebarName[];
-extern const char kAshSidebarDescription[];
-
 extern const char kAutomaticPasswordGenerationName[];
 extern const char kAutomaticPasswordGenerationDescription[];
 
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc
index a8746a8..07b6c1e 100644
--- a/chrome/browser/history/top_sites_factory.cc
+++ b/chrome/browser/history/top_sites_factory.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/locale_settings.h"
@@ -32,6 +33,7 @@
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/ntp_tiles/constants.h"
 #include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
@@ -66,12 +68,16 @@
 #endif
 
 void InitializePrepopulatedPageList(
+    PrefService* prefs,
     history::PrepopulatedPageList* prepopulated_pages) {
 #if !defined(OS_ANDROID)
   DCHECK(prepopulated_pages);
+  bool hide_web_store_icon = prefs->GetBoolean(prefs::kHideWebStoreIcon);
   prepopulated_pages->reserve(arraysize(kRawPrepopulatedPages));
   for (size_t i = 0; i < arraysize(kRawPrepopulatedPages); ++i) {
     const RawPrepopulatedPage& page = kRawPrepopulatedPages[i];
+    if (hide_web_store_icon && page.url_id == IDS_WEBSTORE_URL)
+      continue;
     prepopulated_pages->push_back(history::PrepopulatedPage(
         GURL(l10n_util::GetStringUTF8(page.url_id)),
         l10n_util::GetStringUTF16(page.title_id),
@@ -116,7 +122,6 @@
   history::HistoryService* history_service =
       HistoryServiceFactory::GetForProfile(profile,
                                            ServiceAccessType::EXPLICIT_ACCESS);
-
   scoped_refptr<history::TopSitesImpl> top_sites(new history::TopSitesImpl(
       profile->GetPrefs(), history_service,
       CreateTopSitesProvider(profile, history_service), prepopulated_page_list,
@@ -142,7 +147,8 @@
 scoped_refptr<RefcountedKeyedService> TopSitesFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   history::PrepopulatedPageList prepopulated_pages;
-  InitializePrepopulatedPageList(&prepopulated_pages);
+  InitializePrepopulatedPageList(
+      Profile::FromBrowserContext(context)->GetPrefs(), &prepopulated_pages);
   return BuildTopSites(context, prepopulated_pages);
 }
 
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 64d56a6b..dd408580 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -136,18 +136,6 @@
 
 namespace {
 
-void NotifyDownloadInitiatedOnUI(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter) {
-  content::WebContents* web_contents = wc_getter.Run();
-  if (!web_contents)
-    return;
-
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_DOWNLOAD_INITIATED,
-      content::Source<content::WebContents>(web_contents),
-      content::NotificationService::NoDetails());
-}
-
 prerender::PrerenderManager* GetPrerenderManager(
     content::WebContents* web_contents) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -448,11 +436,6 @@
     std::vector<std::unique_ptr<content::ResourceThrottle>>* throttles) {
   const content::ResourceRequestInfo* info =
         content::ResourceRequestInfo::ForRequest(request);
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&NotifyDownloadInitiatedOnUI,
-                     info->GetWebContentsGetterForRequest()));
-
   // If it's from the web, we don't trust it, so we push the throttle on.
   if (is_content_initiated) {
     throttles->push_back(std::make_unique<DownloadResourceThrottle>(
diff --git a/chrome/browser/media/OWNERS b/chrome/browser/media/OWNERS
index cbdac8c2..db25441 100644
--- a/chrome/browser/media/OWNERS
+++ b/chrome/browser/media/OWNERS
@@ -10,6 +10,10 @@
 per-file media_engagement*=beccahughes@chromium.org
 per-file media_engagement*=mlamouri@chromium.org
 
+# For Unified Autoplay
+per-file unified_autoplay*=beccahughes@chromium.org
+per-file unified_autoplay*=mlamouri@chromium.org
+
 # For IPC security review
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index f99fc69e..44316d5 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -451,15 +451,6 @@
   }
 
   void TestPolicyCheck() {
-// TODO(crbug.com/847591): ChromeOS Widevine CDM does not support policy check
-// API yet. Remove this condition when the CDM is updated.
-#if defined(WIDEVINE_CDM_AVAILABLE) && defined(OS_CHROMEOS)
-    if (IsWidevine(CurrentKeySystem())) {
-      DVLOG(0) << "Skipping test due to HDCP policy check related bugs.";
-      return;
-    }
-#endif
-
     base::StringPairs query_params;
     // We do not care about playback so choose an arbitrary media file.
     query_params.emplace_back("mediaFile", "bear-a_enc-a.webm");
diff --git a/chrome/browser/media/media_engagement_score_details.mojom b/chrome/browser/media/media_engagement_score_details.mojom
index 514b81f..8257607a 100644
--- a/chrome/browser/media/media_engagement_score_details.mojom
+++ b/chrome/browser/media/media_engagement_score_details.mojom
@@ -42,6 +42,9 @@
   bool feature_record_data;
   bool feature_bypass_autoplay;
   bool feature_preload_data;
+  bool feature_autoplay_sound_settings;
+  bool pref_unified_autoplay;
+  bool has_custom_autoplay_policy;
   string autoplay_policy;
 
   // The current version of any preloaded component.
diff --git a/chrome/browser/media/unified_autoplay_config.cc b/chrome/browser/media/unified_autoplay_config.cc
new file mode 100644
index 0000000..db395f0
--- /dev/null
+++ b/chrome/browser/media/unified_autoplay_config.cc
@@ -0,0 +1,30 @@
+// 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/media/unified_autoplay_config.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+
+// static
+void UnifiedAutoplayConfig::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(prefs::kBlockAutoplayEnabled, true);
+}
+
+// static
+bool UnifiedAutoplayConfig::ShouldBlockAutoplay(Profile* profile) {
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForProfile(profile);
+  if (settings_map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_SOUND,
+                                             nullptr) == CONTENT_SETTING_BLOCK) {
+    return true;
+  }
+
+  return profile->GetPrefs()->GetBoolean(prefs::kBlockAutoplayEnabled);
+}
diff --git a/chrome/browser/media/unified_autoplay_config.h b/chrome/browser/media/unified_autoplay_config.h
new file mode 100644
index 0000000..64df2ea
--- /dev/null
+++ b/chrome/browser/media/unified_autoplay_config.h
@@ -0,0 +1,30 @@
+// 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_MEDIA_UNIFIED_AUTOPLAY_CONFIG_H_
+#define CHROME_BROWSER_MEDIA_UNIFIED_AUTOPLAY_CONFIG_H_
+
+#include "base/macros.h"
+
+class Profile;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}  // namespace user_prefs
+
+class UnifiedAutoplayConfig {
+ public:
+  // Register profile prefs in the pref registry.
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable*);
+
+  // Checks whether autoplay should be blocked by user preference. This will be
+  // true if the block autoplay pref is true and if the default sound content
+  // setting value is not block.
+  static bool ShouldBlockAutoplay(Profile*);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(UnifiedAutoplayConfig);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_UNIFIED_AUTOPLAY_CONFIG_H_
diff --git a/chrome/browser/media/unified_autoplay_config_unittest.cc b/chrome/browser/media/unified_autoplay_config_unittest.cc
new file mode 100644
index 0000000..711b844
--- /dev/null
+++ b/chrome/browser/media/unified_autoplay_config_unittest.cc
@@ -0,0 +1,164 @@
+// 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/media/unified_autoplay_config.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/content_settings/sound_content_setting_observer.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/common/web_preferences.h"
+#include "content/public/test/web_contents_tester.h"
+#include "media/base/media_switches.h"
+
+// Unit tests for the unified autoplay policy with the unified sound settings
+// UI enabled.
+
+class UnifiedAutoplaySoundSettingsTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  ~UnifiedAutoplaySoundSettingsTest() override = default;
+
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(media::kAutoplaySoundSettings);
+    ChromeRenderViewHostTestHarness::SetUp();
+
+    SoundContentSettingObserver::CreateForWebContents(web_contents());
+  }
+
+  void SetSoundContentSettingDefault(ContentSetting value) {
+    HostContentSettingsMap* content_settings =
+        HostContentSettingsMapFactory::GetForProfile(profile());
+    content_settings->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_SOUND,
+                                               value);
+  }
+
+  void SetAutoplayPrefValue(bool value) {
+    GetPrefs()->SetBoolean(prefs::kBlockAutoplayEnabled, value);
+    EXPECT_EQ(value, GetPrefs()->GetBoolean(prefs::kBlockAutoplayEnabled));
+  }
+
+  bool ShouldBlockAutoplay() {
+    return UnifiedAutoplayConfig::ShouldBlockAutoplay(profile());
+  }
+
+  content::AutoplayPolicy GetAppliedAutoplayPolicy() {
+    return web_contents()
+        ->GetRenderViewHost()
+        ->GetWebkitPreferences()
+        .autoplay_policy;
+  }
+
+  void NavigateToTestPage() {
+    content::WebContentsTester::For(web_contents())
+        ->NavigateAndCommit(GURL("https://first.example.com"));
+  }
+
+ private:
+  PrefService* GetPrefs() { return profile()->GetPrefs(); }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(UnifiedAutoplaySoundSettingsTest, ContentSetting_Allow) {
+  SetSoundContentSettingDefault(CONTENT_SETTING_ALLOW);
+  SetAutoplayPrefValue(false);
+
+  EXPECT_FALSE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kNoUserGestureRequired,
+            GetAppliedAutoplayPolicy());
+}
+
+TEST_F(UnifiedAutoplaySoundSettingsTest, ContentSetting_Block) {
+  SetSoundContentSettingDefault(CONTENT_SETTING_BLOCK);
+
+  SetAutoplayPrefValue(false);
+  EXPECT_TRUE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kDocumentUserActivationRequired,
+            GetAppliedAutoplayPolicy());
+
+  // Set back to ALLOW to ensure that the policy is updated on the next
+  // navigation.
+  SetSoundContentSettingDefault(CONTENT_SETTING_ALLOW);
+  EXPECT_FALSE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kNoUserGestureRequired,
+            GetAppliedAutoplayPolicy());
+}
+
+TEST_F(UnifiedAutoplaySoundSettingsTest, Feature_DisabledNoop) {
+  // Explicitly disable the feature.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures({}, {media::kAutoplaySoundSettings});
+
+  SetAutoplayPrefValue(false);
+  EXPECT_FALSE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kDocumentUserActivationRequired,
+            GetAppliedAutoplayPolicy());
+}
+
+TEST_F(UnifiedAutoplaySoundSettingsTest, Pref_DefaultEnabled) {
+  EXPECT_TRUE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kDocumentUserActivationRequired,
+            GetAppliedAutoplayPolicy());
+}
+
+TEST_F(UnifiedAutoplaySoundSettingsTest, Pref_Disabled) {
+  SetAutoplayPrefValue(false);
+  EXPECT_FALSE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kNoUserGestureRequired,
+            GetAppliedAutoplayPolicy());
+
+  // Now update the pref and make sure we apply it on the next navigation.
+  SetAutoplayPrefValue(true);
+  EXPECT_TRUE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kDocumentUserActivationRequired,
+            GetAppliedAutoplayPolicy());
+}
+
+// Unit tests for the unified autoplay policy with the unified sound settings
+// UI enabled and a custom autoplay policy command line switch.
+
+class UnifiedAutoplaySoundSettingsOverrideTest
+    : public UnifiedAutoplaySoundSettingsTest {
+ public:
+  ~UnifiedAutoplaySoundSettingsOverrideTest() override = default;
+
+  void SetUp() override {
+    scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII(
+        switches::kAutoplayPolicy,
+        switches::autoplay::kUserGestureRequiredPolicy);
+
+    UnifiedAutoplaySoundSettingsTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedCommandLine scoped_command_line_;
+};
+
+TEST_F(UnifiedAutoplaySoundSettingsOverrideTest, CommandLineOverride) {
+  EXPECT_TRUE(ShouldBlockAutoplay());
+
+  NavigateToTestPage();
+  EXPECT_EQ(content::AutoplayPolicy::kUserGestureRequired,
+            GetAppliedAutoplayPolicy());
+}
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
index 4a58431..eae926aa 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.cc
@@ -129,8 +129,6 @@
   g_webrtc_event_log_manager = nullptr;
 }
 
-// TODO(crbug.com/775415): If a BrowserContext had the policy as active in
-// the past, but no longer does, purge pending log files from before.
 void WebRtcEventLogManager::EnableForBrowserContext(
     BrowserContext* browser_context,
     base::OnceClosure reply) {
@@ -143,39 +141,33 @@
     first_browser_context_initializations_done_ = true;
   }
 
-  StartListeningForPrefChangeForBrowserContext(browser_context);
-
-  if (!IsRemoteLoggingAllowedForBrowserContext(browser_context)) {
-    MaybeReply(FROM_HERE, std::move(reply));
-    return;
-  }
+  const bool enable_for_remote_logging =
+      IsRemoteLoggingAllowedForBrowserContext(browser_context);
 
   // |this| is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
   // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(
-          &WebRtcEventLogManager::EnableRemoteBoundLoggingForBrowserContext,
-          base::Unretained(this), GetBrowserContextId(browser_context),
-          browser_context->GetPath(), std::move(reply)));
+      base::BindOnce(&WebRtcEventLogManager::EnableForBrowserContextInternal,
+                     base::Unretained(this),
+                     GetBrowserContextId(browser_context),
+                     browser_context->GetPath(), enable_for_remote_logging,
+                     std::move(reply)));
 }
 
 void WebRtcEventLogManager::DisableForBrowserContext(
-    content::BrowserContext* browser_context,
+    const content::BrowserContext* browser_context,
     base::OnceClosure reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(browser_context);
 
-  StopListeningForPrefChangeForBrowserContext(browser_context);
-
   // |this| is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
   // will not be dereferenced after destruction.
   task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(
-          &WebRtcEventLogManager::DisableRemoteBoundLoggingForBrowserContext,
-          base::Unretained(this), GetBrowserContextId(browser_context),
-          std::move(reply)));
+      base::BindOnce(&WebRtcEventLogManager::DisableForBrowserContextInternal,
+                     base::Unretained(this),
+                     GetBrowserContextId(browser_context), std::move(reply)));
 }
 
 void WebRtcEventLogManager::PeerConnectionAdded(
@@ -501,14 +493,14 @@
 void WebRtcEventLogManager::OnLoggingTargetStarted(LoggingTarget target,
                                                    PeerConnectionKey key) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  auto it = peer_connections_with_event_logging_enabled_in_webrtc_.find(key);
-  if (it != peer_connections_with_event_logging_enabled_in_webrtc_.end()) {
+  auto it = peer_connections_with_event_logging_enabled_.find(key);
+  if (it != peer_connections_with_event_logging_enabled_.end()) {
     DCHECK_EQ((it->second & target), 0u);
     it->second |= target;
   } else {
     // This is the first client for WebRTC event logging - let WebRTC know
     // that it should start informing us of events.
-    peer_connections_with_event_logging_enabled_in_webrtc_.emplace(key, target);
+    peer_connections_with_event_logging_enabled_.emplace(key, target);
     pc_tracker_proxy_->SetWebRtcEventLoggingState(key, true);
   }
 }
@@ -518,92 +510,19 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
   // Record that we're no longer performing this type of logging for this PC.
-  auto it = peer_connections_with_event_logging_enabled_in_webrtc_.find(key);
-  CHECK(it != peer_connections_with_event_logging_enabled_in_webrtc_.end());
+  auto it = peer_connections_with_event_logging_enabled_.find(key);
+  CHECK(it != peer_connections_with_event_logging_enabled_.end());
   DCHECK_NE(it->second, 0u);
   it->second &= ~target;
 
   // If we're not doing any other type of logging for this peer connection,
   // it's time to stop receiving notifications for it from WebRTC.
   if (it->second == 0u) {
-    peer_connections_with_event_logging_enabled_in_webrtc_.erase(it);
+    peer_connections_with_event_logging_enabled_.erase(it);
     pc_tracker_proxy_->SetWebRtcEventLoggingState(key, false);
   }
 }
 
-void WebRtcEventLogManager::StartListeningForPrefChangeForBrowserContext(
-    BrowserContext* browser_context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(first_browser_context_initializations_done_);
-  CHECK(!browser_context->IsOffTheRecord());
-
-  const auto browser_context_id = GetBrowserContextId(browser_context);
-  auto it = pref_change_registrars_.emplace(std::piecewise_construct,
-                                            std::make_tuple(browser_context_id),
-                                            std::make_tuple());
-  DCHECK(it.second) << "Already listening.";
-  PrefChangeRegistrar& registrar = it.first->second;
-
-  Profile* profile = Profile::FromBrowserContext(browser_context);
-  DCHECK(profile);
-  registrar.Init(profile->GetPrefs());
-
-  // * |this| is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
-  //   will not be dereferenced after destruction.
-  // * base::Unretained(browser_context) is safe, because |browser_context|
-  //   stays alive until Chrome shut-down, at which point we'll stop listening
-  //   as part of its (BrowserContext's) tear-down process.
-  registrar.Add(prefs::kWebRtcEventLogCollectionAllowed,
-                base::BindRepeating(&WebRtcEventLogManager::OnPrefChange,
-                                    base::Unretained(this),
-                                    base::Unretained(browser_context)));
-}
-
-void WebRtcEventLogManager::StopListeningForPrefChangeForBrowserContext(
-    BrowserContext* browser_context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  const auto browser_context_id = GetBrowserContextId(browser_context);
-
-  size_t erased_count = pref_change_registrars_.erase(browser_context_id);
-  DCHECK_EQ(erased_count, 1u);
-}
-
-void WebRtcEventLogManager::OnPrefChange(BrowserContext* browser_context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(first_browser_context_initializations_done_);
-
-  const Profile* profile = Profile::FromBrowserContext(browser_context);
-  DCHECK(profile);
-
-  const bool enabled =
-      profile->GetPrefs()->GetBoolean(prefs::kWebRtcEventLogCollectionAllowed);
-
-  if (!enabled) {
-    // Dynamic refresh of the policy to DISABLED; stop ongoing logs, remove
-    // pending log files and stop any active uploads.
-    ClearCacheForBrowserContext(browser_context, base::Time::Min(),
-                                base::Time::Max(), base::DoNothing());
-  }
-
-  // |this| is destroyed by ~BrowserProcessImpl(), so base::Unretained(this)
-  // will not be dereferenced after destruction.
-  base::OnceClosure task;
-  if (enabled) {
-    task = base::BindOnce(
-        &WebRtcEventLogManager::EnableRemoteBoundLoggingForBrowserContext,
-        base::Unretained(this), GetBrowserContextId(browser_context),
-        browser_context->GetPath(), base::OnceClosure());
-  } else {
-    task = base::BindOnce(
-        &WebRtcEventLogManager::DisableRemoteBoundLoggingForBrowserContext,
-        base::Unretained(this), GetBrowserContextId(browser_context),
-        base::OnceClosure());
-  }
-
-  task_runner_->PostTask(FROM_HERE, std::move(task));
-}
-
 void WebRtcEventLogManager::OnFirstBrowserContextLoaded() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -648,26 +567,27 @@
       std::move(log_file_writer_factory));
 }
 
-void WebRtcEventLogManager::EnableRemoteBoundLoggingForBrowserContext(
+void WebRtcEventLogManager::EnableForBrowserContextInternal(
     BrowserContextId browser_context_id,
     const base::FilePath& browser_context_dir,
+    bool enable_for_remote_logging,
     base::OnceClosure reply) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DCHECK_NE(browser_context_id, kNullBrowserContextId);
 
-  remote_logs_manager_.EnableForBrowserContext(browser_context_id,
-                                               browser_context_dir);
+  if (enable_for_remote_logging) {
+    remote_logs_manager_.EnableForBrowserContext(browser_context_id,
+                                                 browser_context_dir);
+  }
 
   MaybeReply(FROM_HERE, std::move(reply));
 }
 
-void WebRtcEventLogManager::DisableRemoteBoundLoggingForBrowserContext(
+void WebRtcEventLogManager::DisableForBrowserContextInternal(
     BrowserContextId browser_context_id,
     base::OnceClosure reply) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  // Note that the BrowserContext might never have been enabled in the
-  // remote-bound manager; that's not a problem.
   remote_logs_manager_.DisableForBrowserContext(browser_context_id);
 
   MaybeReply(FROM_HERE, std::move(reply));
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager.h b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
index 8903e26..f283b7c 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager.h
@@ -19,7 +19,6 @@
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h"
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_local.h"
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h"
-#include "components/prefs/pref_change_registrar.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/webrtc_event_logger.h"
 
@@ -74,7 +73,7 @@
   void EnableForBrowserContext(content::BrowserContext* browser_context,
                                base::OnceClosure reply) override;
 
-  void DisableForBrowserContext(content::BrowserContext* browser_context,
+  void DisableForBrowserContext(const content::BrowserContext* browser_context,
                                 base::OnceClosure reply) override;
 
   void PeerConnectionAdded(int render_process_id,
@@ -199,13 +198,6 @@
   void OnLoggingTargetStarted(LoggingTarget target, PeerConnectionKey key);
   void OnLoggingTargetStopped(LoggingTarget target, PeerConnectionKey key);
 
-  void StartListeningForPrefChangeForBrowserContext(
-      content::BrowserContext* browser_context);
-  void StopListeningForPrefChangeForBrowserContext(
-      content::BrowserContext* browser_context);
-
-  void OnPrefChange(content::BrowserContext* browser_context);
-
   // network_connection_tracker() and system_request_context() are not available
   // during instantiation; we get them when the first profile is loaded, which
   // is also the earliest time when they could be needed.
@@ -219,14 +211,17 @@
       net::URLRequestContextGetter* url_request_context_getter,
       std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory);
 
-  void EnableRemoteBoundLoggingForBrowserContext(
+  // The BrowserContext is always enabled for local-bound logs.
+  // |enable_for_remote_logging| indicates whether it should also be enabled
+  // for remote-bound logs. This depends on a Chrome policy.
+  void EnableForBrowserContextInternal(
       BrowserContextId browser_context_id,
       const base::FilePath& browser_context_dir,
+      bool enable_for_remote_logging,
       base::OnceClosure reply);
 
-  void DisableRemoteBoundLoggingForBrowserContext(
-      BrowserContextId browser_context_id,
-      base::OnceClosure reply);
+  void DisableForBrowserContextInternal(BrowserContextId browser_context_id,
+                                        base::OnceClosure reply);
 
   void PeerConnectionAddedInternal(PeerConnectionKey key,
                                    const std::string& peer_connection_id,
@@ -333,15 +328,10 @@
   // This is only possible when the appropriate Chrome policy is configured.
   WebRtcRemoteEventLogManager remote_logs_manager_;
 
-  // Each loaded BrowserContext is mapped to a PrefChangeRegistrar, which keeps
-  // us informed about preference changes, thereby allowing as to support
-  // dynamic refresh.
-  std::map<BrowserContextId, PrefChangeRegistrar> pref_change_registrars_;
-
   // This keeps track of which peer connections have event logging turned on
   // in WebRTC, and for which client(s).
   std::map<PeerConnectionKey, LoggingTargetBitmap>
-      peer_connections_with_event_logging_enabled_in_webrtc_;
+      peer_connections_with_event_logging_enabled_;
 
   // The set of RenderProcessHosts with which the manager is registered for
   // observation. Allows us to register for each RPH only once, and get notified
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
index fcd8318..b4502da9 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.cc
@@ -217,10 +217,10 @@
     return;
   }
 
-  enabled_browser_contexts_.insert(browser_context_id);
-
   AddPendingLogs(browser_context_id, remote_bound_logs_dir);
 
+  enabled_browser_contexts_.insert(browser_context_id);
+
   if (!proactive_prune_scheduling_delta_.is_zero() &&
       !proactive_prune_scheduling_started_) {
     proactive_prune_scheduling_started_ = true;
@@ -228,6 +228,7 @@
   }
 }
 
+// TODO(crbug.com/775415): Add unit tests.
 void WebRtcRemoteEventLogManager::DisableForBrowserContext(
     BrowserContextId browser_context_id) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
@@ -239,14 +240,8 @@
   enabled_browser_contexts_.erase(browser_context_id);
 
 #if DCHECK_IS_ON()
-  // DisableForBrowserContext() is called in one of two cases:
-  // 1. If Chrome is shutting down. In that case, all the RPHs associated with
-  //    this BrowserContext must already have exited, which should have
-  //    implicitly stopped all active logs.
-  // 2. Remote-bound logging is no longer allowed for this BrowserContext.
-  //    In that case, some peer connections associated with this BrowserContext
-  //    might still be active, or become active at a later time, but all
-  //    logs must have already been stopped.
+  // All of the RPHs associated with this BrowserContext must already have
+  // exited, which should have implicitly stopped all active logs.
   auto pred = [browser_context_id](decltype(active_logs_)::value_type& log) {
     return log.first.browser_context_id == browser_context_id;
   };
@@ -254,6 +249,7 @@
 #endif
 
   // Pending logs for this BrowserContext are no longer eligible for upload.
+  // (Active uploads, if any, are not affected.)
   for (auto it = pending_logs_.begin(); it != pending_logs_.end();) {
     if (it->browser_context_id == browser_context_id) {
       it = pending_logs_.erase(it);
@@ -262,9 +258,6 @@
     }
   }
 
-  // Active uploads of logs associated with this BrowserContext must be stopped.
-  MaybeCancelUpload(base::Time::Min(), base::Time::Max(), browser_context_id);
-
   // Active logs may have been removed, which could remove upload suppression,
   // or pending logs which were about to be uploaded may have been removed,
   // so uploading may no longer be possible.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
index 9a0fb638..838e984d 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h
@@ -57,18 +57,12 @@
   // peer connections associated with this BrowserContext, in the
   // BrowserContext's user-data directory, becomes possible.
   // This method would typically be called when a BrowserContext is initialized.
-  // Enabling for the same BrowserContext twice in a row, without disabling
-  // in between, is an error.
   void EnableForBrowserContext(BrowserContextId browser_context_id,
                                const base::FilePath& browser_context_dir);
 
-  // Disables remote-bound logging for a given BrowserContext. Pending logs from
-  // earlier (while it was enabled) may no longer be uploaded, additional
-  // logs will not be created, and any active uploads associated with the
-  // BrowserContext will be cancelled.
-  // Disabling for a BrowserContext which was not enabled is not an error,
-  // because the caller is not required to know whether a previous call
-  // to EnableForBrowserContext() was successful.
+  // Enables remote-bound logging for a given BrowserContext. Pending logs from
+  // earlier (while it was enabled) may still be uploaded, but no additional
+  // logs will be created.
   void DisableForBrowserContext(BrowserContextId browser_context_id);
 
   // Called to inform |this| of peer connections being added/removed.
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
index f49eb7bb..b9258c94 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
@@ -150,33 +150,20 @@
 
   class Factory : public WebRtcEventLogUploader::Factory {
    public:
-    Factory(bool cancellation_expected,
-            base::Optional<size_t> expected_instance_count =
-                base::Optional<size_t>())
-        : cancellation_expected_(cancellation_expected),
-          expected_instance_count_(expected_instance_count),
-          instance_count_(0) {}
+    explicit Factory(bool cancellation_expected)
+        : cancellation_expected_(cancellation_expected) {}
 
-    ~Factory() override {
-      if (expected_instance_count_.has_value()) {
-        EXPECT_EQ(instance_count_, expected_instance_count_.value());
-      }
-    }
+    ~Factory() override = default;
 
     std::unique_ptr<WebRtcEventLogUploader> Create(
         const WebRtcLogFileInfo& log_file,
         UploadResultCallback callback) override {
-      if (expected_instance_count_.has_value()) {
-        EXPECT_LE(++instance_count_, expected_instance_count_.value());
-      }
       return std::make_unique<NullWebRtcEventLogUploader>(
           log_file, cancellation_expected_);
     }
 
    private:
     const bool cancellation_expected_;
-    const base::Optional<size_t> expected_instance_count_;
-    size_t instance_count_;
   };
 
  private:
@@ -886,23 +873,6 @@
   const bool policy_enabled_;  // Whether the policy is enabled for the profile.
 };
 
-class WebRtcEventLogManagerTestPolicy : public WebRtcEventLogManagerTestBase {
- public:
-  WebRtcEventLogManagerTestPolicy() {
-    scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog);
-
-    // Avoid proactive pruning; it has the potential to mess up tests, as well
-    // as keep pendings tasks around with a dangling reference to the unit
-    // under test. (Zero is a sentinel value for disabling proactive pruning.)
-    scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII(
-        ::switches::kWebRtcRemoteEventLogUploadDelayMs, "0");
-
-    event_log_manager_ = WebRtcEventLogManager::CreateSingletonInstance();
-  }
-
-  ~WebRtcEventLogManagerTestPolicy() override = default;
-};
-
 class WebRtcEventLogManagerTestUploadSuppressionDisablingFlag
     : public WebRtcEventLogManagerTestBase {
  public:
@@ -1024,9 +994,6 @@
   WebRtcEventLogManagerTestCompression() {
     scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog);
 
-    // Avoid proactive pruning; it has the potential to mess up tests, as well
-    // as keep pendings tasks around with a dangling reference to the unit
-    // under test. (Zero is a sentinel value for disabling proactive pruning.)
     scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII(
         ::switches::kWebRtcRemoteEventLogUploadDelayMs, "0");
   }
@@ -3574,253 +3541,6 @@
                         WebRtcEventLogManagerTestWithRemoteLoggingDisabled,
                         ::testing::Bool());
 
-// This test is redundant; it is provided for completeness; see following tests.
-TEST_F(WebRtcEventLogManagerTestPolicy, StartsEnabledAllowsRemoteLogging) {
-  const bool allow_remote_logging = true;
-  auto browser_context = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(browser_context.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-  EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging);
-}
-
-// This test is redundant; it is provided for completeness; see following tests.
-TEST_F(WebRtcEventLogManagerTestPolicy, StartsDisabledRejectsRemoteLogging) {
-  const bool allow_remote_logging = false;
-  auto browser_context = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(browser_context.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-  EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging);
-}
-
-// #1 and #2 differ in the order of AddPeerConnection and the changing of
-// the pref value.
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsEnabledThenDisabledRejectsRemoteLogging1) {
-  bool allow_remote_logging = true;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging);
-}
-
-// #1 and #2 differ in the order of AddPeerConnection and the changing of
-// the pref value.
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsEnabledThenDisabledRejectsRemoteLogging2) {
-  bool allow_remote_logging = true;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-
-  EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging);
-}
-
-// #1 and #2 differ in the order of AddPeerConnection and the changing of
-// the pref value.
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsDisabledThenEnabledAllowsRemoteLogging1) {
-  bool allow_remote_logging = false;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging);
-}
-
-// #1 and #2 differ in the order of AddPeerConnection and the changing of
-// the pref value.
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsDisabledThenEnabledAllowsRemoteLogging2) {
-  bool allow_remote_logging = false;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-
-  EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging);
-}
-
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsDisabledThenEnabledUploadsPendingLogFiles) {
-  bool allow_remote_logging = false;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  base::Optional<base::FilePath> log_file;
-  ON_CALL(remote_observer_, OnRemoteLogStarted(key, _))
-      .WillByDefault(Invoke(SaveFilePathTo(&log_file)));
-  ASSERT_TRUE(PeerConnectionAdded(key));
-  ASSERT_TRUE(allow_remote_logging)
-      << "Must turn on before StartRemoteLogging, to test the right thing.";
-  ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging);
-  ASSERT_TRUE(log_file);
-
-  base::RunLoop run_loop;
-  std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo(
-      browser_context_id_, *log_file, GetLastModificationTime(*log_file))};
-  SetWebRtcEventLogUploaderFactoryForTesting(
-      std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>(
-          &expected_files, true, &run_loop));
-
-  ASSERT_TRUE(PeerConnectionRemoved(key));
-
-  WaitForPendingTasks(&run_loop);
-}
-
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsEnabledThenDisabledDoesNotUploadPendingLogFiles) {
-  SuppressUploading();
-
-  std::list<WebRtcLogFileInfo> empty_list;
-  base::RunLoop run_loop;
-  SetWebRtcEventLogUploaderFactoryForTesting(
-      std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>(
-          &empty_list, true, &run_loop));
-
-  bool allow_remote_logging = true;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  ASSERT_TRUE(PeerConnectionAdded(key));
-  ASSERT_TRUE(allow_remote_logging)
-      << "Must turn off after StartRemoteLogging, to test the right thing.";
-  ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging);
-  ASSERT_TRUE(PeerConnectionRemoved(key));
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  UnsuppressUploading();
-
-  WaitForPendingTasks(&run_loop);
-}
-
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsEnabledThenDisabledDeletesPendingLogFiles) {
-  SuppressUploading();
-
-  std::list<WebRtcLogFileInfo> empty_list;
-  base::RunLoop run_loop;
-  SetWebRtcEventLogUploaderFactoryForTesting(
-      std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>(
-          &empty_list, true, &run_loop));
-
-  bool allow_remote_logging = true;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  base::Optional<base::FilePath> log_file;
-  ON_CALL(remote_observer_, OnRemoteLogStarted(key, _))
-      .WillByDefault(Invoke(SaveFilePathTo(&log_file)));
-  ASSERT_TRUE(PeerConnectionAdded(key));
-  ASSERT_TRUE(allow_remote_logging)
-      << "Must turn off after StartRemoteLogging, to test the right thing.";
-  ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging);
-  ASSERT_TRUE(log_file);
-
-  // Make the file PENDING.
-  ASSERT_TRUE(PeerConnectionRemoved(key));
-  ASSERT_TRUE(base::PathExists(*log_file));  // Test sanity; exists before.
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  WaitForPendingTasks(&run_loop);
-
-  // Test focus - file deleted without being uploaded.
-  EXPECT_FALSE(base::PathExists(*log_file));
-
-  // Still not uploaded.
-  UnsuppressUploading();
-  WaitForPendingTasks();
-}
-
-TEST_F(WebRtcEventLogManagerTestPolicy,
-       StartsEnabledThenDisabledCancelsAndDeletesCurrentlyUploadedLogFile) {
-  // This factory expects exactly one log to be created, then cancelled.
-  SetWebRtcEventLogUploaderFactoryForTesting(
-      std::make_unique<NullWebRtcEventLogUploader::Factory>(true, 1));
-
-  bool allow_remote_logging = true;
-  auto profile = CreateBrowserContext("name", allow_remote_logging);
-
-  auto rph = std::make_unique<MockRenderProcessHost>(profile.get());
-  const auto key = GetPeerConnectionKey(rph.get(), kLid);
-
-  base::Optional<base::FilePath> log_file;
-  ON_CALL(remote_observer_, OnRemoteLogStarted(key, _))
-      .WillByDefault(Invoke(SaveFilePathTo(&log_file)));
-  ASSERT_TRUE(PeerConnectionAdded(key));
-  ASSERT_TRUE(allow_remote_logging)
-      << "Must turn off after StartRemoteLogging, to test the right thing.";
-  ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging);
-  ASSERT_TRUE(log_file);
-
-  // Log file's upload commences.
-  ASSERT_TRUE(PeerConnectionRemoved(key));
-
-  ASSERT_TRUE(base::PathExists(*log_file));  // Test sanity; exists before.
-
-  allow_remote_logging = !allow_remote_logging;
-  profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed,
-                                  allow_remote_logging);
-
-  WaitForPendingTasks();
-
-  // Test focus - file deleted without being uploaded.
-  // When the test terminates, the NullWebRtcEventLogUploader::Factory's
-  // expectation that one log file was uploaded, and that the upload was
-  // cancelled, is enforced.
-  // Deletion of the file not performed by NullWebRtcEventLogUploader; instead,
-  // WebRtcEventLogUploaderImplTest.CancelOnOngoingUploadDeletesFile tests that.
-}
-
 TEST_F(WebRtcEventLogManagerTestUploadSuppressionDisablingFlag,
        UploadingNotSuppressedByActivePeerConnections) {
   SuppressUploading();
diff --git a/chrome/browser/metrics/upgrade_metrics_provider.cc b/chrome/browser/metrics/upgrade_metrics_provider.cc
index 53db7002..826a67773 100644
--- a/chrome/browser/metrics/upgrade_metrics_provider.cc
+++ b/chrome/browser/metrics/upgrade_metrics_provider.cc
@@ -14,8 +14,7 @@
 void UpgradeMetricsProvider::ProvideCurrentSessionData(
     metrics::ChromeUserMetricsExtension* uma_proto) {
   UpgradeDetector* upgrade_detector = UpgradeDetector::GetInstance();
-  UMA_HISTOGRAM_ENUMERATION(
-      "UpgradeDetector.NotificationStage",
-      upgrade_detector->upgrade_notification_stage(),
-      UpgradeDetector::kUpgradeNotificationAnnoyanceLevelCount);
+  UMA_HISTOGRAM_ENUMERATION("UpgradeDetector.NotificationStage",
+                            upgrade_detector->upgrade_notification_stage(),
+                            UpgradeDetector::UPGRADE_ANNOYANCE_MAX_VALUE + 1);
 }
diff --git a/chrome/browser/metrics/upgrade_metrics_provider.h b/chrome/browser/metrics/upgrade_metrics_provider.h
index 42f85c8..c9ed83f 100644
--- a/chrome/browser/metrics/upgrade_metrics_provider.h
+++ b/chrome/browser/metrics/upgrade_metrics_provider.h
@@ -8,9 +8,8 @@
 #include "base/macros.h"
 #include "components/metrics/metrics_provider.h"
 
-// UpgradeMetricsProvider groups various constants and functions used for
-// reporting extension IDs with UMA reports (after hashing the extension IDs
-// for privacy).
+// UpgradeMetricsProvider reports the state of detected pending updates in UMA
+// reports.
 class UpgradeMetricsProvider : public metrics::MetricsProvider {
  public:
   UpgradeMetricsProvider();
diff --git a/chrome/browser/metrics/upgrade_metrics_provider_unittest.cc b/chrome/browser/metrics/upgrade_metrics_provider_unittest.cc
index c5a0135..6068a99 100644
--- a/chrome/browser/metrics/upgrade_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/upgrade_metrics_provider_unittest.cc
@@ -31,6 +31,7 @@
 TEST_F(UpgradeMetricsProviderTest, HistogramCheck) {
   base::test::ScopedTaskEnvironment task_environment;
   TestHistogramLevel(UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+  TestHistogramLevel(UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
   TestHistogramLevel(UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
   TestHistogramLevel(UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
   TestHistogramLevel(UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
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
index 3147c6a8..a3cbdfd 100644
--- 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
@@ -281,6 +281,8 @@
   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.
diff --git a/chrome/browser/policy/browser_dm_token_storage_linux.cc b/chrome/browser/policy/browser_dm_token_storage_linux.cc
index d84e893..44b63be 100644
--- a/chrome/browser/policy/browser_dm_token_storage_linux.cc
+++ b/chrome/browser/policy/browser_dm_token_storage_linux.cc
@@ -117,8 +117,8 @@
   if (!base::ReadFileToString(token_file_path, &enrollment_token))
     return std::string();
 
-  return std::string(
-      base::TrimWhitespaceASCII(enrollment_token, base::TRIM_TRAILING));
+  return base::TrimWhitespaceASCII(enrollment_token, base::TRIM_ALL)
+      .as_string();
 }
 
 std::string BrowserDMTokenStorageLinux::InitDMToken() {
diff --git a/chrome/browser/policy/browser_dm_token_storage_mac.mm b/chrome/browser/policy/browser_dm_token_storage_mac.mm
index e4c6d0e..7ed47ac 100644
--- a/chrome/browser/policy/browser_dm_token_storage_mac.mm
+++ b/chrome/browser/policy/browser_dm_token_storage_mac.mm
@@ -38,6 +38,15 @@
     FILE_PATH_LITERAL("Google/Chrome Cloud Enrollment/");
 const CFStringRef kEnrollmentTokenPolicyName =
     CFSTR("MachineLevelUserCloudPolicyEnrollmentToken");
+const char kEnrollmentTokenFilePath[] =
+#if defined(GOOGLE_CHROME_BUILD)
+    FILE_PATH_LITERAL(
+        "/Library/Google/Chrome/MachineLevelUserCloudPolicyEnrollmentToken");
+#else
+    FILE_PATH_LITERAL(
+        "/Library/Application "
+        "Support/Chromium/MachineLevelUserCloudPolicyEnrollmentToken");
+#endif
 
 bool GetDmTokenFilePath(base::FilePath* token_file_path,
                         const std::string& client_id,
@@ -69,6 +78,46 @@
   return base::ImportantFileWriter::WriteFileAtomically(token_file_path, token);
 }
 
+// Get the enrollment token from policy file: /Library/com.google.Chrome.plist.
+// Return true if policy is set, otherwise false.
+bool GetEnrollmentTokenFromPolicy(std::string* enrollment_token) {
+// Since the configuration management infrastructure is not initialized when
+// this code runs, read the policy preference directly.
+#if defined(GOOGLE_CHROME_BUILD)
+  // Explicitly access the "com.google.Chrome" bundle ID, no matter what this
+  // app's bundle ID actually is. All channels of Chrome should obey the same
+  // policies.
+  CFStringRef bundle_id = CFSTR("com.google.Chrome");
+#else
+  base::ScopedCFTypeRef<CFStringRef> bundle_id(
+      base::SysUTF8ToCFStringRef(base::mac::BaseBundleID()));
+#endif
+
+  base::ScopedCFTypeRef<CFPropertyListRef> value(
+      CFPreferencesCopyAppValue(kEnrollmentTokenPolicyName, bundle_id));
+
+  if (!value ||
+      !CFPreferencesAppValueIsForced(kEnrollmentTokenPolicyName, bundle_id)) {
+    return false;
+  }
+  CFStringRef value_string = base::mac::CFCast<CFStringRef>(value);
+  if (!value_string)
+    return false;
+
+  *enrollment_token = base::SysCFStringRefToUTF8(value_string);
+  return true;
+}
+
+bool GetEnrollmentTokenFromFile(std::string* enrollment_token) {
+  if (!base::ReadFileToString(base::FilePath(kEnrollmentTokenFilePath),
+                              enrollment_token)) {
+    return false;
+  }
+  *enrollment_token =
+      base::TrimWhitespaceASCII(*enrollment_token, base::TRIM_ALL).as_string();
+  return true;
+}
+
 }  // namespace
 
 // static
@@ -110,29 +159,14 @@
 }
 
 std::string BrowserDMTokenStorageMac::InitEnrollmentToken() {
-  // Since the configuration management infrastructure is not initialized when
-  // this code runs, read the policy preference directly.
-#if defined(GOOGLE_CHROME_BUILD)
-  // Explicitly access the "com.google.Chrome" bundle ID, no matter what this
-  // app's bundle ID actually is. All channels of Chrome should obey the same
-  // policies.
-  CFStringRef bundle_id = CFSTR("com.google.Chrome");
-#else
-  base::ScopedCFTypeRef<CFStringRef> bundle_id(
-      base::SysUTF8ToCFStringRef(base::mac::BaseBundleID()));
-#endif
+  std::string enrollment_token;
+  if (GetEnrollmentTokenFromPolicy(&enrollment_token))
+    return enrollment_token;
 
-  base::ScopedCFTypeRef<CFPropertyListRef> value(
-      CFPreferencesCopyAppValue(kEnrollmentTokenPolicyName, bundle_id));
+  if (GetEnrollmentTokenFromFile(&enrollment_token))
+    return enrollment_token;
 
-  if (!value ||
-      !CFPreferencesAppValueIsForced(kEnrollmentTokenPolicyName, bundle_id))
-    return std::string();
-  CFStringRef value_string = base::mac::CFCast<CFStringRef>(value);
-  if (!value_string)
-    return std::string();
-
-  return base::SysCFStringRefToUTF8(value_string);
+  return std::string();
 }
 
 std::string BrowserDMTokenStorageMac::InitDMToken() {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 95e7b325..5d1735b 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -84,6 +84,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker_test_support.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
+#include "chrome/browser/search/ntp_features.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ssl/ssl_blocking_page.h"
@@ -98,6 +99,8 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h"
+#include "chrome/browser/ui/search/instant_test_utils.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
 #include "chrome/browser/ui/toolbar/media_router_action_controller.h"
@@ -114,7 +117,9 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/web_application_info.h"
+#include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "chrome/grit/locale_settings.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/search_test_utils.h"
 #include "chrome/test/base/testing_profile.h"
@@ -131,6 +136,7 @@
 #include "components/infobars/core/infobar.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/network_time/network_time_tracker.h"
+#include "components/ntp_tiles/constants.h"
 #include "components/omnibox/browser/autocomplete_controller.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
@@ -354,6 +360,14 @@
       base::PathService::Get(chrome::DIR_TEST_DATA, test_data_directory));
 }
 
+content::RenderFrameHost* GetMostVisitedIframe(content::WebContents* tab) {
+  for (content::RenderFrameHost* frame : tab->GetAllFrames()) {
+    if (frame->GetFrameName() == "mv-single")
+      return frame;
+  }
+  return nullptr;
+}
+
 // Filters requests to the hosts in |urls| and redirects them to the test data
 // dir through URLRequestMockHTTPJobs.
 void RedirectHostsToTestData(const char* const urls[], size_t size) {
@@ -599,6 +613,16 @@
   return result;
 }
 
+bool ContainsWebstoreTile(content::RenderFrameHost* iframe) {
+  int num_webstore_tiles = 0;
+  EXPECT_TRUE(instant_test_utils::GetIntFromJS(
+      iframe,
+      "document.querySelectorAll(\".md-tile[href='" +
+          l10n_util::GetStringUTF8(IDS_WEBSTORE_URL) + "']\").length",
+      &num_webstore_tiles));
+  return num_webstore_tiles == 1;
+}
+
 #if defined(OS_CHROMEOS)
 class TestAudioObserver : public chromeos::CrasAudioHandler::AudioObserver {
  public:
@@ -2038,39 +2062,6 @@
   EXPECT_TRUE(is_toggle_dev_mode_checkbox_disabled);
 }
 
-// TODO(samarth): remove along with rest of NTP4 code.
-IN_PROC_BROWSER_TEST_F(PolicyTest, DISABLED_WebStoreIconHidden) {
-  // Verifies that the web store icons can be hidden from the new tab page.
-
-  // Open new tab page and look for the web store icons.
-  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
-  content::WebContents* contents =
-    browser()->tab_strip_model()->GetActiveWebContents();
-
-#if !defined(OS_CHROMEOS)
-  // Look for web store's app ID in the apps page.
-  EXPECT_TRUE(ContainsVisibleElement(contents,
-                                     "ahfgeienlihckogmohjhadlkjgocpleb"));
-#endif
-
-  // The next NTP has no footer.
-  if (ContainsVisibleElement(contents, "footer"))
-    EXPECT_TRUE(ContainsVisibleElement(contents, "chrome-web-store-link"));
-
-  // Turn off the web store icons.
-  PolicyMap policies;
-  policies.Set(key::kHideWebStoreIcon, POLICY_LEVEL_MANDATORY,
-               POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-               base::WrapUnique(new base::Value(true)), nullptr);
-  UpdateProviderPolicy(policies);
-
-  // The web store icons should now be hidden.
-  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
-  EXPECT_FALSE(ContainsVisibleElement(contents,
-                                      "ahfgeienlihckogmohjhadlkjgocpleb"));
-  EXPECT_FALSE(ContainsVisibleElement(contents, "chrome-web-store-link"));
-}
-
 IN_PROC_BROWSER_TEST_F(PolicyTest, DownloadDirectory) {
   // Verifies that the download directory can be forced by policy.
 
@@ -4063,6 +4054,127 @@
   EXPECT_GT(samples->GetCount(82), 0);
 }
 
+// Similar to PolicyTest, but force to enable the new tab material design flag
+// before the browser start.
+class PolicyWebStoreIconTest : public PolicyTest {
+ public:
+  PolicyWebStoreIconTest() {}
+  ~PolicyWebStoreIconTest() override {}
+
+  void SetUpInProcessBrowserTestFixture() override {
+    PolicyTest::SetUpInProcessBrowserTestFixture();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PolicyTest::SetUpCommandLine(command_line);
+    // Force to enable the new tab page material design flag
+    scoped_feature_list.InitAndEnableFeature(ntp_tiles::kNtpIcons);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PolicyWebStoreIconTest);
+  base::test::ScopedFeatureList scoped_feature_list;
+};
+
+IN_PROC_BROWSER_TEST_F(PolicyWebStoreIconTest, AppsWebStoreIconHidden) {
+  // Verifies that the web store icon can be hidden from the chrome://apps
+  // page. A policy change takes immediate effect on the apps page for the
+  // current profile. Browser restart is not required.
+
+  // Open new tab page and look for the web store icons.
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAppsURL));
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+#if !defined(OS_CHROMEOS)
+  // Look for web store's app ID in the apps page.
+  EXPECT_TRUE(
+      ContainsVisibleElement(contents, "ahfgeienlihckogmohjhadlkjgocpleb"));
+#endif
+
+  // The next NTP has no footer.
+  if (ContainsVisibleElement(contents, "footer"))
+    EXPECT_TRUE(ContainsVisibleElement(contents, "chrome-web-store-link"));
+
+  // Turn off the web store icons.
+  PolicyMap policies;
+  policies.Set(key::kHideWebStoreIcon, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+               base::WrapUnique(new base::Value(true)), nullptr);
+  UpdateProviderPolicy(policies);
+
+  // The web store icons should now be hidden.
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAppsURL));
+  EXPECT_FALSE(
+      ContainsVisibleElement(contents, "ahfgeienlihckogmohjhadlkjgocpleb"));
+  EXPECT_FALSE(ContainsVisibleElement(contents, "chrome-web-store-link"));
+}
+
+IN_PROC_BROWSER_TEST_F(PolicyWebStoreIconTest, NTPWebStoreIconShown) {
+  // This test is to verify that the web store icons is shown when no policy
+  // applies. See WebStoreIconPolicyTest.NTPWebStoreIconHidden for verification
+  // when a policy is in effect.
+
+  // Force to enable the new tab page material design flag
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(ntp_tiles::kNtpIcons);
+
+  // Open new tab page and look for the web store icons.
+  content::WebContents* active_tab =
+      local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+
+  content::RenderFrameHost* iframe = GetMostVisitedIframe(active_tab);
+
+  // Look though all the tiles and see whether there is a webstore icon.
+  // Make sure that there is one web store icon.
+  EXPECT_TRUE(ContainsWebstoreTile(iframe));
+}
+
+// Similar to PolicyWebStoreIconShownTest, but applies the HideWebStoreIcon
+// policy before the browser is started. This is required because the list that
+// includes the WebStoreIcon on the NTP is initialized at browser start.
+class PolicyWebStoreIconHiddenTest : public PolicyTest {
+ public:
+  PolicyWebStoreIconHiddenTest() {}
+  ~PolicyWebStoreIconHiddenTest() override {}
+
+  void SetUpInProcessBrowserTestFixture() override {
+    PolicyTest::SetUpInProcessBrowserTestFixture();
+    PolicyMap policies;
+    policies.Set(key::kHideWebStoreIcon, POLICY_LEVEL_MANDATORY,
+                 POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+                 std::make_unique<base::Value>(true), nullptr);
+    provider_.UpdateChromePolicy(policies);
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PolicyTest::SetUpCommandLine(command_line);
+    // Force to enable the new tab page material design flag
+    scoped_feature_list.InitAndEnableFeature(ntp_tiles::kNtpIcons);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PolicyWebStoreIconHiddenTest);
+  base::test::ScopedFeatureList scoped_feature_list;
+};
+
+IN_PROC_BROWSER_TEST_F(PolicyWebStoreIconHiddenTest, NTPWebStoreIconHidden) {
+  // Verifies that the web store icon can be hidden from the new tab page. Check
+  // to see NTPWebStoreIconShown for behavior when the policy is not applied.
+
+  // Open new tab page and look for the web store icon
+  content::WebContents* active_tab =
+      local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+
+  content::RenderFrameHost* iframe = GetMostVisitedIframe(active_tab);
+
+  // Applying the policy before the browser started, the web store icon should
+  // now be hidden.
+  EXPECT_FALSE(ContainsWebstoreTile(iframe));
+}
+
 class MediaStreamDevicesControllerBrowserTest
     : public PolicyTest,
       public testing::WithParamInterface<bool> {
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index d0cbf3c9..d05890fc 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -316,6 +316,7 @@
 #endif
 
 #if !defined(OS_ANDROID)
+#include "chrome/browser/media/unified_autoplay_config.h"
 #include "components/ntp_tiles/custom_links_manager_impl.h"
 #endif
 
@@ -740,6 +741,10 @@
   confirm_quit::RegisterLocalState(registry);
 #endif
 
+#if !defined(OS_ANDROID)
+  UnifiedAutoplayConfig::RegisterProfilePrefs(registry);
+#endif
+
   RegisterProfilePrefsForMigration(registry);
 }
 
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index f8cf5fbd..bc3f0abd 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -453,18 +453,17 @@
 
 std::unique_ptr<PrefService> CreateLocalState(
     const base::FilePath& pref_filename,
-    base::SequencedTaskRunner* pref_io_task_runner,
     policy::PolicyService* policy_service,
     scoped_refptr<PrefRegistry> pref_registry,
     bool async,
     std::unique_ptr<PrefValueStore::Delegate> delegate) {
   sync_preferences::PrefServiceSyncableFactory factory;
-  PrepareFactory(&factory, pref_filename, policy_service,
-                 nullptr,  // supervised_user_settings
-                 new JsonPrefStore(pref_filename, pref_io_task_runner,
-                                   std::unique_ptr<PrefFilter>()),
-                 nullptr,  // extension_prefs
-                 async);
+  PrepareFactory(
+      &factory, pref_filename, policy_service,
+      nullptr,  // supervised_user_settings
+      new JsonPrefStore(pref_filename, std::unique_ptr<PrefFilter>()),
+      nullptr,  // extension_prefs
+      async);
   return factory.Create(std::move(pref_registry), std::move(delegate));
 }
 
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.h b/chrome/browser/prefs/chrome_pref_service_factory.h
index c6617f7..8020d463 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.h
+++ b/chrome/browser/prefs/chrome_pref_service_factory.h
@@ -66,7 +66,6 @@
 
 std::unique_ptr<PrefService> CreateLocalState(
     const base::FilePath& pref_filename,
-    base::SequencedTaskRunner* pref_io_task_runner,
     policy::PolicyService* policy_service,
     scoped_refptr<PrefRegistry> pref_registry,
     bool async,
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index 63e904d..421d93b 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -10,7 +10,6 @@
 #include "build/build_config.h"
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
-#include "components/certificate_transparency/pref_names.h"
 #include "components/consent_auditor/pref_names.h"
 #include "components/dom_distiller/core/pref_names.h"
 #include "components/flags_ui/flags_ui_pref_names.h"
@@ -47,7 +46,6 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_pref_names.h"
-#include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chromeos/chromeos_pref_names.h"
 #include "components/drive/drive_pref_names.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
@@ -87,6 +85,15 @@
     ash::prefs::kShouldAlwaysShowAccessibilityMenu,
 #endif  // defined(OS_CHROMEOS)
 
+    // Bookmark preferences are common between incognito and regular mode.
+    bookmarks::prefs::kBookmarkEditorExpandedNodes,
+    bookmarks::prefs::kEditBookmarksEnabled,
+    bookmarks::prefs::kManagedBookmarks,
+    bookmarks::prefs::kManagedBookmarksFolderName,
+    bookmarks::prefs::kShowAppsShortcutInBookmarkBar,
+    bookmarks::prefs::kShowManagedBookmarksInBookmarkBar,
+    bookmarks::prefs::kShowBookmarkBar,
+
     // Metrics preferences are out of profile scope and are merged between
     // incognito and regular modes.
     metrics::prefs::kInstallDate, metrics::prefs::kMetricsClientID,
@@ -131,6 +138,26 @@
     metrics::prefs::kUninstallMetricsPageLoadCount,
     metrics::prefs::kUninstallMetricsUptimeSec, metrics::prefs::kUkmCellDataUse,
     metrics::prefs::kUmaCellDataUse, metrics::prefs::kUserCellDataUse,
+
+    // Variations preferences maybe changed from incognito mode and should be
+    // kept in sync between incognito and regular modes.
+    variations::prefs::kVariationsCompressedSeed,
+    variations::prefs::kVariationsCountry,
+    variations::prefs::kVariationsCrashStreak,
+    variations::prefs::kVariationsFailedToFetchSeedStreak,
+    variations::prefs::kVariationsLastFetchTime,
+    variations::prefs::kVariationsPermanentConsistencyCountry,
+    variations::prefs::kVariationsPermutedEntropyCache,
+    variations::prefs::kVariationsRestrictParameter,
+    variations::prefs::kVariationsSafeCompressedSeed,
+    variations::prefs::kVariationsSafeSeedDate,
+    variations::prefs::kVariationsSafeSeedFetchTime,
+    variations::prefs::kVariationsSafeSeedLocale,
+    variations::prefs::kVariationsSafeSeedPermanentConsistencyCountry,
+    variations::prefs::kVariationsSafeSeedSessionConsistencyCountry,
+    variations::prefs::kVariationsSafeSeedSignature,
+    variations::prefs::kVariationsSeedDate,
+    variations::prefs::kVariationsSeedSignature,
 };
 
 // TODO(https://crbug.com/861722): Remove this list.
@@ -168,11 +195,6 @@
     ash::prefs::kTouchpadEnabled, ash::prefs::kTouchscreenEnabled,
 #endif  // defined(OS_CHROMEOS)
 
-// chrome/browser/chromeos/crostini/crostini_pref_names.h
-#if defined(OS_CHROMEOS)
-    crostini::prefs::kCrostiniEnabled,
-#endif  // defined(OS_CHROMEOS)
-
 // chrome/browser/accessibility/animation_policy_prefs.h
 #if !defined(OS_ANDROID)
     kAnimationPolicyAllowed, kAnimationPolicyOnce, kAnimationPolicyNone,
@@ -744,21 +766,6 @@
     chromeos::prefs::kQuirksClientLastServerCheck,
 #endif  // defined(OS_CHROMEOS)
 
-    // components/bookmarks/common/bookmark_pref_names.h
-    bookmarks::prefs::kBookmarkEditorExpandedNodes,
-    bookmarks::prefs::kEditBookmarksEnabled,
-    bookmarks::prefs::kManagedBookmarks,
-    bookmarks::prefs::kManagedBookmarksFolderName,
-    bookmarks::prefs::kShowAppsShortcutInBookmarkBar,
-    bookmarks::prefs::kShowManagedBookmarksInBookmarkBar,
-    bookmarks::prefs::kShowBookmarkBar,
-
-    // components/certificate_transparency/pref_names.h
-    certificate_transparency::prefs::kCTRequiredHosts,
-    certificate_transparency::prefs::kCTExcludedHosts,
-    certificate_transparency::prefs::kCTExcludedSPKIs,
-    certificate_transparency::prefs::kCTExcludedLegacySPKIs,
-
     // components/consent_auditor/pref_names.h
     consent_auditor::prefs::kLocalConsentsDictionary,
 
@@ -853,25 +860,6 @@
     unified_consent::prefs::kUnifiedConsentMigrationState,
     unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
 
-    // components/variations/pref_names.h
-    variations::prefs::kVariationsCompressedSeed,
-    variations::prefs::kVariationsCountry,
-    variations::prefs::kVariationsCrashStreak,
-    variations::prefs::kVariationsFailedToFetchSeedStreak,
-    variations::prefs::kVariationsLastFetchTime,
-    variations::prefs::kVariationsPermanentConsistencyCountry,
-    variations::prefs::kVariationsPermutedEntropyCache,
-    variations::prefs::kVariationsRestrictParameter,
-    variations::prefs::kVariationsSafeCompressedSeed,
-    variations::prefs::kVariationsSafeSeedDate,
-    variations::prefs::kVariationsSafeSeedFetchTime,
-    variations::prefs::kVariationsSafeSeedLocale,
-    variations::prefs::kVariationsSafeSeedPermanentConsistencyCountry,
-    variations::prefs::kVariationsSafeSeedSessionConsistencyCountry,
-    variations::prefs::kVariationsSafeSeedSignature,
-    variations::prefs::kVariationsSeedDate,
-    variations::prefs::kVariationsSeedSignature,
-
     // components/web_resource/web_resource_pref_names.h
     prefs::kEulaAccepted,
 
diff --git a/chrome/browser/prefs/profile_pref_store_manager.cc b/chrome/browser/prefs/profile_pref_store_manager.cc
index 5ddd46a..6c0ac41f 100644
--- a/chrome/browser/prefs/profile_pref_store_manager.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager.cc
@@ -92,7 +92,7 @@
     prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate) {
   if (!kPlatformSupportsPreferenceTracking) {
     return new JsonPrefStore(profile_path_.Append(chrome::kPreferencesFilename),
-                             io_task_runner, nullptr);
+                             nullptr, io_task_runner);
   }
   return CreateTrackedPersistentPrefStore(
       CreateTrackedPrefStoreConfiguration(
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 3cea5f0e..8f57aa5 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
@@ -675,6 +676,20 @@
   }
 #endif
 
+  // It is important that the MessageLoop not pump extra messages during
+  // EndSession() as some of those may be tasks queued to attempt to revive
+  // services and processes that were just intentionally killed. This is a
+  // regression blocker for https://crbug.com/318527.
+  // Need to use this WeakPtr workaround as the browser test harness runs all
+  // tasks until idle when tearing down.
+  struct FailsIfCalledWhileOnStack
+      : public base::SupportsWeakPtr<FailsIfCalledWhileOnStack> {
+    void Fail() { ADD_FAILURE(); }
+  } fails_if_called_while_on_stack;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&FailsIfCalledWhileOnStack::Fail,
+                                fails_if_called_while_on_stack.AsWeakPtr()));
+
   // This retry loop reduces flakiness due to the fact that this ultimately
   // tests whether or not a code path hits a timed wait.
   bool succeeded = false;
diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc
index ab6246f..2c29b18 100644
--- a/chrome/browser/profiles/profile_downloader.cc
+++ b/chrome/browser/profiles/profile_downloader.cc
@@ -21,21 +21,17 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/signin/core/browser/account_fetcher_service.h"
 #include "components/signin/core/browser/avatar_icon_util.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_client.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
 #include "skia/ext/image_operations.h"
 #include "url/gurl.h"
 
@@ -49,12 +45,13 @@
 }  // namespace
 
 ProfileDownloader::ProfileDownloader(ProfileDownloaderDelegate* delegate)
-    : OAuth2TokenService::Consumer("profile_downloader"),
-      delegate_(delegate),
+    : delegate_(delegate),
       picture_status_(PICTURE_FAILED),
-      account_tracker_service_(
-          AccountTrackerServiceFactory::GetForProfile(
-              delegate_->GetBrowserProfile())),
+      account_tracker_service_(AccountTrackerServiceFactory::GetForProfile(
+          delegate_->GetBrowserProfile())),
+      identity_manager_(IdentityManagerFactory::GetForProfile(
+          delegate_->GetBrowserProfile())),
+      identity_manager_observer_(this),
       waiting_for_account_info_(false) {
   DCHECK(delegate_);
   account_tracker_service_->AddObserver(this);
@@ -68,26 +65,21 @@
   VLOG(1) << "Starting profile downloader...";
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  ProfileOAuth2TokenService* service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(
-          delegate_->GetBrowserProfile());
-  if (!service) {
+  if (!identity_manager_) {
     // This can happen in some test paths.
-    LOG(WARNING) << "User has no token service";
+    LOG(WARNING) << "User has no identity manager";
     delegate_->OnProfileDownloadFailure(
         this, ProfileDownloaderDelegate::TOKEN_ERROR);
     return;
   }
 
-  SigninManagerBase* signin_manager =
-      SigninManagerFactory::GetForProfile(delegate_->GetBrowserProfile());
-  account_id_ =
-      account_id.empty() ?
-          signin_manager->GetAuthenticatedAccountId() : account_id;
-  if (service->RefreshTokenIsAvailable(account_id_))
+  account_id_ = account_id.empty()
+                    ? identity_manager_->GetPrimaryAccountInfo().account_id
+                    : account_id;
+  if (identity_manager_->HasAccountWithRefreshToken(account_id_))
     StartFetchingOAuth2AccessToken();
   else
-    service->AddObserver(this);
+    identity_manager_observer_.Add(identity_manager_);
 }
 
 base::string16 ProfileDownloader::GetProfileHostedDomain() const {
@@ -145,26 +137,21 @@
 }
 
 void ProfileDownloader::StartFetchingOAuth2AccessToken() {
-  Profile* profile = delegate_->GetBrowserProfile();
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(GaiaConstants::kGoogleUserInfoProfile);
   // Required to determine if lock should be enabled.
   scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
-  ProfileOAuth2TokenService* token_service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
-  oauth2_access_token_request_ = token_service->StartRequest(
-      account_id_, scopes, this);
+
+  oauth2_access_token_fetcher_ =
+      std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
+          "profile_downloader", identity_manager_, scopes,
+          base::BindOnce(&ProfileDownloader::OnAccessTokenFetchComplete,
+                         base::Unretained(this)),
+          identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
 }
 
 ProfileDownloader::~ProfileDownloader() {
-  // Ensures PO2TS observation is cleared when ProfileDownloader is destructed
-  // before refresh token is available.
-  ProfileOAuth2TokenService* service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(
-          delegate_->GetBrowserProfile());
-  if (service)
-    service->RemoveObserver(this);
-
+  oauth2_access_token_fetcher_.reset();
   account_tracker_service_->RemoveObserver(this);
 }
 
@@ -302,41 +289,32 @@
       this, ProfileDownloaderDelegate::IMAGE_DECODE_FAILED);
 }
 
-void ProfileDownloader::OnRefreshTokenAvailable(const std::string& account_id) {
-  ProfileOAuth2TokenService* service =
-      ProfileOAuth2TokenServiceFactory::GetForProfile(
-          delegate_->GetBrowserProfile());
-  if (account_id != account_id_)
+void ProfileDownloader::OnRefreshTokenUpdatedForAccount(
+    const AccountInfo& account_info,
+    bool is_valid) {
+  if (!is_valid || account_info.account_id != account_id_)
     return;
 
-  service->RemoveObserver(this);
+  identity_manager_observer_.Remove(identity_manager_);
   StartFetchingOAuth2AccessToken();
 }
 
-// Callback for OAuth2TokenService::Request on success. |access_token| is the
-// token used to start fetching user data.
-void ProfileDownloader::OnGetTokenSuccess(
-    const OAuth2TokenService::Request* request,
-    const std::string& access_token,
-    const base::Time& expiration_time) {
-  DCHECK_EQ(request, oauth2_access_token_request_.get());
-  oauth2_access_token_request_.reset();
-  auth_token_ = access_token;
+void ProfileDownloader::OnAccessTokenFetchComplete(
+    GoogleServiceAuthError error,
+    identity::AccessTokenInfo access_token_info) {
+  oauth2_access_token_fetcher_.reset();
+  if (error.state() != GoogleServiceAuthError::NONE) {
+    LOG(WARNING)
+        << "ProfileDownloader: token request using refresh token failed:"
+        << error.ToString();
+    delegate_->OnProfileDownloadFailure(this,
+                                        ProfileDownloaderDelegate::TOKEN_ERROR);
+    return;
+  }
+  auth_token_ = access_token_info.token;
   StartFetchingImage();
 }
 
-// Callback for OAuth2TokenService::Request on failure.
-void ProfileDownloader::OnGetTokenFailure(
-    const OAuth2TokenService::Request* request,
-    const GoogleServiceAuthError& error) {
-  DCHECK_EQ(request, oauth2_access_token_request_.get());
-  oauth2_access_token_request_.reset();
-  LOG(WARNING) << "ProfileDownloader: token request using refresh token failed:"
-               << error.ToString();
-  delegate_->OnProfileDownloadFailure(
-      this, ProfileDownloaderDelegate::TOKEN_ERROR);
-}
-
 void ProfileDownloader::OnAccountUpdated(const AccountInfo& info) {
   if (info.account_id == account_id_ && info.IsValid()) {
     account_info_ = info;
diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h
index 0027431..871d4bd 100644
--- a/chrome/browser/profiles/profile_downloader.h
+++ b/chrome/browser/profiles/profile_downloader.h
@@ -10,22 +10,25 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/image_decoder.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
-#include "google_apis/gaia/oauth2_token_service.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
+namespace identity {
+class PrimaryAccountAccessTokenFetcher;
+}
 class ProfileDownloaderDelegate;
 
 // Downloads user profile information. The profile picture is decoded in a
 // sandboxed process.
 class ProfileDownloader : public ImageDecoder::ImageRequest,
-                          public OAuth2TokenService::Observer,
-                          public OAuth2TokenService::Consumer,
+                          public identity::IdentityManager::Observer,
                           public AccountTrackerService::Observer {
  public:
   enum PictureStatus {
@@ -92,20 +95,17 @@
   void OnImageDecoded(const SkBitmap& decoded_image) override;
   void OnDecodeImageFailed() override;
 
-  // Overriden from OAuth2TokenService::Observer:
-  void OnRefreshTokenAvailable(const std::string& account_id) override;
-
-  // Overriden from OAuth2TokenService::Consumer:
-  void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
-                         const std::string& access_token,
-                         const base::Time& expiration_time) override;
-  void OnGetTokenFailure(const OAuth2TokenService::Request* request,
-                         const GoogleServiceAuthError& error) override;
-
+  // Overriden from identity::IdentityManager::Observer:
+  void OnRefreshTokenUpdatedForAccount(const AccountInfo& account_info,
+                                       bool is_valid) override;
 
   // Implementation of AccountTrackerService::Observer.
   void OnAccountUpdated(const AccountInfo& info) override;
 
+  // Callback for PrimaryAccountAccessTokenFetcher.
+  void OnAccessTokenFetchComplete(GoogleServiceAuthError error,
+                                  identity::AccessTokenInfo access_token_info);
+
   // Issues the first request to get user profile image.
   void StartFetchingImage();
 
@@ -120,11 +120,15 @@
   std::string account_id_;
   std::string auth_token_;
   std::unique_ptr<network::SimpleURLLoader> simple_loader_;
-  std::unique_ptr<OAuth2TokenService::Request> oauth2_access_token_request_;
+  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
+      oauth2_access_token_fetcher_;
   AccountInfo account_info_;
   SkBitmap profile_picture_;
   PictureStatus picture_status_;
   AccountTrackerService* account_tracker_service_;
+  identity::IdentityManager* identity_manager_;
+  ScopedObserver<identity::IdentityManager, identity::IdentityManager::Observer>
+      identity_manager_observer_;
   bool waiting_for_account_info_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileDownloader);
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index caf28c4ab..042865c 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1513,7 +1513,8 @@
   return std::make_unique<chromeos::device_sync::DeviceSyncService>(
       IdentityManagerFactory::GetForProfile(this),
       gcm::GCMProfileServiceFactory::GetForProfile(this)->driver(),
-      chromeos::GcmDeviceInfoProviderImpl::GetInstance(), GetRequestContext());
+      chromeos::GcmDeviceInfoProviderImpl::GetInstance(),
+      GetURLLoaderFactory());
 }
 
 std::unique_ptr<service_manager::Service>
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index 613499d..a4e9ace 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -25,6 +25,7 @@
 #include "components/services/heap_profiling/public/cpp/settings.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/zlib/zlib.h"
 
 #if defined(OS_WIN)
@@ -86,7 +87,7 @@
   metadata->SetKey(kConfigScenarioName, base::Value("MEMLOG"));
 
   TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
-      g_browser_process->system_request_context());
+      g_browser_process->shared_url_loader_factory());
 
   uploader->DoUpload(file_contents, content::TraceUploader::COMPRESSED_UPLOAD,
                      std::move(metadata),
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
index 28b0f94..41ead96d 100644
--- a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
@@ -6,6 +6,8 @@
 
 #include "base/process/process.h"
 #include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
+#include "chrome/browser/resource_coordinator/page_signal_receiver.h"
+#include "chrome/browser/resource_coordinator/render_process_probe.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/resource_coordinator/public/cpp/process_resource_coordinator.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
@@ -31,3 +33,19 @@
   browser_child_process_watcher_ =
       std::make_unique<resource_coordinator::BrowserChildProcessWatcher>();
 }
+
+void ChromeBrowserMainExtraPartsResourceCoordinator::PreBrowserStart() {
+  if (base::FeatureList::IsEnabled(features::kPerformanceMeasurement)) {
+    DCHECK(resource_coordinator::RenderProcessProbe::IsEnabled());
+    resource_coordinator::PageSignalReceiver* page_signal_receiver =
+        resource_coordinator::PageSignalReceiver::GetInstance();
+
+    DCHECK(resource_coordinator::PageSignalReceiver::IsEnabled());
+    resource_coordinator::RenderProcessProbe* render_process_probe =
+        resource_coordinator::RenderProcessProbe::GetInstance();
+
+    performance_measurement_manager_ =
+        std::make_unique<resource_coordinator::PerformanceMeasurementManager>(
+            page_signal_receiver, render_process_probe);
+  }
+}
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
index b581afd..2e5e8f5 100644
--- a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 #include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
+#include "chrome/browser/resource_coordinator/performance_measurement_manager.h"
 
 namespace resource_coordinator {
 
@@ -26,6 +27,7 @@
   // ChromeBrowserMainExtraParts overrides.
   void ServiceManagerConnectionStarted(
       content::ServiceManagerConnection* connection) override;
+  void PreBrowserStart() override;
 
   std::unique_ptr<resource_coordinator::ProcessResourceCoordinator>
       process_resource_coordinator_;
@@ -33,6 +35,9 @@
   std::unique_ptr<resource_coordinator::BrowserChildProcessWatcher>
       browser_child_process_watcher_;
 
+  std::unique_ptr<resource_coordinator::PerformanceMeasurementManager>
+      performance_measurement_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsResourceCoordinator);
 };
 
diff --git a/chrome/browser/resource_coordinator/render_process_probe.cc b/chrome/browser/resource_coordinator/render_process_probe.cc
index d3dbc751..1a77413 100644
--- a/chrome/browser/resource_coordinator/render_process_probe.cc
+++ b/chrome/browser/resource_coordinator/render_process_probe.cc
@@ -32,8 +32,7 @@
 
 // static
 bool RenderProcessProbe::IsEnabled() {
-  // Check that service_manager is active, GRC is enabled,
-  // and render process CPU profiling is enabled.
+  // Check that service_manager is active and GRC is enabled.
   return content::ServiceManagerConnection::GetForProcess() != nullptr &&
          resource_coordinator::IsResourceCoordinatorEnabled();
 }
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 0db3112e..448b3c66 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -14,7 +14,7 @@
 declare_args() {
   # Whether to compress the main Chromevox javascript files or load the
   # modules individually from source files.
-  chromevox_compress_js = !is_debug
+  chromevox_compress_js = true
 }
 
 closure_library_dir =
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 79e1648..ec6545f 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -1473,7 +1473,8 @@
   });
 });
 
-TEST_F('BackgroundTest', 'NavigationEscapesEdit', function() {
+// Fails consistently (timeout) on linux-chromeos-dbg https://crbug.com/872258
+TEST_F('BackgroundTest', 'DISABLED_NavigationEscapesEdit', function() {
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(function() {/*!
     <p>before content editable</p>
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_bn.xtb b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_bn.xtb
index 364e2a4e..45238678 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_bn.xtb
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_bn.xtb
@@ -156,6 +156,7 @@
 <translation id="2462626033734746142">রেডিও বোতাম গ্রুপ</translation>
 <translation id="2471138580042810658">শিরোনাম ৬</translation>
 <translation id="248982282205370495">{COUNT,plural, =1{তারা}one{#টি তারা}other{#টি তারা}}</translation>
+<translation id="249330843868392562">টেক্সট টু স্পিচ সেটিংস খুলুন</translation>
 <translation id="2523609930580546572">ChromeVox টিউটোরিয়াল</translation>
 <translation id="2525706221823668172">Chromebook এর কীবোর্ড শর্টকাটগুলি</translation>
 <translation id="2549392850788122959"><ph name="KEY" /> আবার সেট হয়েছে৷</translation>
@@ -753,6 +754,7 @@
 <translation id="7241683698754534149">একটি নতুন ট্যাবে দীর্ঘ বিবরণ খুলুন</translation>
 <translation id="7248671827512403053">অ্যাপ্লিকেশান</translation>
 <translation id="725969808843520477">পরবর্তী রেডিও বোতাম</translation>
+<translation id="7261612856573623172">সিস্টেম টেক্সট টু স্পিচ ভয়েস</translation>
 <translation id="7269119382257320590">কোনো যতিচিহ্ন নেই</translation>
 <translation id="7273174640290488576">খালি</translation>
 <translation id="7274770952766771364">নোটের রেফারেন্স</translation>
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_es-419.xtb b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_es-419.xtb
index 3811dc04..0f8ce85 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_es-419.xtb
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_es-419.xtb
@@ -156,6 +156,7 @@
 <translation id="2462626033734746142">Grupo de botones de selección</translation>
 <translation id="2471138580042810658">Encabezado 6</translation>
 <translation id="248982282205370495">{COUNT,plural, =1{asterisco}other{# asteriscos}}</translation>
+<translation id="249330843868392562">Abrir la configuración de texto a voz</translation>
 <translation id="2523609930580546572">Instructivo de ChromeVox</translation>
 <translation id="2525706221823668172">Combinaciones de teclas para Chromebook</translation>
 <translation id="2549392850788122959">Se restableció <ph name="KEY" />.</translation>
@@ -753,6 +754,7 @@
 <translation id="7241683698754534149">Abrir la descripción larga en una pestaña nueva</translation>
 <translation id="7248671827512403053">Aplicación</translation>
 <translation id="725969808843520477">Siguiente botón de selección</translation>
+<translation id="7261612856573623172">Voz en la función de texto a voz del sistema</translation>
 <translation id="7269119382257320590">Sin puntuación</translation>
 <translation id="7273174640290488576">En blanco</translation>
 <translation id="7274770952766771364">Nota de referencia</translation>
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_te.xtb b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_te.xtb
index 861587e..5632a35 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_te.xtb
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_te.xtb
@@ -156,6 +156,7 @@
 <translation id="2462626033734746142">రేడియో బటన్ సమూహం</translation>
 <translation id="2471138580042810658">శీర్షిక 6</translation>
 <translation id="248982282205370495">{COUNT,plural, =1{నక్షత్రం గుర్తు}other{# నక్షత్రం గుర్తులు}}</translation>
+<translation id="249330843868392562">వచనం నుండి ప్రసంగం సెట్టింగ్‌లను తెరువు</translation>
 <translation id="2523609930580546572">ChromeVox ట్యుటోరియల్</translation>
 <translation id="2525706221823668172">Chromebook కీబోర్డ్ సత్వరమార్గాలు</translation>
 <translation id="2549392850788122959"><ph name="KEY" /> రీసెట్ చేయబడింది.</translation>
@@ -753,6 +754,7 @@
 <translation id="7241683698754534149">పెద్ద వివరణను కొత్త ట్యాబ్‌లో తెరవండి</translation>
 <translation id="7248671827512403053">అనువర్తనం</translation>
 <translation id="725969808843520477">తదుపరి రేడియో బటన్</translation>
+<translation id="7261612856573623172">వచనం నుండి ప్రసంగం సిస్టమ్ వాయిస్</translation>
 <translation id="7269119382257320590">విరామచిహ్నాలు లేవు</translation>
 <translation id="7273174640290488576">ఖాళీ</translation>
 <translation id="7274770952766771364">గమనిక సూచన</translation>
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_zh-CN.xtb b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_zh-CN.xtb
index 3196dc66..061c517b 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_zh-CN.xtb
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings_zh-CN.xtb
@@ -155,6 +155,7 @@
 <translation id="2462626033734746142">单选按钮组</translation>
 <translation id="2471138580042810658">6级标题标记</translation>
 <translation id="248982282205370495">{COUNT,plural, =1{1个星号}other{#个星号}}</translation>
+<translation id="249330843868392562">打开文字转语音设置</translation>
 <translation id="2523609930580546572">ChromeVox 教程</translation>
 <translation id="2525706221823668172">Chromebook 键盘快捷键</translation>
 <translation id="2549392850788122959">已重置“<ph name="KEY" />”。</translation>
@@ -752,6 +753,7 @@
 <translation id="7241683698754534149">在新标签页中打开详细说明</translation>
 <translation id="7248671827512403053">应用</translation>
 <translation id="725969808843520477">下一个单选按钮</translation>
+<translation id="7261612856573623172">系统默认文字转语音声音</translation>
 <translation id="7269119382257320590">不读出任何标点符号</translation>
 <translation id="7273174640290488576">空白</translation>
 <translation id="7274770952766771364">备注参考资料</translation>
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.html b/chrome/browser/resources/chromeos/login/sync_consent.html
index f25c51a6..becd6ce2 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.html
+++ b/chrome/browser/resources/chromeos/login/sync_consent.html
@@ -19,7 +19,7 @@
       <hd-iron-icon slot="oobe-icon"
           icon1x="sync-consent-32:googleg" icon2x="sync-consent-64:googleg">
       </hd-iron-icon>
-      <h1 slot="title">
+      <h1 slot="title" consent-description>
         [[i18nDynamic(locale, 'syncConsentScreenTitle')]]
       </h1>
       <div slot="footer" class="layout vertical">
@@ -30,10 +30,10 @@
           </img>
           <div class="overview-list-item-text flex layout vertical
               center-justified">
-            <div class="overview-list-item-title">
+            <div class="overview-list-item-title" consent-description>
               [[i18nDynamic(locale, 'syncConsentScreenChromeSyncName')]]
             </div>
-            <div class="overview-list-item-description">
+            <div class="overview-list-item-description" consent-description>
               [[i18nDynamic(locale, 'syncConsentScreenChromeSyncDescription')]]
             </div>
           </div>
@@ -44,22 +44,24 @@
           </hd-iron-icon>
           <div class="overview-list-item-text flex layout vertical
               center-justified">
-            <div class="overview-list-item-title">
+            <div class="overview-list-item-title" consent-description>
               [[i18nDynamic(locale, 'syncConsentScreenPersonalizeGoogleServicesName')]]
             </div>
-            <div class="overview-list-item-description">
+            <div class="overview-list-item-description" consent-description>
               [[i18nDynamic(locale, 'syncConsentScreenPersonalizeGoogleServicesDescription')]]
             </div>
           </div>
         </div>
-        <cr-checkbox id="reviewSettingsBox">
+        <cr-checkbox id="reviewSettingsBox" consent-description>
           [[i18nDynamic(locale, 'syncConsentReviewSyncOptionsText')]]
         </cr-checkbox>
       </div>
       <div slot="bottom-buttons" class="layout horizontal end-justified">
-        <oobe-text-button
+        <oobe-text-button id="settingsSaveAndContinueButton"
             on-tap="onSettingsSaveAndContinue_" class="focus-on-show" inverse>
-          <div>[[i18nDynamic(locale, 'syncConsentAcceptAndContinue')]]</div>
+          <div consent-description consent-confirmation>
+            [[i18nDynamic(locale, 'syncConsentAcceptAndContinue')]]
+          </div>
         </oobe-text-button>
       </div>
     </oobe-dialog>
@@ -70,7 +72,7 @@
                    chrome://oobe/logo_24px-2x.svg 2x"
           slot="oobe-icon">
       </img>
-      <h1 slot="title">
+      <h1 slot="title" consent-description>
         [[i18nDynamic(locale, 'syncConsentNewScreenTitle')]]
       </h1>
       <div slot="footer" class="layout vertical">
@@ -79,7 +81,7 @@
             icon1x="sync-consent-24:sync_ic" icon2x="sync-consent-48:sync_ic">
           </hd-iron-icon>
           <div class="sync-feature-item-text flex layout vertical
-              center-justified">
+              center-justified" consent-description>
             [[i18nDynamic(locale, 'syncConsentNewBookmarksDesc')]]
           </div>
         </div>
@@ -89,7 +91,7 @@
               icon2x="sync-consent-48:assistant_ic">
           </hd-iron-icon>
           <div class="sync-feature-item-text flex layout vertical
-              center-justified">
+              center-justified" consent-description>
             [[i18nDynamic(locale, 'syncConsentNewServicesDesc')]]
           </div>
         </div>
@@ -99,7 +101,7 @@
               icon2x="sync-consent-48:googleg_ic">
           </hd-iron-icon>
           <div class="sync-feature-item-text flex layout vertical
-              center-justified">
+              center-justified" consent-description>
             [[i18nDynamic(locale, 'syncConsentNewImproveChrome')]]
           </div>
         </div>
@@ -110,7 +112,7 @@
               icon2x="sync-consent-48:settings_ic">
           </hd-iron-icon>
           <div class="sync-feature-item-text flex layout vertical
-              center-justified">
+              center-justified" consent-description>
             [[i18nDynamic(locale, 'syncConsentNewGoogleMayUse')]]
           </div>
         </div>
@@ -120,11 +122,15 @@
         <oobe-welcome-secondary-button id="moreOptionsButton"
             on-tap="onMoreOptionsButton_"
             label-for-aria$="[[i18nDynamic(locale, 'syncConsentNewMoreOptions')]]">
-          <div>[[i18nDynamic(locale, 'syncConsentNewMoreOptions')]]</div>
+          <div consent-description>
+            [[i18nDynamic(locale, 'syncConsentNewMoreOptions')]]
+          </div>
         </oobe-welcome-secondary-button>
         <oobe-text-button id="yesIAmInButton"
           on-tap="onYesIAmInButton_" class="focus-on-show" inverse>
-          <div>[[i18nDynamic(locale, 'syncConsentNewYesIAmIn')]]</div>
+          <div consent-description consent-confirmation>
+            [[i18nDynamic(locale, 'syncConsentNewYesIAmIn')]]
+          </div>
         </oobe-text-button>
       </div>
     </oobe-dialog>
@@ -135,52 +141,55 @@
                    chrome://oobe/logo_24px-2x.svg 2x"
           slot="oobe-icon">
       </img>
-      <h1 slot="title">
+      <h1 slot="title" consent-description>
         [[i18nDynamic(locale, 'syncConsentNewSyncOptions')]]
       </h1>
       <div slot="subtitle">
-        <div>
+        <div consent-description>
           [[i18nDynamic(locale, 'syncConsentNewSyncOptionsSubtitle')]]
         </div>
-        <div>
+        <div consent-description>
           [[i18nDynamic(locale, 'syncConsentNewChooseOption')]]
         </div>
       </div>
       <div slot="footer" class="layout vertical">
         <paper-radio-group id="optionsGroup" selected="reviewOptions"
             on-paper-radio-group-changed="onOptionsSelectionChanged_">
-          <paper-radio-button name="reviewOptions" class="focus-on-show"
-              class="options-list-item flex layout horizontal center">
+          <paper-radio-button name="reviewOptions"
+              class="options-list-item flex layout horizontal center
+                  focus-on-show" consent-option>
             <div class="options-list-item-text flex layout vertical
                 center-justified">
-                <div class="sync-option-title">
+                <div class="sync-option-title" consent-description>
                   [[i18nDynamic(locale, 'syncConsentNewOptionReview')]]
                 </div>
-                <div class="sync-option-subtitle">
+                <div class="sync-option-subtitle" consent-description>
                   [[i18nDynamic(locale, 'syncConsentNewOptionReviewDsc')]]
                 </div>
             </div>
           </paper-radio-button>
           <paper-radio-button name="justSync" name="justSync"
-              class="options-list-item flex layout horizontal center">
+              class="options-list-item flex layout horizontal center"
+              consent-option>
             <div class="options-list-item-text flex layout vertical
                 center-justified">
-                <div class="sync-option-title">
+                <div class="sync-option-title" consent-description>
                   [[i18nDynamic(locale, 'syncConsentNewOptionJustSync')]]
                 </div>
-                <div class="sync-option-subtitle">
+                <div class="sync-option-subtitle" consent-description>
                   [[i18nDynamic(locale, 'syncConsentNewOptionJustSyncDsc')]]
                 </div>
             </div>
           </paper-radio-button>
           <paper-radio-button name="syncAndPersonalization"
-              class="options-list-item flex layout horizontal center">
+              class="options-list-item flex layout horizontal center"
+              consent-option>
             <div class="options-list-item-text flex layout vertical
                 center-justified">
-                <div class="sync-option-title">
+                <div class="sync-option-title" consent-description>
                   [[i18nDynamic(locale, 'syncConsentNewOptionSyncAndPersonalization')]]
                 </div>
-                <div class="sync-option-subtitle">
+                <div class="sync-option-subtitle" consent-description>
                   [[i18nDynamic(locale, 'syncConsentNewOptionSyncAndPersonalizationDsc')]]
                 </div>
             </div>
@@ -190,7 +199,9 @@
       <div slot="bottom-buttons" class="layout horizontal end-justified">
         <oobe-text-button
             on-tap="onOptionsAcceptAndContinue_" inverse>
-          <div>[[i18nDynamic(locale, 'syncConsentAcceptAndContinue')]]</div>
+          <div consent-description consent-confirmation>
+            [[i18nDynamic(locale, 'syncConsentAcceptAndContinue')]]
+          </div>
         </oobe-text-button>
       </div>
     </oobe-dialog>
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.js b/chrome/browser/resources/chromeos/login/sync_consent.js
index 0d1ca48..9728568 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.js
+++ b/chrome/browser/resources/chromeos/login/sync_consent.js
@@ -79,15 +79,58 @@
    * This is 'on-tap' event handler for 'AcceptAndContinue' button.
    * @private
    */
-  onSettingsSaveAndContinue_: function() {
+  onSettingsSaveAndContinue_: function(e) {
     if (this.$.reviewSettingsBox.checked) {
-      chrome.send('login.SyncConsentScreen.userActed', ['continue-and-review']);
+      chrome.send('login.SyncConsentScreen.continueAndReview', [
+        this.getConsentDescription_(), this.getConsentConfirmation_(e.path)
+      ]);
     } else {
-      chrome.send(
-          'login.SyncConsentScreen.userActed', ['continue-with-defaults']);
+      chrome.send('login.SyncConsentScreen.continueWithDefaults', [
+        this.getConsentDescription_(), this.getConsentConfirmation_(e.path)
+      ]);
     }
   },
 
+  /**
+   * @param {!Array<!HTMLElement>} path Path of the click event. Must contain
+   *     a consent confirmation element.
+   * @return {string} The text of the consent confirmation element.
+   * @private
+   */
+  getConsentConfirmation_: function(path) {
+    for (let element of path) {
+      if (!element.hasAttribute)
+        continue;
+
+      if (element.hasAttribute('consent-confirmation'))
+        return element.innerHTML.trim();
+
+      // Search down in case of click on a button with description below.
+      let labels = element.querySelectorAll('[consent-confirmation]');
+      if (labels && labels.length > 0) {
+        assert(labels.length == 1);
+
+        let result = '';
+        for (let label of labels) {
+          result += label.innerHTML.trim();
+        }
+        return result;
+      }
+    }
+    assertNotReached('No consent confirmation element found.');
+    return '';
+  },
+
+  /** @return {!Array<string>} Text of the consent description elements. */
+  getConsentDescription_: function() {
+    let consentDescription =
+        Array.from(this.shadowRoot.querySelectorAll('[consent-description]'))
+            .filter(element => element.clientWidth * element.clientHeight > 0)
+            .map(element => element.innerHTML.trim());
+    assert(consentDescription);
+    return consentDescription;
+  },
+
   /******************************************************
    * Get Google smarts in Chrome dialog.
    ******************************************************/
diff --git a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_bn.xtb b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_bn.xtb
index 7e04bb2..0c52b01 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_bn.xtb
+++ b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_bn.xtb
@@ -1,7 +1,10 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="bn">
+<translation id="111880247472081232">আপনার নির্বাচন-টু-স্পিক টেক্সট-টু-স্পিচ সেটিংস গ্লোবাল টেক্সট-টু-স্পিচ সেটিংসে স্থানান্তরিত হয়েছে।</translation>
 <translation id="1197088940767939838">কমলা</translation>
+<translation id="1273314450961659276">টেক্সট টু স্পিচ সেটিংস</translation>
+<translation id="1498542103351704084">নির্বাচন-টু-স্পিক স্পিচ সেটিংস আপডেট করা হয়েছে</translation>
 <translation id="1555130319947370107">নীল</translation>
 <translation id="1666326070478924810">'বাছুন ও শুনুন'-এর সেটিংস</translation>
 <translation id="1966649499058910679">প্রতিটি শব্দ যেভাবে উচ্চারণ করা হয় সেইভাবে হাইলাইট করুন</translation>
@@ -9,11 +12,14 @@
 <translation id="2714180132046334502">গাঢ় ব্যাকগ্রাউন্ড</translation>
 <translation id="27349076983469322">হালকা ব্যাকগ্রাউন্ড</translation>
 <translation id="335581015389089642">স্পিচ</translation>
+<translation id="3784184786832188702">নির্বাচন-টু-স্পিক এখন গ্লোবাল টেক্সট টু স্পিচ সেটিংস ব্যবহার করে।</translation>
 <translation id="5901630391730855834">হলুদ</translation>
 <translation id="6017514345406065928">সবুজ</translation>
 <translation id="6475604559827479857">শব্দ হাইলাইট করার জন্য রং:</translation>
 <translation id="6837853484260746864">একটি ভয়েস বেছে নিন:</translation>
+<translation id="7261612856573623172">সিস্টেম টেক্সট টু স্পিচ ভয়েস</translation>
 <translation id="7768784765476638775">বাছুন ও শুনুন</translation>
 <translation id="7914870167134465181">হাইলাইট করা</translation>
+<translation id="8324974933005349667">টেক্সট টু স্পিচ সেটিংস ব্যক্তিগতকৃত করুন</translation>
 <translation id="992256792861109788">গোলাপী</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_es-419.xtb b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_es-419.xtb
index 5e51349..b9cb16c 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_es-419.xtb
+++ b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_es-419.xtb
@@ -1,7 +1,10 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="es-419">
+<translation id="111880247472081232">Tus opciones de configuración de Seleccionar para pronunciar texto a voz migraron a la configuración de texto a voz.</translation>
 <translation id="1197088940767939838">Naranja</translation>
+<translation id="1273314450961659276">Configuración de texto a voz</translation>
+<translation id="1498542103351704084">Se actualizó la configuración de Seleccionar para pronunciar</translation>
 <translation id="1555130319947370107">Azul</translation>
 <translation id="1666326070478924810">Configuración de Seleccionar para pronunciar</translation>
 <translation id="1966649499058910679">Destaca cada palabra a medida que se pronuncia</translation>
@@ -9,11 +12,14 @@
 <translation id="2714180132046334502">Fondo oscuro</translation>
 <translation id="27349076983469322">Fondo claro</translation>
 <translation id="335581015389089642">Voz</translation>
+<translation id="3784184786832188702">Seleccionar para pronunciar ahora usa la configuración global de texto a voz.</translation>
 <translation id="5901630391730855834">Amarillo</translation>
 <translation id="6017514345406065928">Verde</translation>
 <translation id="6475604559827479857">Color para destacar palabras:</translation>
 <translation id="6837853484260746864">Seleccionar una voz:</translation>
+<translation id="7261612856573623172">Voz en la función de texto a voz del sistema</translation>
 <translation id="7768784765476638775">Seleccionar para pronunciar</translation>
 <translation id="7914870167134465181">Destacar</translation>
+<translation id="8324974933005349667">Personalizar la configuración de texto a voz</translation>
 <translation id="992256792861109788">Rosa</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_te.xtb b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_te.xtb
index 3880841..0690ca8a 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_te.xtb
+++ b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_te.xtb
@@ -1,7 +1,10 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="te">
+<translation id="111880247472081232">మీ వినడానికి ఎంచుకోండి వచనం నుండి ప్రసంగం సెట్టింగ్‌లు అంతర్జాతీయ వచనం నుండి ప్రసంగం సెట్టింగ్‌లకు తరలించబడ్డాయి.</translation>
 <translation id="1197088940767939838">నారింజ రంగు</translation>
+<translation id="1273314450961659276">వచనం నుండి ప్రసంగం సెట్టింగ్‌లు</translation>
+<translation id="1498542103351704084">వినడానికి ఎంచుకోండి ప్రసంగం సెట్టింగ్‌లు అప్‌డేట్ చేయబడ్డాయి</translation>
 <translation id="1555130319947370107">నీలం</translation>
 <translation id="1666326070478924810">వినడానికి-ఎంచుకోండి సెట్టింగ్‌లు</translation>
 <translation id="1966649499058910679">ప్రతి పదాన్ని చదివినప్పుడు దానిని హైలైట్ చేయి</translation>
@@ -9,11 +12,14 @@
 <translation id="2714180132046334502">ముదురు నేపథ్యం</translation>
 <translation id="27349076983469322">తేలికపాటి నేపథ్యం</translation>
 <translation id="335581015389089642">ప్రసంగం</translation>
+<translation id="3784184786832188702">వినడానికి ఎంచుకోండి ఇప్పుడు అంతర్జాతీయ వచనం నుండి ప్రసంగం సెట్టింగ్‌లను ఉపయోగిస్తుంది.</translation>
 <translation id="5901630391730855834">పసుపు</translation>
 <translation id="6017514345406065928">ఆకుపచ్చ</translation>
 <translation id="6475604559827479857">పదం హైలైట్‌ల కోసం రంగు:</translation>
 <translation id="6837853484260746864">వాయిస్‌ని ఎంచుకోండి:</translation>
+<translation id="7261612856573623172">వచనం నుండి ప్రసంగం సిస్టమ్ వాయిస్</translation>
 <translation id="7768784765476638775">వినడానికి ఎంచుకోండి</translation>
 <translation id="7914870167134465181">హైలైటింగ్</translation>
+<translation id="8324974933005349667">వచనం నుండి ప్రసంగం సెట్టింగ్‌లను వ్యక్తిగతీకరించండి</translation>
 <translation id="992256792861109788">గులాబి రంగు</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_zh-CN.xtb b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_zh-CN.xtb
index 43dc7bf..cedc977 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_zh-CN.xtb
+++ b/chrome/browser/resources/chromeos/select_to_speak/strings/select_to_speak_strings_zh-CN.xtb
@@ -1,7 +1,10 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-CN">
+<translation id="111880247472081232">您的随选朗读文字转语音设置已迁移至全局文字转语音设置。</translation>
 <translation id="1197088940767939838">橙色</translation>
+<translation id="1273314450961659276">文字转语音设置</translation>
+<translation id="1498542103351704084">随选朗读语音设置已更新</translation>
 <translation id="1555130319947370107">蓝色</translation>
 <translation id="1666326070478924810">“随选朗读”设置</translation>
 <translation id="1966649499058910679">突出显示每个正被读出的字词</translation>
@@ -9,11 +12,14 @@
 <translation id="2714180132046334502">深色背景</translation>
 <translation id="27349076983469322">浅色背景</translation>
 <translation id="335581015389089642">语音</translation>
+<translation id="3784184786832188702">随选朗读功能现在使用全局文字转语音设置。</translation>
 <translation id="5901630391730855834">黄色</translation>
 <translation id="6017514345406065928">绿色</translation>
 <translation id="6475604559827479857">字词的突出显示颜色:</translation>
 <translation id="6837853484260746864">请选择一种声音:</translation>
+<translation id="7261612856573623172">系统默认文字转语音声音</translation>
 <translation id="7768784765476638775">随选朗读</translation>
 <translation id="7914870167134465181">突出显示</translation>
+<translation id="8324974933005349667">个性化文字转语音设置</translation>
 <translation id="992256792861109788">粉色</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
index f619a1c..71cb81c 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
@@ -448,7 +448,7 @@
 .v2 #categories-list > li > div {
   color: rgb(95, 99, 104);
   font-family: 'Roboto';
-  font-size: 13px;
+  font-size: 12px;
   font-weight: 500;
   padding: 0 30px;
 }
@@ -464,7 +464,6 @@
 
 .v2 #categories-list > li[selected] > div {
   color: rgb(26, 115, 232);
-  font-weight: 700;
 }
 
 .v2 #surprise-me {
@@ -521,6 +520,7 @@
   border-radius: 4px;
   box-shadow: 0 4px 8px rgba(32, 33, 36, 0.17);
   transform: scale(0.8);
+  transition: transform 240ms;
 }
 
 .v2 .image-picker .check {
@@ -600,7 +600,7 @@
 }
 
 .v2 .top-header-contents > div:not(.divider) {
-  padding-top: 15px;
+  padding-top: 16px;
 }
 
 .v2 .top-header-contents #cancel-preview-wallpaper {
@@ -609,7 +609,7 @@
   background-size: 20px 20px;
   height: 4px;
   margin-inline-start: 16px;
-  margin-top: 12px;
+  margin-top: 13px;
   padding-inline-start: 32px;
 }
 
@@ -828,6 +828,10 @@
   -webkit-filter: grayscale(1);
 }
 
+.v2 .image-picker-offline img:not([offline]) {
+  opacity: 0.5;
+}
+
 .v2 .daily-refresh-slider::before {
   background-color: #fff;
   border-radius: 50%;
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
index ae830e0..e0e28b6 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
@@ -389,9 +389,6 @@
             'focus', function() {
               chrome.wallpaperPrivate.minimizeInactiveWindows();
             });
-        window.onMinimized.addListener(function() {
-          chrome.wallpaperPrivate.restoreMinimizedWindows();
-        });
       }
       WallpaperUtil.testSendMessage('wallpaper-window-created');
     });
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
index 11cd393..1e9cc39b 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
@@ -642,6 +642,14 @@
     },
 
     /**
+     * The opacity that the slideshow images should have.
+     * @type {number} opacity The desired opacity.
+     */
+    get slideShowImageOpacity() {
+      return this.classList.contains('image-picker-offline') ? 0.5 : 1;
+    },
+
+    /**
      * The selected item.
      * @type {!Object} Wallpaper information inserted into the data model.
      */
@@ -724,7 +732,7 @@
       }
 
       slideShowImage.style.opacity =
-          this.dailyRefreshImages.length == 0 ? 1 : 0;
+          this.dailyRefreshImages.length == 0 ? this.slideShowImageOpacity : 0;
       slideShowImage.classList.add('slide-show');
       this.dailyRefreshItem.insertBefore(
           slideShowImage, this.dailyRefreshItem.firstChild);
@@ -741,7 +749,7 @@
       if (images.length <= index)
         return;
       for (var i = 0; i < images.length; ++i) {
-        images[i].style.opacity = i === index ? 1 : 0;
+        images[i].style.opacity = i === index ? this.slideShowImageOpacity : 0;
       }
       var nextIndex = (index + 1) % images.length;
       this.dailyRefreshTimer_ =
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/main.html b/chrome/browser/resources/chromeos/wallpaper_manager/main.html
index 1f1c0204..34b6dfb 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/main.html
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/main.html
@@ -188,7 +188,7 @@
       </div>
     </div>
   </div>
-  <div id="message-container"></div>
+  <div id="message-container" i18n-content="connectionFailed"></div>
   <div id="preview-canvas"></div>
   <div id="preview-spinner" hidden></div>
   <div id="daily-refresh-banner-template" hidden>
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.css b/chrome/browser/resources/local_ntp/custom_links_edit.css
index 83d0b42..ed12b1a 100644
--- a/chrome/browser/resources/local_ntp/custom_links_edit.css
+++ b/chrome/browser/resources/local_ntp/custom_links_edit.css
@@ -6,6 +6,10 @@
   overflow: hidden;
 }
 
+.mouse-navigation {
+  outline: none;
+}
+
 #edit-link-dialog {
   background-color: #fff;
   border: none;
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.js b/chrome/browser/resources/local_ntp/custom_links_edit.js
index 1f0e8124..b205a955a 100644
--- a/chrome/browser/resources/local_ntp/custom_links_edit.js
+++ b/chrome/browser/resources/local_ntp/custom_links_edit.js
@@ -54,6 +54,7 @@
 const KEYCODES = {
   ENTER: 13,
   ESC: 27,
+  TAB: 9,
 };
 
 
@@ -105,6 +106,13 @@
 
 
 /**
+ * True if keyboard navigation should start at the first input field.
+ * @type {boolean}
+ */
+let startKeyboardAtFirstField = false;
+
+
+/**
  * True if the provided url is valid.
  * @type {string}
  */
@@ -137,8 +145,8 @@
   $(IDS.URL_FIELD).classList.add(CLASSES.TEXT_MODIFIED);
 
   // Set accessibility names.
-  $(IDS.DELETE).name = deleteLinkTitle + ' ' + data.title;
-  $(IDS.DONE).name = editLinkTitle + ' ' + data.title;
+  $(IDS.DELETE).setAttribute('aria-label', deleteLinkTitle + ' ' + data.title);
+  $(IDS.DONE).setAttribute('aria-label', editLinkTitle + ' ' + data.title);
   $(IDS.DONE).title = editLinkTitle;
 }
 
@@ -224,6 +232,7 @@
     prepopulatedLink.rid = -1;
     prepopulatedLink.title = '';
     prepopulatedLink.url = '';
+    startKeyboardAtFirstField = false;
   }, 10);
 }
 
@@ -236,15 +245,19 @@
   let cmd = event.data.cmd;
   let args = event.data;
   if (cmd === 'linkData') {
+    startKeyboardAtFirstField = true;
     if (args.tid) {  // We are editing a link, prepopulate the link data.
+      document.title = editLinkTitle;
       $(IDS.DIALOG_TITLE).textContent = editLinkTitle;
       prepopulateFields(args.tid);
     } else {  // We are adding a link, disable the delete button.
+      document.title = addLinkTitle;
       $(IDS.DIALOG_TITLE).textContent = addLinkTitle;
       $(IDS.DELETE).disabled = true;
       disableSubmitUntilTextInput();
       // Set accessibility names.
-      $(IDS.DONE).name = $(IDS.DONE).title = addLinkTitle;
+      $(IDS.DONE).setAttribute('aria-label', addLinkTitle);
+      $(IDS.DONE).title = addLinkTitle;
     }
   }
 }
@@ -256,12 +269,9 @@
  */
 function disableOutlineOnMouseClick(element) {
   element.addEventListener('mousedown', (event) => {
-    element.style.outline = 'none';
+    element.classList.add('mouse-navigation');
     let resetOutline = (event) => {
-      // Clear current focus to prevent the outline from reappearing when the
-      // user switches windows.
-      document.activeElement.blur();
-      element.style.outline = '';
+      element.classList.remove('mouse-navigation');
       element.removeEventListener('blur', resetOutline);
     };
     element.addEventListener('blur', resetOutline);
@@ -283,6 +293,8 @@
     queryArgs[decodeURIComponent(val[0])] = decodeURIComponent(val[1]);
   }
 
+  document.title = queryArgs['editTitle'];
+
   // Enable RTL.
   // TODO(851293): Add RTL formatting.
   if (queryArgs['rtl'] == '1') {
@@ -296,16 +308,29 @@
   deleteLinkTitle = queryArgs['linkRemove'];
   $(IDS.DIALOG_TITLE).textContent = addLinkTitle;
   $(IDS.TITLE_FIELD_NAME).textContent = queryArgs['nameField'];
-  $(IDS.TITLE_FIELD_NAME).name = queryArgs['nameField'];
+  $(IDS.TITLE_FIELD_NAME).setAttribute('aria-label', queryArgs['nameField']);
   $(IDS.URL_FIELD_NAME).textContent = queryArgs['urlField'];
-  $(IDS.URL_FIELD_NAME).name = queryArgs['urlField'];
+  $(IDS.URL_FIELD_NAME).setAttribute('aria-label', queryArgs['urlField']);
   $(IDS.DELETE).textContent = $(IDS.DELETE).title = queryArgs['linkRemove'];
-  $(IDS.CANCEL).textContent = $(IDS.CANCEL).title = $(IDS.CANCEL).name =
-      queryArgs['linkCancel'];
+  $(IDS.CANCEL).textContent = $(IDS.CANCEL).title = queryArgs['linkCancel'];
+  $(IDS.CANCEL).setAttribute('aria-label', queryArgs['linkCancel']);
   $(IDS.DONE).textContent = $(IDS.DONE).title = queryArgs['linkDone'];
   $(IDS.INVALID_URL).textContent = queryArgs['invalidUrl'];
 
   // Set up event listeners.
+  document.body.onkeydown = (event) => {
+    if (event.keyCode === KEYCODES.ESC) {
+      // Close the iframe instead of just this dialog.
+      event.preventDefault();
+      closeDialog();
+    } else if (event.keyCode === KEYCODES.TAB && startKeyboardAtFirstField) {
+      // Start keyboard navigation at the first input field when the dialog
+      // opens.
+      event.preventDefault();
+      $(IDS.TITLE_FIELD).focus();
+      startKeyboardAtFirstField = false;
+    }
+  };
   $(IDS.URL_FIELD).addEventListener('input', (event) => {
     if (!$(IDS.URL_FIELD).classList.contains(CLASSES.TEXT_MODIFIED))
       $(IDS.URL_FIELD).classList.add(CLASSES.TEXT_MODIFIED);
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 5c96cc1d..a56f39b 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -84,6 +84,10 @@
   padding: 0;
 }
 
+.mouse-navigation {
+  outline: none;
+}
+
 #ntp-contents {
   display: flex;
   flex-direction: column;
@@ -700,9 +704,11 @@
 
 #one-google {
   position: absolute;
-  right: 0;
   top: 0;
   transition: opacity 130ms;
+  /* One Google Bar can automatically align to left and right
+    based on the profile language preference */
+  width: 100%;
 }
 
 #one-google.hidden {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index b913eef..9768fc6 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -18,6 +18,7 @@
       {{LOCAL_NTP_INTEGRITY}}></script>
   <meta charset="utf-8">
   <meta name="google" value="notranslate">
+  <meta name="referrer" content="strict-origin">
 </head>
 <!-- Remember to update the test HTML files in chrome/test/data/local_ntp/
    whenever making changes to this file.-->
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index e17edfe..2ae9ce02 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -911,12 +911,9 @@
  */
 function disableOutlineOnMouseClick(element) {
   element.addEventListener('mousedown', (event) => {
-    element.style.outline = 'none';
+    element.classList.add('mouse-navigation');
     let resetOutline = (event) => {
-      // Clear current focus to prevent the outline from reappearing when the
-      // user switches windows.
-      document.activeElement.blur();
-      element.style.outline = '';
+      element.classList.remove('mouse-navigation');
       element.removeEventListener('blur', resetOutline);
     };
     element.addEventListener('blur', resetOutline);
@@ -956,7 +953,9 @@
   registerKeyHandler(restoreAllLink, KEYCODE.ENTER, onRestoreAll);
   registerKeyHandler(restoreAllLink, KEYCODE.SPACE, onRestoreAll);
   restoreAllLink.textContent =
-      configData.translatedStrings.restoreThumbnailsShort;
+      (configData.isCustomLinksEnabled ?
+           configData.translatedStrings.restoreDefaultLinks :
+           configData.translatedStrings.restoreThumbnailsShort);
 
   $(IDS.ATTRIBUTION_TEXT).textContent =
       configData.translatedStrings.attributionIntro;
@@ -1114,6 +1113,9 @@
   if (NTP_DESIGN.numTitleLines > 1)
     args.push('ntl=' + NTP_DESIGN.numTitleLines);
 
+  args.push(
+      'title=' +
+      encodeURIComponent(configData.translatedStrings.mostVisitedTitle));
   args.push('removeTooltip=' +
       encodeURIComponent(configData.translatedStrings.removeThumbnailTooltip));
 
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 7375b7d..6ab3fa9 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -375,6 +375,10 @@
   display: none;
 }
 
+.mouse-navigation {
+  outline: none;
+}
+
 .md-tile-container {
   border-radius: 4px;
   box-sizing: border-box;
@@ -522,7 +526,8 @@
   width: var(--md-menu-size);
 }
 
-.md-menu:focus {
+.md-menu:active,
+.md-menu:focus:not(.mouse-navigation) {
   opacity: 1;
 }
 
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index f48dda0a..4100061 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -36,9 +36,9 @@
   MD_ADD_BACKGROUND: 'md-add-background',
   MD_MENU: 'md-menu',
   MD_EDIT_MENU: 'md-edit-menu',
-  MD_TILE: 'md-tile-container',
+  MD_TILE: 'md-tile',
+  MD_TILE_CONTAINER: 'md-tile-container',
   MD_TILE_INNER: 'md-tile-inner',
-  MD_TILE_LINK: 'md-tile',
   MD_TITLE: 'md-title',
   MD_TITLE_CONTAINER: 'md-title-container',
 };
@@ -426,15 +426,20 @@
  * @param {Element} tile DOM node of the tile we want to remove.
  */
 var blacklistTile = function(tile) {
-  tile.classList.add('blacklisted');
-  tile.addEventListener('transitionend', function(ev) {
-    if (ev.propertyName != 'width')
-      return;
+  let tid = isMDEnabled ? Number(tile.firstChild.getAttribute('data-tid')) :
+                          Number(tile.getAttribute('data-tid'));
 
-    window.parent.postMessage(
-        {cmd: 'tileBlacklisted', tid: Number(tile.getAttribute('data-tid'))},
-        DOMAIN_ORIGIN);
-  });
+  if (isCustomLinksEnabled) {
+    chrome.embeddedSearch.newTabPage.deleteMostVisitedItem(tid);
+  } else {
+    tile.classList.add('blacklisted');
+    tile.addEventListener('transitionend', function(ev) {
+      if (ev.propertyName != 'width')
+        return;
+      window.parent.postMessage(
+          {cmd: 'tileBlacklisted', tid: Number(tid)}, DOMAIN_ORIGIN);
+    });
+  }
 };
 
 
@@ -464,12 +469,9 @@
  */
 function disableOutlineOnMouseClick(element) {
   element.addEventListener('mousedown', (event) => {
-    element.style.outline = 'none';
+    element.classList.add('mouse-navigation');
     let resetOutline = (event) => {
-      // Clear current focus to prevent the outline from reappearing when the
-      // user switches windows.
-      document.activeElement.blur();
-      element.style.outline = '';
+      element.classList.remove('mouse-navigation');
       element.removeEventListener('blur', resetOutline);
     };
     element.addEventListener('blur', resetOutline);
@@ -652,14 +654,14 @@
  * @return {Element}
  */
 function renderMaterialDesignTile(data) {
-  let mdTile = document.createElement('div');
-  mdTile.role = 'none';
+  let mdTileContainer = document.createElement('div');
+  mdTileContainer.role = 'none';
 
   if (data == null) {
-    mdTile.className = CLASSES.MD_EMPTY_TILE;
-    return mdTile;
+    mdTileContainer.className = CLASSES.MD_EMPTY_TILE;
+    return mdTileContainer;
   }
-  mdTile.className = CLASSES.MD_TILE;
+  mdTileContainer.className = CLASSES.MD_TILE_CONTAINER;
 
   if (data.isCustomLink)
     tilesAreCustomLinks = true;
@@ -669,18 +671,18 @@
   // This is set in the load/error event for the favicon image.
   let tileType = TileVisualType.NONE;
 
-  let mdTileLink = document.createElement('a');
-  mdTileLink.className = CLASSES.MD_TILE_LINK;
-  mdTileLink.tabIndex = 0;
-  mdTileLink.setAttribute('data-tid', data.tid);
-  mdTileLink.setAttribute('data-pos', position);
+  let mdTile = document.createElement('a');
+  mdTile.className = CLASSES.MD_TILE;
+  mdTile.tabIndex = 0;
+  mdTile.setAttribute('data-tid', data.tid);
+  mdTile.setAttribute('data-pos', position);
   if (isSchemeAllowed(data.url)) {
-    mdTileLink.href = data.url;
+    mdTile.href = data.url;
   }
-  mdTileLink.setAttribute('aria-label', data.title);
-  mdTileLink.title = data.title;
+  mdTile.setAttribute('aria-label', data.title);
+  mdTile.title = data.title;
 
-  mdTileLink.addEventListener('click', function(ev) {
+  mdTile.addEventListener('click', function(ev) {
     if (data.isAddButton) {
       editCustomLink();
       logEvent(LOG_TYPE.NTP_CUSTOMIZE_ADD_SHORTCUT_CLICKED);
@@ -690,30 +692,28 @@
           data.dataGenerationTime);
     }
   });
-  mdTileLink.addEventListener('keydown', function(event) {
+  mdTile.addEventListener('keydown', function(event) {
     if ((event.keyCode == 46 /* DELETE */ ||
          event.keyCode == 8 /* BACKSPACE */) &&
         !data.isAddButton) {
       event.preventDefault();
       event.stopPropagation();
-      blacklistTile(this);
+      blacklistTile(mdTileContainer);
     } else if (
         event.keyCode == 13 /* ENTER */ || event.keyCode == 32 /* SPACE */) {
       event.preventDefault();
       this.click();
     } else if (event.keyCode == 37 /* LEFT */) {
-      const tiles =
-          document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE_LINK);
+      const tiles = document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE);
       tiles[Math.max(Number(this.getAttribute('data-pos')) - 1, 0)].focus();
     } else if (event.keyCode == 39 /* RIGHT */) {
-      const tiles =
-          document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE_LINK);
+      const tiles = document.querySelectorAll('#mv-tiles .' + CLASSES.MD_TILE);
       tiles[Math.min(
                 Number(this.getAttribute('data-pos')) + 1, tiles.length - 1)]
           .focus();
     }
   });
-  disableOutlineOnMouseClick(mdTileLink);
+  disableOutlineOnMouseClick(mdTile);
 
   let mdTileInner = document.createElement('div');
   mdTileInner.className = CLASSES.MD_TILE_INNER;
@@ -787,8 +787,8 @@
   mdTitle.style.direction = data.direction || 'ltr';
   mdTitleContainer.appendChild(mdTitle);
   mdTileInner.appendChild(mdTitleContainer);
-  mdTileLink.appendChild(mdTileInner);
-  mdTile.appendChild(mdTileLink);
+  mdTile.appendChild(mdTileInner);
+  mdTileContainer.appendChild(mdTile);
 
   if (!data.isAddButton) {
     let mdMenu = document.createElement('button');
@@ -796,7 +796,9 @@
     if (isCustomLinksEnabled) {
       mdMenu.classList.add(CLASSES.MD_EDIT_MENU);
       mdMenu.title = queryArgs['editLinkTooltip'] || '';
-      mdMenu.name = (queryArgs['editLinkTooltip'] || '') + ' ' + data.title;
+      mdMenu.setAttribute(
+          'aria-label',
+          (queryArgs['editLinkTooltip'] || '') + ' ' + data.title);
       mdMenu.addEventListener('click', function(ev) {
         editCustomLink(data.tid);
         ev.preventDefault();
@@ -805,10 +807,11 @@
       });
     } else {
       mdMenu.title = queryArgs['removeTooltip'] || '';
-      mdMenu.name = (queryArgs['removeTooltip'] || '') + ' ' + data.title;
+      mdMenu.setAttribute(
+          'aria-label', (queryArgs['removeTooltip'] || '') + ' ' + data.title);
       mdMenu.addEventListener('click', function(ev) {
         removeAllOldTiles();
-        blacklistTile(mdTileLink);
+        blacklistTile(mdTileContainer);
         ev.preventDefault();
         ev.stopPropagation();
       });
@@ -820,10 +823,10 @@
     });
     disableOutlineOnMouseClick(mdMenu);
 
-    mdTile.appendChild(mdMenu);
+    mdTileContainer.appendChild(mdMenu);
   }
 
-  return mdTile;
+  return mdTileContainer;
 }
 
 
@@ -847,6 +850,8 @@
     queryArgs[decodeURIComponent(val[0])] = decodeURIComponent(val[1]);
   }
 
+  document.title = queryArgs['title'];
+
   if ('ntl' in queryArgs) {
     var ntl = parseInt(queryArgs['ntl'], 10);
     if (isFinite(ntl))
diff --git a/chrome/browser/resources/media/media_engagement.js b/chrome/browser/resources/media/media_engagement.js
index a1619c2..199c6d2 100644
--- a/chrome/browser/resources/media/media_engagement.js
+++ b/chrome/browser/resources/media/media_engagement.js
@@ -124,6 +124,15 @@
       formatFeatureFlag(config.featureBypassAutoplay)));
   configTableBody.appendChild(createConfigRow(
       'Preload MEI data', formatFeatureFlag(config.featurePreloadData)));
+  configTableBody.appendChild(createConfigRow(
+      'Autoplay sound settings',
+      formatFeatureFlag(config.featureAutoplaySoundSettings)));
+  configTableBody.appendChild(createConfigRow(
+      'Unified autoplay (preference)',
+      formatFeatureFlag(config.prefUnifiedAutoplay)));
+  configTableBody.appendChild(createConfigRow(
+      'Custom autoplay policy',
+      formatFeatureFlag(config.hasCustomAutoplayPolicy)));
   configTableBody.appendChild(
       createConfigRow('Autoplay Policy', config.autoplayPolicy));
   configTableBody.appendChild(createConfigRow(
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 7771042..94da713 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -130,6 +130,7 @@
   deps = [
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js/cr/ui:command",
   ]
 }
 
diff --git a/chrome/browser/resources/settings/find_shortcut_behavior.html b/chrome/browser/resources/settings/find_shortcut_behavior.html
index f6440393..50b4f350 100644
--- a/chrome/browser/resources/settings/find_shortcut_behavior.html
+++ b/chrome/browser/resources/settings/find_shortcut_behavior.html
@@ -1,3 +1,4 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/cr/ui/command.html">
 <script src="find_shortcut_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/find_shortcut_behavior.js b/chrome/browser/resources/settings/find_shortcut_behavior.js
index 63d51aa..0beae62 100644
--- a/chrome/browser/resources/settings/find_shortcut_behavior.js
+++ b/chrome/browser/resources/settings/find_shortcut_behavior.js
@@ -23,15 +23,14 @@
    */
   let modalContextOpen = false;
 
+  const shortcut =
+      new cr.ui.KeyboardShortcutList(cr.isMac ? 'meta|f' : 'ctrl|f');
+
   window.addEventListener('keydown', e => {
-    if (listeners.length == 0)
+    if (e.defaultPrevented || listeners.length == 0)
       return;
 
-    const modifierPressed = cr.isMac ? e.metaKey : e.ctrlKey;
-    if (modifierPressed && e.key == 'f') {
-      if (e.defaultPrevented)
-        return;
-
+    if (shortcut.matchesEvent(e)) {
       const listener = /** @type {!{handleFindShortcut: function(boolean)}} */ (
           listeners[listeners.length - 1]);
       if (listener.handleFindShortcut(modalContextOpen))
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index c127839..e334c12 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -2589,12 +2589,6 @@
     observer.Wait();
   }
 
-  // To exit the browser cleanly (and this test) we need to complete the
-  // download after completing this test.
-  content::DownloadTestObserverTerminal dangerous_download_observer(
-      content::BrowserContext::GetDownloadManager(browser()->profile()), 1,
-      content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT);
-
   // Proceed through the SSL interstitial. This doesn't use
   // ProceedThroughInterstitial() since no page load will commit.
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
@@ -2602,14 +2596,15 @@
   WaitForInterstitial(tab);
   ASSERT_NO_FATAL_FAILURE(ExpectSSLInterstitial(tab));
   {
-    content::TestNavigationObserver nav_observer(tab);
-    content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_DOWNLOAD_INITIATED,
-        content::NotificationService::AllSources());
+    // Wait for the download to complete after proceeding with the download.
+    // This serves to verify the download was initiated, and to let the
+    // test successfully shut down and cleanup. Exiting the browser with a
+    // download still in-progress can lead to test failues.
+    content::DownloadTestObserverTerminal dangerous_download_observer(
+        content::BrowserContext::GetDownloadManager(browser()->profile()), 1,
+        content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT);
     SendInterstitialCommand(tab, security_interstitials::CMD_PROCEED);
-    observer.Wait();
-    if (IsCommittedInterstitialTest())
-      nav_observer.Wait();
+    dangerous_download_observer.WaitForFinished();
   }
 
   // There should still be an interstitial at this point. Press the
@@ -2620,8 +2615,6 @@
   ASSERT_NO_FATAL_FAILURE(ExpectSSLInterstitial(tab));
   EXPECT_TRUE(chrome::CanGoBack(browser()));
   chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB);
-
-  dangerous_download_observer.WaitForFinished();
 }
 
 //
@@ -5935,7 +5928,8 @@
 }
 
 // Checks that navigations after pushState maintain the SSL status.
-IN_PROC_BROWSER_TEST_P(SSLUITest, PushStateSSLState) {
+// Flaky, see https://crbug.com/872029 and https://crbug.com/872030.
+IN_PROC_BROWSER_TEST_P(SSLUITest, DISABLED_PushStateSSLState) {
   ASSERT_TRUE(https_server_.Start());
 
   ui_test_utils::NavigateToURL(browser(),
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc
index c93c629c..502bfe4 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -70,8 +70,8 @@
     bool load_synchronously) {
   base::FilePath path =
       profile_path.Append(chrome::kSupervisedUserSettingsFilename);
-  PersistentPrefStore* store = new JsonPrefStore(path, sequenced_task_runner,
-                                                 std::unique_ptr<PrefFilter>());
+  PersistentPrefStore* store = new JsonPrefStore(
+      path, std::unique_ptr<PrefFilter>(), sequenced_task_runner);
   Init(store);
   if (load_synchronously) {
     store_->ReadPrefs();
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 19b6a7a..bd6bc5e 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -255,7 +255,8 @@
         prefs::kSavingBrowserHistoryDisabled,
         content::BrowserThread::GetTaskRunnerForThread(
             content::BrowserThread::UI),
-        web_data_service_thread_, profile_web_data_service_, password_store_);
+        web_data_service_thread_, profile_web_data_service_,
+        account_web_data_service_, password_store_);
   }
 }
 
@@ -589,38 +590,6 @@
       // Reading List is only supported on iOS at the moment.
       NOTREACHED();
       return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
-    case syncer::AUTOFILL:
-      return autofill::AutocompleteSyncBridge::FromWebDataService(
-                 profile_web_data_service_.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    case syncer::AUTOFILL_PROFILE:
-      return autofill::AutofillProfileSyncBridge::FromWebDataService(
-                 profile_web_data_service_.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    case syncer::AUTOFILL_WALLET_DATA: {
-      // TODO(feuunk): This doesn't allow switching which database to use at
-      // runtime. This should be fixed as part of the USS migration for
-      // payments.
-      auto service = account_web_data_service_ ? account_web_data_service_
-                                               : profile_web_data_service_;
-      return autofill::AutofillWalletSyncBridge::FromWebDataService(
-                 service.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    }
-    case syncer::AUTOFILL_WALLET_METADATA: {
-      // TODO(feuunk): This doesn't allow switching which database to use at
-      // runtime. This should be fixed as part of the USS migration for
-      // payments.
-      auto service = account_web_data_service_ ? account_web_data_service_
-                                               : profile_web_data_service_;
-      return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(
-                 service.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    }
 #if defined(OS_CHROMEOS)
     case syncer::PRINTERS:
       return chromeos::SyncedPrintersManagerFactory::GetForBrowserContext(
@@ -629,10 +598,6 @@
           ->change_processor()
           ->GetControllerDelegate();
 #endif  // defined(OS_CHROMEOS)
-    case syncer::TYPED_URLS:
-      // TypedURLModelTypeController doesn't exercise this function.
-      NOTREACHED();
-      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::USER_CONSENTS:
       return ConsentAuditorFactory::GetForProfile(profile_)
           ->GetControllerDelegate();
@@ -649,6 +614,17 @@
       return BookmarkSyncServiceFactory::GetForProfile(profile_)
           ->GetBookmarkSyncControllerDelegate();
     }
+
+    // We don't exercise this function for certain datatypes, because their
+    // controllers get the delegate elsewhere.
+    case syncer::AUTOFILL:
+    case syncer::AUTOFILL_PROFILE:
+    case syncer::AUTOFILL_WALLET_DATA:
+    case syncer::AUTOFILL_WALLET_METADATA:
+    case syncer::TYPED_URLS:
+      NOTREACHED();
+      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
+
     default:
       NOTREACHED();
       return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
diff --git a/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc b/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
index 39f59f3..4777416 100644
--- a/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
@@ -127,7 +127,7 @@
   // Default apps: chrome + web store + internal apps.
   const size_t kNumDefaultApps =
       2u + app_list::GetNumberOfInternalAppsShowInLauncherForTest(
-               /*apps_name=*/nullptr, GetProfile(0)->IsGuestSession());
+               /*apps_name=*/nullptr);
   ASSERT_EQ(kNumApps + kNumDefaultApps, service->GetNumSyncItemsForTest());
 
   ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 25279b84..79454e6d 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -20,6 +20,7 @@
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/test/fake_server/fake_server.h"
 #include "components/webdata/common/web_data_service_consumer.h"
 #include "content/public/browser/notification_service.h"
@@ -185,21 +186,43 @@
   EXPECT_EQ(1U, GetServerCards(GetProfileWebDataService(0)).size());
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, DownloadAccountStorage) {
+// ChromeOS does not support late signin after profile creation, so the test
+// below does not apply, at least in the current form.
+#if !defined(OS_CHROMEOS)
+// TODO(crbug.com/853688): Reenable once the USS implementation of
+// AUTOFILL_WALLET_DATA (AutofillWalletSyncBridge) has sufficient functionality.
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       DISABLED_DownloadAccountStorage) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       // Enabled.
-      {autofill::features::kAutofillEnableAccountWalletStorage},
+      {switches::kSyncStandaloneTransport, switches::kSyncUSSAutofillWalletData,
+       autofill::features::kAutofillEnableAccountWalletStorage},
       // Disabled.
       {});
+
+  ASSERT_TRUE(SetupClients());
   AddDefaultCard(GetFakeServer());
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
+  ASSERT_TRUE(GetClient(0)->SignIn());
+  ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization(
+      /*skip_passphrase_verification=*/false));
+  ASSERT_TRUE(AwaitQuiescence());
+  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
+            GetSyncService(0)->GetTransportState());
+  ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
+      syncer::AUTOFILL_WALLET_DATA));
 
   auto profile_data = GetProfileWebDataService(0);
   ASSERT_NE(nullptr, profile_data);
   auto account_data = GetAccountWebDataService(0);
   ASSERT_NE(nullptr, account_data);
 
+  // Check that no card is stored in the profile storage.
+  EXPECT_EQ(0U, GetServerCards(profile_data).size());
+
+  // Check that one card is stored in the account storage.
+  EXPECT_EQ(1U, GetServerCards(account_data).size());
+
   autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
   std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
@@ -214,13 +237,8 @@
   EXPECT_EQ(kDefaultCardExpYear, card->expiration_year());
   EXPECT_EQ(base::UTF8ToUTF16(kDefaultCardName),
             card->GetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NAME_FULL));
-
-  // Check that the card is *not* stored in the profile storage.
-  EXPECT_EQ(0U, GetServerCards(GetProfileWebDataService(0)).size());
-
-  // Check that the card is stored in the account storage.
-  EXPECT_EQ(1U, GetServerCards(GetAccountWebDataService(0)).size());
 }
+#endif  // !defined(OS_CHROMEOS)
 
 // Wallet data should get cleared from the database when sync is disabled.
 IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableSync) {
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 0d341863..73048845b 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -49,11 +49,14 @@
 // The tallest tab height in any mode.
 constexpr int kTallestTabHeight = 41;
 
+// The tallest height above the tabs in any mode is 19 DIP.
+constexpr int kTallestFrameHeight = kTallestTabHeight + 19;
+
 // Version number of the current theme pack. We just throw out and rebuild
 // theme packs that aren't int-equal to this. Increment this number if you
 // change default theme assets or if you need themes to recreate their generated
 // images (which are cached).
-const int kThemePackVersion = 56;
+const int kThemePackVersion = 57;
 
 // IDs that are in the DataPack won't clash with the positive integer
 // uint16_t. kHeaderID should always have the maximum value because we want the
@@ -282,12 +285,6 @@
 
   // The maximum useful height of the image at |prs_id|.
   int max_height;
-
-  // Whether cropping the image at |prs_id| should be skipped on OSes which
-  // have a frame border to the left and right of the web contents.
-  // This should be true for images which can be used to decorate the border to
-  // the left and the right of the web contents.
-  bool skip_if_frame_border;
 };
 
 // The images which should be cropped before being saved to the data pack. The
@@ -296,15 +293,15 @@
 // |kThemePackVersion| must be incremented if any of the maximum heights below
 // are modified.
 const struct CropEntry kImagesToCrop[] = {
-  { PRS_THEME_FRAME, 120, true },
-  { PRS_THEME_FRAME_INACTIVE, 120, true },
-  { PRS_THEME_FRAME_INCOGNITO, 120, true },
-  { PRS_THEME_FRAME_INCOGNITO_INACTIVE, 120, true },
-  { PRS_THEME_FRAME_OVERLAY, 120, true },
-  { PRS_THEME_FRAME_OVERLAY_INACTIVE, 120, true },
-  { PRS_THEME_TOOLBAR, 200, false },
-  { PRS_THEME_BUTTON_BACKGROUND, 60, false },
-  { PRS_THEME_WINDOW_CONTROL_BACKGROUND, 50, false },
+    {PRS_THEME_FRAME, kTallestFrameHeight},
+    {PRS_THEME_FRAME_INACTIVE, kTallestFrameHeight},
+    {PRS_THEME_FRAME_INCOGNITO, kTallestFrameHeight},
+    {PRS_THEME_FRAME_INCOGNITO_INACTIVE, kTallestFrameHeight},
+    {PRS_THEME_FRAME_OVERLAY, kTallestFrameHeight},
+    {PRS_THEME_FRAME_OVERLAY_INACTIVE, kTallestFrameHeight},
+    {PRS_THEME_TOOLBAR, 200},
+    {PRS_THEME_BUTTON_BACKGROUND, 60},
+    {PRS_THEME_WINDOW_CONTROL_BACKGROUND, 50},
 };
 
 // A list of images that don't need tinting or any other modification and can
@@ -316,16 +313,6 @@
   PRS_THEME_NTP_ATTRIBUTION,
 };
 
-// Returns true if this OS uses a browser frame which has a non zero width to
-// the left and the right of the web contents.
-bool HasFrameBorder() {
-#if defined(OS_CHROMEOS) || defined(OS_MACOSX)
-  return false;
-#else
-  return true;
-#endif
-}
-
 // Returns a piece of memory with the contents of the file |path|.
 scoped_refptr<base::RefCountedMemory> ReadFileData(const base::FilePath& path) {
   if (!path.empty()) {
@@ -1229,11 +1216,7 @@
 }
 
 void BrowserThemePack::CropImages(ImageCache* images) const {
-  bool has_frame_border = HasFrameBorder();
   for (size_t i = 0; i < arraysize(kImagesToCrop); ++i) {
-    if (has_frame_border && kImagesToCrop[i].skip_if_frame_border)
-      continue;
-
     int prs_id = kImagesToCrop[i].prs_id;
     ImageCache::iterator it = images->find(prs_id);
     if (it == images->end())
@@ -1301,11 +1284,8 @@
       temp_output[frame_values.prs_id] = dest_image;
 
       if (frame_values.color_id) {
-        // The tallest frame height above the top of tabs in any mode.
-        constexpr int kTallestFrameHeight = 19;
         ComputeColorFromImage(frame_values.color_id.value(),
-                              kTallestTabHeight + kTallestFrameHeight,
-                              dest_image);
+                              kTallestFrameHeight, dest_image);
       }
     }
   }
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index 287425d..2a769b4 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -342,7 +342,8 @@
   const gfx::ImageSkiaRep& rep1 = image_skia->GetRepresentation(1.0f);
   ASSERT_FALSE(rep1.is_null());
   EXPECT_EQ(80, rep1.sk_bitmap().width());
-  EXPECT_EQ(80, rep1.sk_bitmap().height());
+  // Bitmap height will be cropped at 60 - kTallestTabHeight + 19.
+  EXPECT_EQ(60, rep1.sk_bitmap().height());
   EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(4, 4));
   EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(8, 8));
   EXPECT_EQ(SkColorSetRGB(0, 241, 237), rep1.sk_bitmap().getColor(16, 16));
@@ -352,7 +353,8 @@
   const gfx::ImageSkiaRep& rep2 = image_skia->GetRepresentation(2.0f);
   ASSERT_FALSE(rep2.is_null());
   EXPECT_EQ(160, rep2.sk_bitmap().width());
-  EXPECT_EQ(160, rep2.sk_bitmap().height());
+  // Cropped height will be 2 * 60.
+  EXPECT_EQ(120, rep2.sk_bitmap().height());
   EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor(4, 4));
   EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(8, 8));
   EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(16, 16));
@@ -378,7 +380,8 @@
   const gfx::ImageSkiaRep& rep3 = image_skia->GetRepresentation(1.0f);
   ASSERT_FALSE(rep3.is_null());
   EXPECT_EQ(80, rep3.sk_bitmap().width());
-  EXPECT_EQ(80, rep3.sk_bitmap().height());
+  // Bitmap height will be cropped at 60 - kTallestTabHeight + 19.
+  EXPECT_EQ(60, rep3.sk_bitmap().height());
   // We take samples of colors and locations along the diagonal whenever
   // the color changes. Note these colors are slightly different from
   // the input PNG file due to input processing.
@@ -398,7 +401,8 @@
   const gfx::ImageSkiaRep& rep4 = image_skia->GetRepresentation(2.0f);
   ASSERT_FALSE(rep4.is_null());
   EXPECT_EQ(160, rep4.sk_bitmap().width());
-  EXPECT_EQ(160, rep4.sk_bitmap().height());
+  // Cropped height will be 2 * 60.
+  EXPECT_EQ(120, rep4.sk_bitmap().height());
   // We expect the same colors and at locations scaled by 2
   // since this bitmap was scaled by 2.
   for (size_t i = 0; i < normal.size(); ++i) {
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 2d6cf18e..4995a92 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -340,8 +340,11 @@
   }
 #endif
   ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi();
-  if (native_theme && native_theme->UsesHighContrastColors())
+  // IncreasedContrastThemeSupplier is designed for the Refresh UI only.
+  if (native_theme && native_theme->UsesHighContrastColors() &&
+      ui::MaterialDesignController::IsRefreshUi()) {
     SetCustomDefaultTheme(new IncreasedContrastThemeSupplier);
+  }
   ClearAllThemeData();
   NotifyThemeChanged();
 }
diff --git a/chrome/browser/themes/theme_service_win.cc b/chrome/browser/themes/theme_service_win.cc
index e556783..2a2eff4 100644
--- a/chrome/browser/themes/theme_service_win.cc
+++ b/chrome/browser/themes/theme_service_win.cc
@@ -14,12 +14,22 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 
+namespace {
+
+SkColor GetDefaultInactiveFrameColor() {
+  return base::win::GetVersion() < base::win::VERSION_WIN10
+             ? SkColorSetRGB(0xEB, 0xEB, 0xEB)
+             : SK_ColorWHITE;
+}
+
+}  // namespace
+
 ThemeServiceWin::ThemeServiceWin() {
-  // This just checks for Windows 10 instead of calling DwmColorsAllowed()
+  // This just checks for Windows 8+ instead of calling DwmColorsAllowed()
   // because we want to monitor the frame color even when a custom frame is in
   // use, so that it will be correct if at any time the user switches to the
   // native frame.
-  if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
     dwm_key_.reset(new base::win::RegKey(
         HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\DWM", KEY_READ));
     if (dwm_key_->Valid())
@@ -60,7 +70,7 @@
       if (!ShouldCustomDrawSystemTitlebar()) {
         return inactive_frame_color_from_registry_
                    ? dwm_inactive_frame_color_.value()
-                   : SK_ColorWHITE;
+                   : GetDefaultInactiveFrameColor();
       }
       if (dwm_inactive_frame_color_)
         return dwm_inactive_frame_color_.value();
@@ -73,38 +83,11 @@
 
 bool ThemeServiceWin::DwmColorsAllowed() const {
   return ShouldUseNativeFrame() &&
-         (base::win::GetVersion() >= base::win::VERSION_WIN10);
+         (base::win::GetVersion() >= base::win::VERSION_WIN8);
 }
 
 void ThemeServiceWin::OnDwmKeyUpdated() {
-  DWORD accent_color, color_prevalence;
-  bool use_dwm_frame_color =
-      dwm_key_->ReadValueDW(L"AccentColor", &accent_color) == ERROR_SUCCESS &&
-      dwm_key_->ReadValueDW(L"ColorPrevalence", &color_prevalence) ==
-          ERROR_SUCCESS &&
-      color_prevalence == 1;
-  inactive_frame_color_from_registry_ = false;
-  if (use_dwm_frame_color) {
-    dwm_frame_color_ = skia::COLORREFToSkColor(accent_color);
-    DWORD accent_color_inactive;
-    if (dwm_key_->ReadValueDW(L"AccentColorInactive", &accent_color_inactive) ==
-        ERROR_SUCCESS) {
-      dwm_inactive_frame_color_ =
-          skia::COLORREFToSkColor(accent_color_inactive);
-      inactive_frame_color_from_registry_ = true;
-    } else {
-      // Tint to create inactive color. Always use the non-incognito version of
-      // the tint, since the frame should look the same in both modes.
-      dwm_inactive_frame_color_ = color_utils::HSLShift(
-          dwm_frame_color_.value(),
-          GetTint(ThemeProperties::TINT_FRAME_INACTIVE, false));
-    }
-  } else {
-    dwm_frame_color_.reset();
-    dwm_inactive_frame_color_.reset();
-  }
-
-  dwm_accent_border_color_ = SK_ColorWHITE;
+  dwm_accent_border_color_ = GetDefaultInactiveFrameColor();
   DWORD colorization_color, colorization_color_balance;
   if ((dwm_key_->ReadValueDW(L"ColorizationColor", &colorization_color) ==
        ERROR_SUCCESS) &&
@@ -131,6 +114,39 @@
         gfx::ToRoundedInt(255 * colorization_color_balance / 100.f));
   }
 
+  inactive_frame_color_from_registry_ = false;
+  if (base::win::GetVersion() < base::win::VERSION_WIN10) {
+    dwm_frame_color_ = dwm_accent_border_color_;
+  } else {
+    DWORD accent_color, color_prevalence;
+    bool use_dwm_frame_color =
+        dwm_key_->ReadValueDW(L"AccentColor", &accent_color) == ERROR_SUCCESS &&
+        dwm_key_->ReadValueDW(L"ColorPrevalence", &color_prevalence) ==
+            ERROR_SUCCESS &&
+        color_prevalence == 1;
+    if (use_dwm_frame_color) {
+      dwm_frame_color_ = skia::COLORREFToSkColor(accent_color);
+      DWORD accent_color_inactive;
+      if (dwm_key_->ReadValueDW(L"AccentColorInactive",
+                                &accent_color_inactive) == ERROR_SUCCESS) {
+        dwm_inactive_frame_color_ =
+            skia::COLORREFToSkColor(accent_color_inactive);
+        inactive_frame_color_from_registry_ = true;
+      }
+    } else {
+      dwm_frame_color_.reset();
+      dwm_inactive_frame_color_.reset();
+    }
+  }
+
+  if (dwm_frame_color_ && !inactive_frame_color_from_registry_) {
+    // Tint to create inactive color. Always use the non-incognito version of
+    // the tint, since the frame should look the same in both modes.
+    dwm_inactive_frame_color_ = color_utils::HSLShift(
+        dwm_frame_color_.value(),
+        GetTint(ThemeProperties::TINT_FRAME_INACTIVE, false));
+  }
+
   // Watch for future changes.
   if (!dwm_key_->StartWatching(base::Bind(
           &ThemeServiceWin::OnDwmKeyUpdated, base::Unretained(this))))
diff --git a/chrome/browser/tracing/background_tracing_field_trial.cc b/chrome/browser/tracing/background_tracing_field_trial.cc
index ddca303..a6a0a82 100644
--- a/chrome/browser/tracing/background_tracing_field_trial.cc
+++ b/chrome/browser/tracing/background_tracing_field_trial.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/background_tracing_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/network_change_notifier.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 
 namespace tracing {
@@ -45,7 +46,7 @@
     std::unique_ptr<const base::DictionaryValue> metadata,
     content::BackgroundTracingManager::FinishedProcessingCallback callback) {
   TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
-      g_browser_process->system_request_context());
+      g_browser_process->shared_url_loader_factory());
 
   if (GURL(upload_url).is_valid())
     uploader->SetUploadURL(upload_url);
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.cc b/chrome/browser/tracing/chrome_tracing_delegate.cc
index dce3d85..cb78f6e3 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.cc
+++ b/chrome/browser/tracing/chrome_tracing_delegate.cc
@@ -82,9 +82,9 @@
 #endif  // defined(OS_ANDROID)
 
 std::unique_ptr<content::TraceUploader> ChromeTracingDelegate::GetTraceUploader(
-    net::URLRequestContextGetter* request_context) {
+    scoped_refptr<network::SharedURLLoaderFactory> factory) {
   return std::unique_ptr<content::TraceUploader>(
-      new TraceCrashServiceUploader(request_context));
+      new TraceCrashServiceUploader(std::move(factory)));
 }
 
 namespace {
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.h b/chrome/browser/tracing/chrome_tracing_delegate.h
index c052326b..517dc0d3 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.h
+++ b/chrome/browser/tracing/chrome_tracing_delegate.h
@@ -18,6 +18,10 @@
 
 class PrefRegistrySimple;
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 class ChromeTracingDelegate : public content::TracingDelegate,
 #if defined(OS_ANDROID)
                               public TabModelListObserver
@@ -32,7 +36,7 @@
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
   std::unique_ptr<content::TraceUploader> GetTraceUploader(
-      net::URLRequestContextGetter* request_context) override;
+      scoped_refptr<network::SharedURLLoaderFactory> factory) override;
 
   bool IsAllowedToBeginBackgroundScenario(
       const content::BackgroundTracingConfig& config,
diff --git a/chrome/browser/tracing/crash_service_uploader.cc b/chrome/browser/tracing/crash_service_uploader.cc
index b965c11..d618b1d0 100644
--- a/chrome/browser/tracing/crash_service_uploader.cc
+++ b/chrome/browser/tracing/crash_service_uploader.cc
@@ -29,10 +29,10 @@
 #include "net/proxy_resolution/proxy_config.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_builder.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 #include "third_party/zlib/zlib.h"
 #include "url/gurl.h"
 
@@ -51,8 +51,9 @@
 }  // namespace
 
 TraceCrashServiceUploader::TraceCrashServiceUploader(
-    net::URLRequestContextGetter* request_context)
-    : request_context_(request_context), max_upload_bytes_(kMaxUploadBytes) {
+    scoped_refptr<network::SharedURLLoaderFactory> factory)
+    : shared_url_loader_factory_(std::move(factory)),
+      max_upload_bytes_(kMaxUploadBytes) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -80,16 +81,21 @@
   max_upload_bytes_ = max_upload_bytes;
 }
 
-void TraceCrashServiceUploader::OnURLFetchComplete(
-    const net::URLFetcher* source) {
+void TraceCrashServiceUploader::OnSimpleURLLoaderComplete(
+    std::unique_ptr<std::string> response_body) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK_EQ(source, url_fetcher_.get());
-  int response_code = source->GetResponseCode();
+
   string feedback;
-  bool success = (response_code == net::HTTP_OK);
+  bool success = !!response_body;
   if (success) {
-    source->GetResponseAsString(&feedback);
+    feedback = std::move(*response_body);
   } else {
+    int response_code = -1;
+    if (simple_url_loader_->ResponseInfo() &&
+        simple_url_loader_->ResponseInfo()->headers) {
+      response_code =
+          simple_url_loader_->ResponseInfo()->headers->response_code();
+    }
     feedback =
         "Uploading failed, response code: " + base::IntToString(response_code);
   }
@@ -97,14 +103,12 @@
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
       base::BindOnce(std::move(done_callback_), success, feedback));
-  url_fetcher_.reset();
+  simple_url_loader_.reset();
 }
 
-void TraceCrashServiceUploader::OnURLFetchUploadProgress(
-    const net::URLFetcher* source,
-    int64_t current,
-    int64_t total) {
-  DCHECK(url_fetcher_.get());
+void TraceCrashServiceUploader::OnURLLoaderUploadProgress(uint64_t current,
+                                                          uint64_t total) {
+  DCHECK(simple_url_loader_);
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   LOG(WARNING) << "Upload progress: " << current << " of " << total;
@@ -139,7 +143,7 @@
     UploadMode upload_mode,
     const std::string& upload_url,
     std::unique_ptr<const base::DictionaryValue> metadata) {
-  DCHECK(!url_fetcher_.get());
+  DCHECK(!simple_url_loader_.get());
 
   if (upload_url.empty()) {
     OnUploadError("Upload URL empty or invalid");
@@ -175,7 +179,7 @@
     version = "unknown";
   }
 
-  if (url_fetcher_.get()) {
+  if (simple_url_loader_) {
     OnUploadError("Already uploading.");
     return;
   }
@@ -205,8 +209,8 @@
 
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&TraceCrashServiceUploader::CreateAndStartURLFetcher,
-                 base::Unretained(this), upload_url, post_data));
+      base::BindOnce(&TraceCrashServiceUploader::CreateAndStartURLLoader,
+                     base::Unretained(this), upload_url, post_data));
 }
 
 void TraceCrashServiceUploader::OnUploadError(
@@ -301,11 +305,11 @@
   return success;
 }
 
-void TraceCrashServiceUploader::CreateAndStartURLFetcher(
+void TraceCrashServiceUploader::CreateAndStartURLLoader(
     const std::string& upload_url,
     const std::string& post_data) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(!url_fetcher_.get());
+  DCHECK(!simple_url_loader_);
 
   std::string content_type = kCrashUploadContentType;
   content_type.append("; boundary=");
@@ -348,14 +352,26 @@
           }
         })");
 
-  url_fetcher_ = net::URLFetcher::Create(
-      GURL(upload_url), net::URLFetcher::POST, this, traffic_annotation);
-  data_use_measurement::DataUseUserData::AttachToFetcher(
-      url_fetcher_.get(),
-      data_use_measurement::DataUseUserData::TRACING_UPLOADER);
-  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
-                             net::LOAD_DO_NOT_SEND_COOKIES);
-  url_fetcher_->SetRequestContext(request_context_);
-  url_fetcher_->SetUploadData(content_type, post_data);
-  url_fetcher_->Start();
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = GURL(upload_url);
+  resource_request->method = "POST";
+  resource_request->enable_upload_progress = true;
+  resource_request->load_flags =
+      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+
+  // TODO(https://crbug.com/808498): Re-add data use measurement once
+  // SimpleURLLoader supports it.
+  // ID=data_use_measurement::DataUseUserData::TRACING_UPLOADER
+  simple_url_loader_ = network::SimpleURLLoader::Create(
+      std::move(resource_request), traffic_annotation);
+  simple_url_loader_->AttachStringForUpload(post_data, content_type);
+
+  simple_url_loader_->SetOnUploadProgressCallback(
+      base::BindRepeating(&TraceCrashServiceUploader::OnURLLoaderUploadProgress,
+                          base::Unretained(this)));
+
+  simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      shared_url_loader_factory_.get(),
+      base::BindOnce(&TraceCrashServiceUploader::OnSimpleURLLoaderComplete,
+                     base::Unretained(this)));
 }
diff --git a/chrome/browser/tracing/crash_service_uploader.h b/chrome/browser/tracing/crash_service_uploader.h
index 332190e..5548eb23 100644
--- a/chrome/browser/tracing/crash_service_uploader.h
+++ b/chrome/browser/tracing/crash_service_uploader.h
@@ -16,31 +16,23 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "content/public/browser/trace_uploader.h"
-#include "net/url_request/url_fetcher_delegate.h"
 
-namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
-}  // namespace net
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
 
 // TraceCrashServiceUploader uploads traces to the Chrome crash service.
-class TraceCrashServiceUploader : public content::TraceUploader,
-                                  public net::URLFetcherDelegate {
+class TraceCrashServiceUploader : public content::TraceUploader {
  public:
   explicit TraceCrashServiceUploader(
-      net::URLRequestContextGetter* request_context);
+      scoped_refptr<network::SharedURLLoaderFactory>);
   ~TraceCrashServiceUploader() override;
 
   void SetUploadURL(const std::string& url);
 
   void SetMaxUploadBytes(size_t max_upload_bytes);
 
-  // net::URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
-  void OnURLFetchUploadProgress(const net::URLFetcher* source,
-                                int64_t current,
-                                int64_t total) override;
-
   // content::TraceUploader
   void DoUpload(const std::string& file_contents,
                 UploadMode upload_mode,
@@ -49,6 +41,9 @@
                 UploadDoneCallback done_callback) override;
 
  private:
+  void OnSimpleURLLoaderComplete(std::unique_ptr<std::string> response_body);
+  void OnURLLoaderUploadProgress(uint64_t position, uint64_t size);
+
   void DoCompressOnBackgroundThread(
       const std::string& file_contents,
       UploadMode upload_mode,
@@ -71,15 +66,15 @@
                 int max_compressed_bytes,
                 char* compressed_contents,
                 int* compressed_bytes);
-  void CreateAndStartURLFetcher(const std::string& upload_url,
-                                const std::string& post_data);
+  void CreateAndStartURLLoader(const std::string& upload_url,
+                               const std::string& post_data);
   void OnUploadError(const std::string& error_message);
 
-  std::unique_ptr<net::URLFetcher> url_fetcher_;
   UploadProgressCallback progress_callback_;
   UploadDoneCallback done_callback_;
 
-  net::URLRequestContextGetter* request_context_;
+  std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
 
   std::string upload_url_;
 
diff --git a/chrome/browser/tracing/navigation_tracing.cc b/chrome/browser/tracing/navigation_tracing.cc
index 6293df66..9590c7f 100644
--- a/chrome/browser/tracing/navigation_tracing.cc
+++ b/chrome/browser/tracing/navigation_tracing.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 using content::RenderFrameHost;
 
@@ -40,7 +41,7 @@
     std::unique_ptr<const base::DictionaryValue> metadata,
     content::BackgroundTracingManager::FinishedProcessingCallback callback) {
   TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
-      g_browser_process->system_request_context());
+      g_browser_process->shared_url_loader_factory());
 
   uploader->DoUpload(
       file_contents->data(), content::TraceUploader::UNCOMPRESSED_UPLOAD,
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
index 7975b53..4cab9032 100644
--- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -708,8 +708,7 @@
 
 // Tests that internal app's context menu is correct.
 TEST_P(AppContextMenuTest, InternalAppMenu) {
-  for (const auto& internal_app :
-       app_list::GetInternalAppList(profile()->IsGuestSession())) {
+  for (const auto& internal_app : app_list::GetInternalAppList()) {
     if (!internal_app.show_in_launcher)
       continue;
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index fa0ae0a..ae06d05 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -85,11 +85,10 @@
 constexpr char kAndroidClockAppId[] = "ddmmnabaeomoacfpfjgghfpocfolhjlg";
 constexpr char kAndroidFilesAppId[] = "gmiohhmfhgfclpeacmdfancbipocempm";
 constexpr char kAndroidCameraAppId[] = "goamfaniemdfcajgcmmflhchgkmbngka";
-constexpr char kAndroidLegacyCameraAppId[] = "obfofkigjfamlldmipdegnjlcpincibc";
 
 constexpr char const* kAppIdsHiddenInLauncher[] = {
-    kAndroidClockAppId, kSettingsAppId, kAndroidFilesAppId, kAndroidCameraAppId,
-    kAndroidLegacyCameraAppId};
+    kAndroidClockAppId, kSettingsAppId, kAndroidFilesAppId,
+    kAndroidCameraAppId};
 
 // Returns true if |event_flags| came from a mouse or touch event.
 bool IsMouseOrTouchEventFromFlags(int event_flags) {
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
index 3f9b48c..e6f9d94a 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
@@ -46,45 +46,45 @@
 namespace {
 constexpr char kChromeCameraAppId[] = "hfhhnacclhffhdffklopdkcgdhifgngh";
 constexpr char kAndroidCameraAppId[] = "goamfaniemdfcajgcmmflhchgkmbngka";
-constexpr char kAndroidLegacyCameraAppId[] = "obfofkigjfamlldmipdegnjlcpincibc";
 }  // namespace
 
-const std::vector<InternalApp>& GetInternalAppList(bool is_guest_mode) {
-  base::NoDestructor<std::vector<InternalApp>> internal_app_list(
+const std::vector<InternalApp>& GetInternalAppList() {
+  static const base::NoDestructor<std::vector<InternalApp>> internal_app_list(
       {{kInternalAppIdKeyboardShortcutViewer,
         IDS_INTERNAL_APP_KEYBOARD_SHORTCUT_VIEWER, IDR_SHORTCUT_VIEWER_LOGO_192,
         /*recommendable=*/false,
         /*searchable=*/true,
-        /*show_in_launcher=*/false, InternalAppName::kKeyboardShortcutViewer,
+        /*show_in_launcher=*/false,
+        InternalAppName::kKeyboardShortcutViewer,
         IDS_LAUNCHER_SEARCHABLE_KEYBOARD_SHORTCUT_VIEWER},
 
        {kInternalAppIdSettings, IDS_INTERNAL_APP_SETTINGS,
         IDR_SETTINGS_LOGO_192,
         /*recommendable=*/true,
         /*searchable=*/true,
-        /*show_in_launcher=*/true, InternalAppName::kSettings,
+        /*show_in_launcher=*/true,
+        InternalAppName::kSettings,
         /*searchable_string_resource_id=*/0},
 
        {kInternalAppIdContinueReading, IDS_INTERNAL_APP_CONTINUOUS_READING,
         IDR_PRODUCT_LOGO_256,
         /*recommendable=*/true,
         /*searchable=*/false,
-        /*show_in_launcher=*/false, InternalAppName::kContinueReading,
-        /*searchable_string_resource_id=*/0}});
+        /*show_in_launcher=*/false,
+        InternalAppName::kContinueReading,
+        /*searchable_string_resource_id=*/0},
 
-  if (!is_guest_mode) {
-    internal_app_list->push_back(
-        {kInternalAppIdCamera, IDS_INTERNAL_APP_CAMERA, IDR_CAMERA_LOGO_192,
-         /*recommendable=*/true,
-         /*searchable=*/true,
-         /*show_in_launcher=*/true, InternalAppName::kCamera,
-         /*searchable_string_resource_id=*/0});
-  }
+       {kInternalAppIdCamera, IDS_INTERNAL_APP_CAMERA, IDR_CAMERA_LOGO_192,
+        /*recommendable=*/true,
+        /*searchable=*/true,
+        /*show_in_launcher=*/true,
+        InternalAppName::kCamera,
+        /*searchable_string_resource_id=*/0}});
   return *internal_app_list;
 }
 
 const InternalApp* FindInternalApp(const std::string& app_id) {
-  for (const auto& app : GetInternalAppList(false)) {
+  for (const auto& app : GetInternalAppList()) {
     if (app_id == app.app_id)
       return &app;
   }
@@ -121,13 +121,9 @@
   AppListClientImpl* controller = AppListClientImpl::GetInstance();
   if (arc_enabled && (!extension || media_consolidated)) {
     // Open ARC++ camera app.
-    if (!arc::LaunchApp(profile, kAndroidCameraAppId, event_flags,
-                        arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER,
-                        controller->GetAppListDisplayId())) {
-      arc::LaunchApp(profile, kAndroidLegacyCameraAppId, event_flags,
-                     arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER,
-                     controller->GetAppListDisplayId());
-    }
+    arc::LaunchApp(profile, kAndroidCameraAppId, event_flags,
+                   arc::UserInteractionType::APP_STARTED_FROM_LAUNCHER,
+                   controller->GetAppListDisplayId());
   } else if (extension) {
     // Open Chrome camera app.
     AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
@@ -234,11 +230,10 @@
   return app->internal_app_name;
 }
 
-size_t GetNumberOfInternalAppsShowInLauncherForTest(std::string* apps_name,
-                                                    bool is_guest_mode) {
+size_t GetNumberOfInternalAppsShowInLauncherForTest(std::string* apps_name) {
   size_t num_of_internal_apps_show_in_launcher = 0u;
   std::vector<std::string> internal_apps_name;
-  for (const auto& app : GetInternalAppList(is_guest_mode)) {
+  for (const auto& app : GetInternalAppList()) {
     if (app.show_in_launcher) {
       ++num_of_internal_apps_show_in_launcher;
       if (apps_name) {
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h
index 120b324..4b56fe97 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h
@@ -52,7 +52,7 @@
 };
 
 // Returns a list of Chrome OS internal apps, which are searchable in launcher.
-const std::vector<InternalApp>& GetInternalAppList(bool is_guest_mode);
+const std::vector<InternalApp>& GetInternalAppList();
 
 // Returns InternalApp by |app_id|.
 // Returns nullptr if |app_id| does not correspond to an internal app.
@@ -95,8 +95,7 @@
 // Returns the number of internal apps which can show in launcher.
 // If |apps_name| is not nullptr, it will be the concatenated string of these
 // internal apps' name.
-size_t GetNumberOfInternalAppsShowInLauncherForTest(std::string* apps_name,
-                                                    bool is_guest_mode);
+size_t GetNumberOfInternalAppsShowInLauncherForTest(std::string* apps_name);
 
 }  // namespace app_list
 
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc b/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc
index fb6c89f..37021a7 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/app_list/internal_app/internal_app_model_builder.h"
 
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_item.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
@@ -14,8 +13,7 @@
     : AppListModelBuilder(controller, InternalAppItem::kItemType) {}
 
 void InternalAppModelBuilder::BuildModel() {
-  for (const auto& internal_app :
-       app_list::GetInternalAppList(profile()->IsGuestSession())) {
+  for (const auto& internal_app : app_list::GetInternalAppList()) {
     if (!internal_app.show_in_launcher)
       continue;
 
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/internal_app/internal_app_model_builder_unittest.cc
index 338a0015..26a7f00 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_model_builder_unittest.cc
@@ -6,13 +6,11 @@
 
 #include "base/macros.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
-#include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -35,6 +33,7 @@
   // AppListTestBase:
   void SetUp() override {
     AppListTestBase::SetUp();
+    CreateBuilder();
   }
 
   void TearDown() override {
@@ -43,20 +42,19 @@
   }
 
  protected:
+  std::unique_ptr<FakeAppListModelUpdater> model_updater_;
+
+ private:
   // Creates a new builder, destroying any existing one.
-  void CreateBuilder(bool guest_mode) {
+  void CreateBuilder() {
     ResetBuilder();  // Destroy any existing builder in the correct order.
 
-    testing_profile()->SetGuestSession(guest_mode);
     model_updater_ = std::make_unique<FakeAppListModelUpdater>();
     controller_ = std::make_unique<test::TestAppListControllerDelegate>();
     builder_ = std::make_unique<InternalAppModelBuilder>(controller_.get());
     builder_->Initialize(nullptr, profile(), model_updater_.get());
   }
 
-  std::unique_ptr<FakeAppListModelUpdater> model_updater_;
-
- private:
   void ResetBuilder() {
     builder_.reset();
     controller_.reset();
@@ -73,20 +71,8 @@
   // The internal apps list is provided by GetInternalAppList() in
   // internal_app_metadata.cc. Only count the apps can display in launcher.
   std::string internal_apps_name;
-  CreateBuilder(false);
   EXPECT_EQ(app_list::GetNumberOfInternalAppsShowInLauncherForTest(
-                &internal_apps_name, profile()->IsGuestSession()),
-            model_updater_->ItemCount());
-  EXPECT_EQ(internal_apps_name, GetModelContent(model_updater_.get()));
-}
-
-TEST_F(InternalAppModelBuilderTest, BuildGuestMode) {
-  // The internal apps list is provided by GetInternalAppList() in
-  // internal_app_metadata.cc. Only count the apps can display in launcher.
-  std::string internal_apps_name;
-  CreateBuilder(true);
-  EXPECT_EQ(app_list::GetNumberOfInternalAppsShowInLauncherForTest(
-                &internal_apps_name, profile()->IsGuestSession()),
+                &internal_apps_name),
             model_updater_->ItemCount());
   EXPECT_EQ(internal_apps_name, GetModelContent(model_updater_.get()));
 }
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 44302fe..374a3df5 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -370,8 +370,7 @@
   // AppSearchProvider::DataSource overrides:
   void AddApps(AppSearchProvider::Apps* apps) override {
     const base::Time time;
-    for (const auto& internal_app :
-         GetInternalAppList(profile()->IsGuestSession())) {
+    for (const auto& internal_app : GetInternalAppList()) {
       if (!std::strcmp(internal_app.app_id, kInternalAppIdContinueReading) &&
           !features::IsContinueReadingEnabled()) {
         continue;
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index 4d137cab..76483973 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -70,10 +70,6 @@
 #include "chrome/browser/exo_parts.h"
 #endif
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-#include "chrome/browser/ui/ash/assistant/assistant_client.h"
-#endif
-
 namespace {
 
 void PushProcessCreationTimeToAsh() {
@@ -198,12 +194,6 @@
       chromeos::input_method::InputMethodManager::Get());
   ime_controller_client_->Init();
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-  // Assistant has to be initialized before session_controller_client to avoid
-  // race of SessionChanged event and assistant_client initialization.
-  assistant_client_ = std::make_unique<AssistantClient>();
-#endif
-
   session_controller_client_ = std::make_unique<SessionControllerClient>();
   session_controller_client_->Init();
 
@@ -288,9 +278,6 @@
   system_tray_client_.reset();
   shell_state_client_.reset();
   session_controller_client_.reset();
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-  assistant_client_.reset();
-#endif
   chrome_new_window_client_.reset();
   network_portal_notification_controller_.reset();
   media_client_.reset();
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
index aa35b34..15b6b1ad 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
@@ -10,7 +10,6 @@
 #include "base/macros.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 #include "chrome/common/buildflags.h"
-#include "chromeos/assistant/buildflags.h"
 
 namespace aura {
 class UserActivityForwarder;
@@ -49,10 +48,6 @@
 class ExoParts;
 #endif
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-class AssistantClient;
-#endif
-
 namespace internal {
 class ChromeLauncherControllerInitializer;
 }
@@ -114,10 +109,6 @@
   std::unique_ptr<ExoParts> exo_parts_;
 #endif
 
-#if BUILDFLAG(ENABLE_CROS_ASSISTANT)
-  std::unique_ptr<AssistantClient> assistant_client_;
-#endif
-
   // Initialized in PostProfileInit in all configs:
   std::unique_ptr<CastConfigClientMediaRouter> cast_config_client_media_router_;
   std::unique_ptr<LoginScreenClient> login_screen_client_;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 63baeb4a..ed9bbc7 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -4306,8 +4306,7 @@
   InitLauncherController();
 
   // Only test the first internal app. The others should be the same.
-  const auto& internal_app =
-      app_list::GetInternalAppList(profile()->IsGuestSession()).front();
+  const auto& internal_app = app_list::GetInternalAppList().front();
   const std::string app_id = internal_app.app_id;
   const ash::ShelfID shelf_id(app_id);
   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
@@ -4338,8 +4337,7 @@
   InitLauncherController();
 
   // Only test the first internal app. The others should be the same.
-  const auto& internal_app =
-      app_list::GetInternalAppList(profile()->IsGuestSession()).front();
+  const auto& internal_app = app_list::GetInternalAppList().front();
   std::string app_id;
   ash::ShelfID shelf_id;
   EXPECT_FALSE(launcher_controller_->GetItem(shelf_id));
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
index af35871..142a120 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -462,8 +462,7 @@
 
 // Tests that the context menu of internal app  is correct.
 TEST_F(LauncherContextMenuTest, InternalAppShelfContextMenu) {
-  for (const auto& internal_app :
-       app_list::GetInternalAppList(profile()->IsGuestSession())) {
+  for (const auto& internal_app : app_list::GetInternalAppList()) {
     if (!internal_app.show_in_launcher)
       continue;
 
@@ -493,8 +492,7 @@
 
 // Tests that the number of context menu options of internal app is correct.
 TEST_F(LauncherContextMenuTest, InternalAppShelfContextMenuOptionsNumber) {
-  for (const auto& internal_app :
-       app_list::GetInternalAppList(profile()->IsGuestSession())) {
+  for (const auto& internal_app : app_list::GetInternalAppList()) {
     const std::string app_id = internal_app.app_id;
     const ash::ShelfID shelf_id(app_id);
     // Pin internal app.
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index 939f315287..7cb1556e 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -81,6 +81,8 @@
   switch (detector->upgrade_notification_stage()) {
     case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
       return ash::mojom::UpdateSeverity::NONE;
+    case UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW:
+      return ash::mojom::UpdateSeverity::VERY_LOW;
     case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
       return ash::mojom::UpdateSeverity::LOW;
     case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
@@ -88,9 +90,10 @@
     case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
       return ash::mojom::UpdateSeverity::HIGH;
     case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
-      return ash::mojom::UpdateSeverity::CRITICAL;
+      break;
   }
-  NOTREACHED();
+  DCHECK_EQ(detector->upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL);
   return ash::mojom::UpdateSeverity::CRITICAL;
 }
 
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
index 2ef837e..3f76a81 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
@@ -105,7 +105,10 @@
 };
 
 // Tests to check if the touch bar shows up properly.
-IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, MakeTouchBar) {
+// DISABLED because it consistently fails "Mac10.12 Tests"
+// https://crbug.com/871740
+IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest,
+                       DISABLED_MakeTouchBar) {
   if (@available(macOS 10.12.2, *)) {
     NSString* const kTextSuggestionsTouchBarId = @"text-suggestions";
 
@@ -123,8 +126,10 @@
 }
 
 // Tests that a change in text selection is handled properly.
+// DISABLED because it consistently fails "Mac10.12 Tests"
+// https://crbug.com/871740
 IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest,
-                       UpdateTextSelection) {
+                       DISABLED_UpdateTextSelection) {
   NSString* const kText = @"text";
   NSString* const kEmptyText = @"";
   const gfx::Range kRange = gfx::Range(0, 4);
@@ -175,7 +180,10 @@
 }
 
 // Tests that a change in WebContents is handled properly.
-IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, SetWebContents) {
+// DISABLED because it consistently fails "Mac10.12 Tests"
+// https://crbug.com/871740
+IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest,
+                       DISABLED_SetWebContents) {
   NSString* const kText = @"text";
   const gfx::Range kRange = gfx::Range(1, 1);
 
@@ -201,4 +209,4 @@
   }
 }
 
-}  // namespace
\ No newline at end of file
+}  // namespace
diff --git a/chrome/browser/ui/hung_renderer/hung_renderer_core.cc b/chrome/browser/ui/hung_renderer/hung_renderer_core.cc
index bc2ff477..9f721476 100644
--- a/chrome/browser/ui/hung_renderer/hung_renderer_core.cc
+++ b/chrome/browser/ui/hung_renderer/hung_renderer_core.cc
@@ -45,11 +45,7 @@
     if (frame->GetProcess() == hung_process)
       return frame->GetLastCommittedURL();
   }
-
-  // If a frame is attempting to commit a navigation into a hung renderer
-  // process, then its |frame->GetProcess()| will still return the process
-  // hosting the previously committed navigation.  In such case, the loop above
-  // might not find any matching frame.
+  NOTREACHED();
   return GURL();
 }
 
@@ -67,15 +63,9 @@
   std::copy_if(AllTabContentses().begin(), AllTabContentses().end(),
                std::back_inserter(result), is_hung);
 
-  // Move |hung_web_contents| to the front.  It might be missing from the
-  // initial |results| when it hasn't yet committed a navigation into the hung
-  // process.
+  // Move |hung_web_contents| to the front.
   auto first = std::find(result.begin(), result.end(), hung_web_contents);
-  if (first != result.end())
-    std::rotate(result.begin(), first, std::next(first));
-  else
-    result.insert(result.begin(), hung_web_contents);
-
+  std::rotate(result.begin(), first, std::next(first));
   return result;
 }
 
@@ -97,8 +87,6 @@
     return page_title;
 
   GURL hung_url = GetURLOfAnyHungFrame(affected_web_contents, hung_process);
-  if (!hung_url.is_valid() || !hung_url.has_host())
-    return page_title;
 
   // N.B. using just the host here is OK since this is a notification and the
   // user doesn't need to make a security critical decision about the page in
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index ee8123ec..7e2af8c 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -52,6 +52,7 @@
 #include "components/omnibox/browser/search_provider.h"
 #include "components/prefs/pref_service.h"
 #include "components/search/search.h"
+#include "components/search_engines/search_engines_pref_names.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/toolbar/toolbar_model.h"
 #include "content/public/browser/navigation_controller.h"
@@ -191,6 +192,15 @@
   return url.spec() == profile_->GetPrefs()->GetString(prefs::kHomePage);
 }
 
+bool ChromeOmniboxClient::IsDefaultSearchProviderEnabled() const {
+  const base::DictionaryValue* url_dict = profile_->GetPrefs()->GetDictionary(
+      DefaultSearchManager::kDefaultSearchProviderDataPrefName);
+  bool disabled_by_policy = false;
+  url_dict->GetBoolean(DefaultSearchManager::kDisabledByPolicy,
+                       &disabled_by_policy);
+  return !disabled_by_policy;
+}
+
 const SessionID& ChromeOmniboxClient::GetSessionID() const {
   return SessionTabHelper::FromWebContents(
       controller_->GetWebContents())->session_id();
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
index 0a3fecc..d82a6fda 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -43,6 +43,7 @@
   bool IsPasteAndGoEnabled() const override;
   bool IsNewTabPage(const GURL& url) const override;
   bool IsHomePage(const GURL& url) const override;
+  bool IsDefaultSearchProviderEnabled() const override;
   const SessionID& GetSessionID() const override;
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   TemplateURLService* GetTemplateURLService() override;
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index ced129b..a247d3a 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -43,6 +43,8 @@
 #include "components/omnibox/browser/history_quick_provider.h"
 #include "components/omnibox/browser/omnibox_popup_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/toolbar/test_toolbar_model.h"
@@ -160,6 +162,14 @@
     ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
   }
 
+  void SetUp() override {
+    EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_))
+        .WillRepeatedly(testing::Return(true));
+    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
+        &policy_provider_);
+    InProcessBrowserTest::SetUp();
+  }
+
   static void GetOmniboxViewForBrowser(
       const Browser* browser,
       OmniboxView** omnibox_view) {
@@ -377,7 +387,13 @@
     base::RunLoop::QuitCurrentWhenIdleDeprecated();
   }
 
+  policy::MockConfigurationPolicyProvider* policy_provider() {
+    return &policy_provider_;
+  }
+
  private:
+  policy::MockConfigurationPolicyProvider policy_provider_;
+
   test::ScopedMacViewsBrowserMode views_mode_{true};
 
   // Non-owning pointer.
@@ -1000,6 +1016,25 @@
   EXPECT_FALSE(omnibox_view->model()->is_keyword_selected());
 }
 
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, SearchDisabledDontCrashOnQuestionMark) {
+  policy::PolicyMap policies;
+  policies.Set("DefaultSearchProviderEnabled", policy::POLICY_LEVEL_MANDATORY,
+               policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_PLATFORM,
+               std::make_unique<base::Value>(false), nullptr);
+  policy_provider()->UpdateChromePolicy(policies);
+  base::RunLoop().RunUntilIdle();
+
+  OmniboxView* omnibox_view = NULL;
+  ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
+
+  base::string16 search_keyword(ASCIIToUTF16(kSearchKeyword));
+
+  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_OEM_2, ui::EF_SHIFT_DOWN));
+  ASSERT_FALSE(omnibox_view->model()->is_keyword_hint());
+  ASSERT_FALSE(omnibox_view->model()->is_keyword_selected());
+  ASSERT_EQ(ASCIIToUTF16("?"), omnibox_view->GetText());
+}
+
 // Flaky on Windows and Linux. http://crbug.com/751543
 #if defined(OS_WIN) || defined(OS_LINUX)
 #define MAYBE_AcceptKeywordBySpace DISABLED_AcceptKeywordBySpace
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 5c59c70..d475c250 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -440,10 +440,12 @@
 
   ui::SelectFileDialog::FileTypeInfo file_types;
   file_types.allowed_paths = ui::SelectFileDialog::FileTypeInfo::NATIVE_PATH;
-  file_types.extensions.resize(2);
+  file_types.extensions.resize(1);
   file_types.extensions[0].push_back(FILE_PATH_LITERAL("jpg"));
   file_types.extensions[0].push_back(FILE_PATH_LITERAL("jpeg"));
-  file_types.extensions[1].push_back(FILE_PATH_LITERAL("png"));
+  file_types.extensions[0].push_back(FILE_PATH_LITERAL("png"));
+  file_types.extension_description_overrides.push_back(
+      l10n_util::GetStringUTF16(IDS_UPLOAD_IMAGE_FORMAT));
 
   select_file_dialog_->SelectFile(
       ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(), directory,
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
index 6a1f1b90..c5bb54a 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
@@ -10,31 +10,54 @@
 #include "chrome/browser/ui/global_error/global_error_service.h"
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
 #include "chrome/browser/upgrade_detector.h"
+#include "chrome/common/channel_info.h"
+#include "components/version_info/channel.h"
 
 namespace {
 
-// Maps an upgrade level to a severity level.
+// Maps an upgrade level to a severity level. When |show_very_low_upgrade_level|
+// is true, VERY_LOW through HIGH all return Severity::LOW. Otherwise, VERY_LOW
+// is ignored and LOW through HIGH return their respective Severity level.
 AppMenuIconController::Severity SeverityFromUpgradeLevel(
+    bool show_very_low_upgrade_level,
     UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
-  switch (level) {
-    case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
-      return AppMenuIconController::Severity::NONE;
-    case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
-      return AppMenuIconController::Severity::LOW;
-    case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
-      return AppMenuIconController::Severity::MEDIUM;
-    case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
-    case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
-      return AppMenuIconController::Severity::HIGH;
+  if (show_very_low_upgrade_level) {
+    // Anything between kNone and kCritical is LOW for unstable desktop Chrome.
+    switch (level) {
+      case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
+        break;
+      case UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW:
+      case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
+      case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
+      case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
+        return AppMenuIconController::Severity::LOW;
+      case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
+        return AppMenuIconController::Severity::HIGH;
+    }
+  } else {
+    switch (level) {
+      case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
+        break;
+      case UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW:
+        // kVeryLow is meaningless for stable channels.
+        return AppMenuIconController::Severity::NONE;
+      case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
+        return AppMenuIconController::Severity::LOW;
+      case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
+        return AppMenuIconController::Severity::MEDIUM;
+      case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
+      case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
+        return AppMenuIconController::Severity::HIGH;
+    }
   }
-  NOTREACHED();
+  DCHECK_EQ(level, UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+
   return AppMenuIconController::Severity::NONE;
 }
 
-// Checks if the app menu icon should be animated for the given upgrade level.
-bool ShouldAnimateUpgradeLevel(
-    UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
-  return level != UpgradeDetector::UPGRADE_ANNOYANCE_NONE;
+// Checks if the app menu icon should be animated for the given severity.
+bool ShouldAnimateSeverity(AppMenuIconController::Severity severity) {
+  return severity != AppMenuIconController::Severity::NONE;
 }
 
 // Returns true if we should show the upgrade recommended icon.
@@ -48,11 +71,23 @@
 #endif
 }
 
+// Return true if the browser is updating on the dev or canary channels.
+bool IsUnstableChannel() {
+  // Unbranded (Chromium) builds are on the UNKNOWN channel, so check explicitly
+  // for the Google Chrome channels that are considered "unstable". This ensures
+  // that Chromium builds get the default behavior.
+  const version_info::Channel channel = chrome::GetChannel();
+  return channel == version_info::Channel::DEV ||
+         channel == version_info::Channel::CANARY;
+}
+
 }  // namespace
 
 AppMenuIconController::AppMenuIconController(Profile* profile,
                                              Delegate* delegate)
-    : profile_(profile), delegate_(delegate) {
+    : is_unstable_channel_(IsUnstableChannel()),
+      profile_(profile),
+      delegate_(delegate) {
   DCHECK(profile_);
   DCHECK(delegate_);
 
@@ -70,9 +105,9 @@
   if (ShouldShowUpgradeRecommended()) {
     UpgradeDetector::UpgradeNotificationAnnoyanceLevel level =
         UpgradeDetector::GetInstance()->upgrade_notification_stage();
-    delegate_->UpdateSeverity(IconType::UPGRADE_NOTIFICATION,
-                              SeverityFromUpgradeLevel(level),
-                              ShouldAnimateUpgradeLevel(level));
+    auto severity = SeverityFromUpgradeLevel(is_unstable_channel_, level);
+    delegate_->UpdateSeverity(IconType::UPGRADE_NOTIFICATION, severity,
+                              ShouldAnimateSeverity(severity));
     return;
   }
 
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.h b/chrome/browser/ui/toolbar/app_menu_icon_controller.h
index 583e3d4..b37afb7 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.h
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.h
@@ -67,6 +67,8 @@
   // UpgradeObserver:
   void OnUpgradeRecommended() override;
 
+  // True for desktop Chrome on dev and canary channels.
+  const bool is_unstable_channel_;
   Profile* profile_;
   Delegate* delegate_;
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 1f15f10..ce0c5c0 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -254,7 +254,6 @@
     } else {
       show_animation_->Show();
     }
-    SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
   }
 
   View* GetTooltipHandlerForPoint(const gfx::Point& point) override {
@@ -394,7 +393,6 @@
     SetInkDropMode(InkDropMode::ON);
     set_ink_drop_visible_opacity(kToolbarInkDropVisibleOpacity);
     SetFocusPainter(nullptr);
-    SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
   }
 
   // MenuButton:
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.cc b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
index 3d2b0db..fc173789 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
@@ -161,7 +161,7 @@
   // Kick off the Crostini Restart sequence. We will be added as an observer.
   restart_id_ = crostini::CrostiniManager::GetInstance()->RestartCrostini(
       profile_, kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
-      base::BindOnce(&CrostiniInstallerView::StartContainerFinished,
+      base::BindOnce(&CrostiniInstallerView::MountContainerFinished,
                      weak_ptr_factory_.GetWeakPtr()),
       this);
   return false;
@@ -253,6 +253,36 @@
   StepProgress();
 }
 
+void CrostiniInstallerView::OnContainerStarted(ConciergeClientResult result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  state_ = State::START_CONTAINER;
+  if (result != ConciergeClientResult::SUCCESS) {
+    LOG(ERROR) << "Failed to start container with error code: "
+               << static_cast<int>(result);
+    HandleError(
+        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR),
+        SetupResult::kErrorStartingContainer);
+    return;
+  }
+  VLOG(1) << "Started container successfully";
+  StepProgress();
+}
+
+void CrostiniInstallerView::OnSshKeysFetched(ConciergeClientResult result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  state_ = State::FETCH_SSH_KEYS;
+  if (result != ConciergeClientResult::SUCCESS) {
+    LOG(ERROR) << "Failed to fetch ssh keys with error code: "
+               << static_cast<int>(result);
+    HandleError(
+        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_ERROR),
+        SetupResult::kErrorFetchingSshKeys);
+    return;
+  }
+  VLOG(1) << "Fetched ssh keys successfully";
+  StepProgress();
+}
+
 // static
 CrostiniInstallerView* CrostiniInstallerView::GetActiveViewForTesting() {
   return g_crostini_installer_view;
@@ -375,16 +405,16 @@
   GetWidget()->GetRootView()->Layout();
 }
 
-void CrostiniInstallerView::StartContainerFinished(
+void CrostiniInstallerView::MountContainerFinished(
     ConciergeClientResult result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  state_ = State::START_CONTAINER;
+  state_ = State::MOUNT_CONTAINER;
   if (result != ConciergeClientResult::SUCCESS) {
-    LOG(ERROR) << "Failed to start container with error code: "
+    LOG(ERROR) << "Failed to mount container with error code: "
                << static_cast<int>(result);
     HandleError(
-        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR),
-        SetupResult::kErrorStartingContainer);
+        l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_ERROR),
+        SetupResult::kErrorMountingContainer);
     return;
   }
   StepProgress();
@@ -392,7 +422,7 @@
 }
 
 void CrostiniInstallerView::ShowLoginShell() {
-  DCHECK_EQ(state_, State::START_CONTAINER);
+  DCHECK_EQ(state_, State::MOUNT_CONTAINER);
   state_ = State::SHOW_LOGIN_SHELL;
 
   crostini::CrostiniManager::GetInstance()->LaunchContainerTerminal(
@@ -432,6 +462,10 @@
     message_id = IDS_CROSTINI_INSTALLER_START_TERMINA_VM_MESSAGE;
   } else if (state_ == State::START_TERMINA_VM) {
     message_id = IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE;
+  } else if (state_ == State::START_CONTAINER) {
+    message_id = IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_MESSAGE;
+  } else if (state_ == State::FETCH_SSH_KEYS) {
+    message_id = IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_MESSAGE;
   }
   if (message_id != 0) {
     message_label_->SetText(l10n_util::GetStringUTF16(message_id));
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.h b/chrome/browser/ui/views/crostini/crostini_installer_view.h
index 4b9ddab..c674c4a 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.h
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.h
@@ -44,6 +44,8 @@
     kErrorStartingTermina = 6,
     kErrorStartingContainer = 7,
     kErrorOffline = 8,
+    kErrorFetchingSshKeys = 9,
+    kErrorMountingContainer = 10,
     kCount
   };
 
@@ -66,6 +68,8 @@
   void OnConciergeStarted(crostini::ConciergeClientResult result) override;
   void OnDiskImageCreated(crostini::ConciergeClientResult result) override;
   void OnVmStarted(crostini::ConciergeClientResult result) override;
+  void OnContainerStarted(crostini::ConciergeClientResult result) override;
+  void OnSshKeysFetched(crostini::ConciergeClientResult result) override;
 
   static CrostiniInstallerView* GetActiveViewForTesting();
 
@@ -80,6 +84,8 @@
     CREATE_DISK_IMAGE,     // Creating the image for the Termina VM.
     START_TERMINA_VM,      // Starting the Termina VM.
     START_CONTAINER,       // Starting the container inside the Termina VM.
+    FETCH_SSH_KEYS,        // Fetch ssh keys from concierge.
+    MOUNT_CONTAINER,       // Do sshfs mount of container.
     SHOW_LOGIN_SHELL,      // Showing a new crosh window.
     INSTALL_END = SHOW_LOGIN_SHELL,  // Marker enum for last install state.
   };
@@ -88,7 +94,7 @@
   ~CrostiniInstallerView() override;
 
   void HandleError(const base::string16& error_message, SetupResult result);
-  void StartContainerFinished(crostini::ConciergeClientResult result);
+  void MountContainerFinished(crostini::ConciergeClientResult result);
   void ShowLoginShell();
   void StepProgress();
   void SetMessageLabel();
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc
index 147a2c4..e7838e8c 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc
@@ -17,8 +17,11 @@
 #include "chrome/browser/ui/views/crostini/crostini_browser_test_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_concierge_client.h"
+#include "chromeos/dbus/fake_cros_disks_client.h"
+#include "chromeos/disks/disk_mount_manager.h"
 #include "components/crx_file/id_util.h"
 #include "net/base/mock_network_change_notifier.h"
 #include "net/base/network_change_notifier_factory.h"
@@ -53,10 +56,37 @@
     base::OnceClosure closure_;
   };
 
+  class WaitingDiskMountManagerObserver
+      : public chromeos::disks::DiskMountManager::Observer {
+   public:
+    void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
+                      chromeos::MountError error_code,
+                      const chromeos::disks::DiskMountManager::MountPointInfo&
+                          mount_info) override {
+      run_loop_->Quit();
+    }
+
+    void WaitForMountEvent() {
+      chromeos::disks::DiskMountManager::GetInstance()->AddObserver(this);
+      run_loop_ = std::make_unique<base::RunLoop>();
+      run_loop_->Run();
+    }
+
+   private:
+    std::unique_ptr<base::RunLoop> run_loop_;
+  };
+
   CrostiniInstallerViewBrowserTest()
-      : waiting_fake_concierge_client_(new WaitingFakeConciergeClient()) {
+      : waiting_fake_concierge_client_(new WaitingFakeConciergeClient()),
+        waiting_disk_mount_manager_observer_(
+            new WaitingDiskMountManagerObserver) {
     chromeos::DBusThreadManager::GetSetterForTesting()->SetConciergeClient(
         base::WrapUnique(waiting_fake_concierge_client_));
+    static_cast<chromeos::FakeCrosDisksClient*>(
+        chromeos::DBusThreadManager::Get()->GetCrosDisksClient())
+        ->AddCustomMountPointCallback(base::BindRepeating(
+            &CrostiniInstallerViewBrowserTest::MaybeMountCrostini,
+            base::Unretained(this)));
   }
 
   // DialogBrowserTest:
@@ -80,8 +110,22 @@
  protected:
   // Owned by chromeos::DBusThreadManager
   WaitingFakeConciergeClient* waiting_fake_concierge_client_ = nullptr;
+  WaitingDiskMountManagerObserver* waiting_disk_mount_manager_observer_ =
+      nullptr;
 
  private:
+  base::FilePath MaybeMountCrostini(
+      const std::string& source_path,
+      const std::vector<std::string>& mount_options) {
+    GURL source_url(source_path);
+    DCHECK(source_url.is_valid());
+    if (source_url.scheme() != "sshfs") {
+      return {};
+    }
+    EXPECT_EQ("sshfs://stub-user@hostname:", source_path);
+    return base::FilePath(
+        browser()->profile()->GetPath().Append("crostini_test"));
+  }
   DISALLOW_COPY_AND_ASSIGN(CrostiniInstallerViewBrowserTest);
 };
 
@@ -106,7 +150,7 @@
   EXPECT_FALSE(HasAcceptButton());
   EXPECT_TRUE(HasCancelButton());
 
-  waiting_fake_concierge_client_->WaitForStartTerminaVmCalled();
+  waiting_disk_mount_manager_observer_->WaitForMountEvent();
 
   // RunUntilIdle in this case will run the rest of the install steps including
   // launching the terminal, on the UI thread.
diff --git a/chrome/browser/ui/views/frame/app_menu_button.cc b/chrome/browser/ui/views/frame/app_menu_button.cc
index 7a220b16..2946bc7b 100644
--- a/chrome/browser/ui/views/frame/app_menu_button.cc
+++ b/chrome/browser/ui/views/frame/app_menu_button.cc
@@ -10,12 +10,9 @@
 #include "chrome/browser/ui/views/toolbar/app_menu.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h"
 #include "ui/views/controls/menu/menu_listener.h"
-#include "ui/views/style/platform_style.h"
 
 AppMenuButton::AppMenuButton(views::MenuButtonListener* menu_button_listener)
-    : views::MenuButton(base::string16(), menu_button_listener, false) {
-  SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
-}
+    : views::MenuButton(base::string16(), menu_button_listener, false) {}
 
 AppMenuButton::~AppMenuButton() {}
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 0a35803a..e777a3c 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -246,6 +246,19 @@
          MD::IsRefreshUi() && ShouldPaintAsActive() && GetFrameImage().isNull();
 }
 
+bool BrowserNonClientFrameView::ShouldDrawStrokes() const {
+  if (!MD::IsRefreshUi())
+    return true;
+
+  // Refresh normally avoids strokes and relies on the active tab contrasting
+  // sufficiently with the frame background.  When there isn't enough contrast,
+  // fall back to a stroke.  Always compute the contrast ratio against the
+  // active frame color, to avoid toggling the stroke on and off as the window
+  // activation state changes.
+  return color_utils::GetContrastRatio(GetTabBackgroundColor(TAB_ACTIVE),
+                                       GetFrameColor(true)) < 1.3;
+}
+
 bool BrowserNonClientFrameView::ShouldPaintAsSingleTabMode() const {
   return browser_view()->IsTabStripVisible() &&
          browser_view()->tabstrip()->SingleTabMode();
@@ -367,7 +380,7 @@
 
 void BrowserNonClientFrameView::PaintToolbarTopStroke(
     gfx::Canvas* canvas) const {
-  if (browser_view()->tabstrip()->ShouldDrawStrokes()) {
+  if (ShouldDrawStrokes()) {
     gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
     gfx::Point toolbar_origin(toolbar_bounds.origin());
     ConvertPointToTarget(browser_view(), this, &toolbar_origin);
@@ -581,7 +594,11 @@
 }
 
 SkColor BrowserNonClientFrameView::GetThemeOrDefaultColor(int color_id) const {
-  return ShouldPaintAsThemed() ? GetThemeProvider()->GetColor(color_id)
-                               : ThemeProperties::GetDefaultColor(
-                                     color_id, browser_view_->IsIncognito());
+  // During shutdown, there may no longer be a widget, and thus no theme
+  // provider.
+  const auto* theme_provider = GetThemeProvider();
+  return ShouldPaintAsThemed() && theme_provider
+             ? theme_provider->GetColor(color_id)
+             : ThemeProperties::GetDefaultColor(color_id,
+                                                browser_view_->IsIncognito());
 }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 323b739..c58a01d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -131,6 +131,9 @@
   // many tabs there are right now.
   virtual bool IsSingleTabModeAvailable() const;
 
+  // Returns whether or not strokes should be drawn around and under the tabs.
+  virtual bool ShouldDrawStrokes() const;
+
   // views::NonClientFrameView:
   void ChildPreferredSizeChanged(views::View* child) override;
   void VisibilityChanged(views::View* starting_from, bool is_visible) override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
index 69c5df8c..5e14146 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -21,12 +21,6 @@
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/canvas.h"
 
-namespace {
-
-constexpr int kTabstripTopInset = 8;
-
-}  // namespace
-
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserNonClientFrameViewMac, public:
 
@@ -85,6 +79,11 @@
   if (!browser_view()->IsTabStripVisible())
     return 0;
 
+  // TODO(pkasting): https://crbug.com/862276  Increase this height when we
+  // can't extend the drag handle into the tabstrip.  Mac seems to reserve 1 DIP
+  // of this as resize handle, so the actual top drag height is 7 DIP.
+  constexpr int kTabstripTopInset = 8;
+
   // Calculate the y offset for the tab strip because in fullscreen mode the tab
   // strip may need to move under the slide down menu bar.
   CGFloat y_offset = kTabstripTopInset;
@@ -94,11 +93,12 @@
     CGFloat title_bar_height =
         NSHeight([NSWindow frameRectForContentRect:NSZeroRect
                                          styleMask:NSWindowStyleMaskTitled]);
-    y_offset +=
+    CGFloat added_height =
         [[fullscreen_toolbar_controller_ menubarTracker] menubarFraction] *
         (menu_bar_height + title_bar_height);
+    y_offset += added_height;
 
-    if (y_offset > kTabstripTopInset) {
+    if (added_height > 0) {
       // When menubar shows up, we need to update mouse tracking area.
       NSWindow* window = GetWidget()->GetNativeWindow();
       NSRect content_bounds = [[window contentView] bounds];
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 756c56e..1ea2e43b 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -224,6 +224,15 @@
          BrowserNonClientFrameView::IsSingleTabModeAvailable();
 }
 
+bool GlassBrowserFrameView::ShouldDrawStrokes() const {
+  // On Win 7, the tabs are drawn as flat shapes against the glass frame, so
+  // the active tab always has a visible shape and strokes are unnecessary.
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return false;
+
+  return BrowserNonClientFrameView::ShouldDrawStrokes();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // GlassBrowserFrameView, views::NonClientFrameView implementation:
 
@@ -488,6 +497,8 @@
   // TODO(bsep): This override has "dead zones" where you can't click on the
   // custom titlebar buttons. It's not clear why it's necessary at all.
   // Investigate tearing this out.
+  // TODO(pkasting): https://crbug.com/862276  This interferes with drag handle
+  // extension because we never run BrowserNonClientFrameView's code.
   CHECK_EQ(target, this);
   bool hit_incognito_icon =
       profile_indicator_icon() &&
@@ -533,6 +544,8 @@
   // not maximized or fullscreen. When maximized, the OS sizes the window such
   // that the border extends beyond the screen edges. In that case, we must
   // return the default value.
+  // TODO(pkasting): https://crbug.com/862276  Increase this height when we
+  // can't extend the drag handle into the tabstrip.
   if (MD::IsRefreshUi() &&
       ((!frame()->IsFullscreen() && !IsMaximized()) || restored)) {
     constexpr int kTopResizeFrameArea = 5;
@@ -777,6 +790,8 @@
 }
 
 void GlassBrowserFrameView::PaintClientEdge(gfx::Canvas* canvas) const {
+  DCHECK_LT(base::win::GetVersion(), base::win::VERSION_WIN10);
+
   // Draw the client edge images.
   gfx::Rect client_bounds = CalculateClientAreaBounds();
   const int x = client_bounds.x();
@@ -785,23 +800,22 @@
   const int bottom = std::max(y, height() - ClientBorderThickness(false));
 
   const ui::ThemeProvider* tp = GetThemeProvider();
-  if (base::win::GetVersion() < base::win::VERSION_WIN10) {
-    const gfx::ImageSkia* const right_image =
-        tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
-    const int img_w = right_image->width();
-    const int height = bottom - y;
-    canvas->TileImageInt(*right_image, right, y, img_w, height);
-    canvas->DrawImageInt(
-        *tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER), right, bottom);
-    const gfx::ImageSkia* const bottom_image =
-        tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
-    canvas->TileImageInt(*bottom_image, x, bottom, client_bounds.width(),
-                         bottom_image->height());
-    canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER),
-                         x - img_w, bottom);
-    canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE),
-                         x - img_w, y, img_w, height);
-  }
+  const gfx::ImageSkia* const right_image =
+      tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
+  const int img_w = right_image->width();
+  const int height = bottom - y;
+  canvas->TileImageInt(*right_image, right, y, img_w, height);
+  canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER),
+                       right, bottom);
+  const gfx::ImageSkia* const bottom_image =
+      tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
+  canvas->TileImageInt(*bottom_image, x, bottom, client_bounds.width(),
+                       bottom_image->height());
+  canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER),
+                       x - img_w, bottom);
+  canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE), x - img_w,
+                       y, img_w, height);
+
   FillClientEdgeRects(x, y, right, bottom,
                       tp->GetColor(ThemeProperties::COLOR_TOOLBAR), canvas);
 }
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index 1ed7fe6..5ccd6eb 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -43,6 +43,7 @@
   gfx::Size GetMinimumSize() const override;
   int GetTabStripLeftInset() const override;
   bool IsSingleTabModeAvailable() const override;
+  bool ShouldDrawStrokes() const override;
   void OnTabRemoved(int index) override;
   void OnTabsMaxXChanged() override;
 
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index e7346e8..02bcd13 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -511,11 +511,7 @@
           : 0;
   frame_background_->set_theme_image_y_inset(y_inset);
   frame_background_->set_theme_overlay_image(GetFrameOverlayImage());
-  const int visible_image_height = GetFrameImage().height() -
-                                   ThemeProperties::kFrameHeightAboveTabs +
-                                   GetTopInset(false);
-  frame_background_->set_top_area_height(
-      std::max(GetTopAreaHeight(), visible_image_height));
+  frame_background_->set_top_area_height(GetTopAreaHeight());
 
   if (layout_->IsTitleBarCondensed())
     PaintMaximizedFrameBorder(canvas);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index 4acb7a4..bba04eb 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -289,6 +289,8 @@
   // Besides the frame border, there's empty space atop the window in restored
   // mode, to use to drag the window around.
   constexpr int kNonClientRestoredExtraThickness = 11;
+  // TODO(pkasting): https://crbug.com/862276  Increase this height when we
+  // can't extend the drag handle into the tabstrip.
   constexpr int kRefreshNonClientRestoredExtraThickness = 4;
   return MD::IsRefreshUi() ? kRefreshNonClientRestoredExtraThickness
                            : kNonClientRestoredExtraThickness;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index f8be6ef..62dc813 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -25,7 +25,6 @@
 #include "ui/views/animation/ink_drop_ripple.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/image_view.h"
-#include "ui/views/style/platform_style.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -73,7 +72,7 @@
   // When using focus rings are visible we should hide the separator instantly
   // when the IconLabelBubbleView is focused. Otherwise we should follow the
   // inkdrop.
-  if (views::PlatformStyle::kPreferFocusRings && owner_->HasFocus()) {
+  if (owner_->focus_ring() && owner_->HasFocus()) {
     layer()->SetOpacity(0.0f);
     return;
   }
@@ -146,8 +145,6 @@
 
   // Flip the canvas in RTL so the separator is drawn on the correct side.
   separator_view_->EnableCanvasFlippingForRTLUI(true);
-
-  SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
 }
 
 IconLabelBubbleView::~IconLabelBubbleView() {
@@ -185,10 +182,6 @@
   return false;
 }
 
-bool IconLabelBubbleView::ShouldShowExtraInternalSpace() const {
-  return false;
-}
-
 double IconLabelBubbleView::WidthMultiplier() const {
   return 1.0;
 }
@@ -311,7 +304,7 @@
 std::unique_ptr<views::InkDrop> IconLabelBubbleView::CreateInkDrop() {
   std::unique_ptr<views::InkDropImpl> ink_drop =
       CreateDefaultFloodFillInkDropImpl();
-  ink_drop->SetShowHighlightOnFocus(!views::PlatformStyle::kPreferFocusRings);
+  ink_drop->SetShowHighlightOnFocus(!focus_ring());
   ink_drop->AddObserver(this);
   return std::move(ink_drop);
 }
@@ -435,7 +428,7 @@
     return 0;
 
   // Touch Optimized, Refresh, and Touch Refresh all have custom spacing values.
-  int default_spacing = 0;
+  int default_spacing;
   switch (ui::MaterialDesignController::GetMode()) {
     case ui::MaterialDesignController::MATERIAL_TOUCH_OPTIMIZED:
       default_spacing = 4;
@@ -452,8 +445,11 @@
           GetLayoutInsets(LOCATION_BAR_ICON_INTERIOR_PADDING).left();
   }
 
-  return default_spacing +
-         (ShouldShowExtraInternalSpace() ? GetPrefixedSeparatorWidth() : 0);
+  return default_spacing + GetExtraInternalSpacing();
+}
+
+int IconLabelBubbleView::GetExtraInternalSpacing() const {
+  return 0;
 }
 
 int IconLabelBubbleView::GetPrefixedSeparatorWidth() const {
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index ad55397..1192d0c 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -108,12 +108,6 @@
   // of whether the separator is shown or not.
   virtual bool ShouldShowExtraEndSpace() const;
 
-  // Returns true when additional padding equal to GetPrefixedSeparatorWidth()
-  // should be added between the icon and the label. This is useful in the case
-  // where it's required to align the label in the same position as text that
-  // would normally follow this view.
-  virtual bool ShouldShowExtraInternalSpace() const;
-
   // Returns a multiplier used to calculate the actual width of the view based
   // on its desired width.  This ranges from 0 for a zero-width view to 1 for a
   // full-width view and can be used to animate the width of the view.
@@ -162,15 +156,20 @@
 
   gfx::Size GetSizeForLabelWidth(int label_width) const;
 
- private:
-  // Spacing between the image and the label.
-  int GetInternalSpacing() const;
-
   // Returns the width taken by the separator stroke and the before-padding.
   // If the separator is not shown, and ShouldShowExtraEndSpace() is false,
   // this returns 0.
   int GetPrefixedSeparatorWidth() const;
 
+ private:
+  // Spacing between the image and the label.
+  int GetInternalSpacing() const;
+
+  // Subclasses that want extra spacing added to the internal spacing can
+  // override this method. This may be used when we want to align the label text
+  // to the suggestion text, like in the SelectedKeywordView.
+  virtual int GetExtraInternalSpacing() const;
+
   // Padding after the separator.
   int GetEndPadding() const;
 
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
index 8bb56e4..c46b1a72 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -49,10 +49,6 @@
   return location_bar_->GetColor(OmniboxPart::LOCATION_BAR_SELECTED_KEYWORD);
 }
 
-bool SelectedKeywordView::ShouldShowExtraInternalSpace() const {
-  return ui::MaterialDesignController::IsRefreshUi();
-}
-
 gfx::Size SelectedKeywordView::CalculatePreferredSize() const {
   // Height will be ignored by the LocationBarView.
   return GetSizeForLabelWidth(full_label_.GetPreferredSize().width());
@@ -102,6 +98,13 @@
   SetLabel(full_name);
 }
 
+int SelectedKeywordView::GetExtraInternalSpacing() const {
+  // MD Refresh needs more space to align the label text with suggestion text.
+  return ui::MaterialDesignController::IsRefreshUi()
+             ? 11
+             : GetPrefixedSeparatorWidth();
+}
+
 const char* SelectedKeywordView::GetClassName() const {
   return "SelectedKeywordView";
 }
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.h b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
index 9d992fa..861f9007 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.h
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
@@ -33,7 +33,6 @@
 
   // IconLabelBubbleView:
   SkColor GetTextColor() const override;
-  bool ShouldShowExtraInternalSpace() const override;
 
   // views::View:
   gfx::Size CalculatePreferredSize() const override;
@@ -48,6 +47,7 @@
 
  private:
   // IconLabelBubbleView:
+  int GetExtraInternalSpacing() const override;
   const char* GetClassName() const override;
 
   LocationBarView* location_bar_;
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
index 7945ad5..b74ab37d 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -45,8 +45,6 @@
       command_id_(command_id),
       active_(false),
       suppress_mouse_released_action_(false) {
-  if (views::PlatformStyle::kPreferFocusRings)
-    focus_ring_ = views::FocusRing::Install(this);
   SetBorder(views::CreateEmptyBorder(
       GetLayoutInsets(LOCATION_BAR_ICON_INTERIOR_PADDING)));
   if (ui::MaterialDesignController::IsNewerMaterialUi()) {
@@ -187,7 +185,7 @@
 std::unique_ptr<views::InkDrop> PageActionIconView::CreateInkDrop() {
   std::unique_ptr<views::InkDropImpl> ink_drop =
       CreateDefaultFloodFillInkDropImpl();
-  ink_drop->SetShowHighlightOnFocus(!views::PlatformStyle::kPreferFocusRings);
+  ink_drop->SetShowHighlightOnFocus(!focus_ring());
   return std::move(ink_drop);
 }
 
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.h b/chrome/browser/ui/views/page_action/page_action_icon_view.h
index e4ea8be..5dea466 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.h
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.h
@@ -15,7 +15,6 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/animation/ink_drop_host_view.h"
-#include "ui/views/controls/focus_ring.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -191,9 +190,6 @@
   // prevent the bubble from reshowing.
   bool suppress_mouse_released_action_;
 
-  // The focus ring used for this view.
-  std::unique_ptr<views::FocusRing> focus_ring_;
-
   DISALLOW_COPY_AND_ASSIGN(PageActionIconView);
 };
 
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 5d2bb849..9a11db5 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -77,6 +77,8 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/clip_recorder.h"
 #include "ui/compositor/paint_recorder.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
@@ -97,6 +99,7 @@
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/controls/webview/webview.h"
@@ -119,6 +122,12 @@
 // top/bottom or left/right of the menu items.
 constexpr int kMenuEdgeMargin = 16;
 
+// If the bubble is too large to fit on the screen, it still needs to be at
+// least this tall to show the default items. The default items is what a signed
+// in user with 1 profile sees: account name, autofill home and 3 profile
+// actions.
+constexpr int kMinimumScrollableContentHeight = 340;
+
 constexpr int kVerticalSpacing = 16;
 
 // Number of times the Dice sign-in promo illustration should be shown.
@@ -537,8 +546,15 @@
       break;
   }
 
+  views::ScrollView* scroll_view = new views::ScrollView;
+  scroll_view->set_hide_horizontal_scrollbar(true);
+  // TODO(https://crbug.com/871762): it's a workaround for the crash.
+  scroll_view->set_draw_overflow_indicator(false);
+  scroll_view->ClipHeightTo(0, GetMaxHeight());
+  scroll_view->SetContents(sub_view);
+
   layout->StartRow(1.0, 0);
-  layout->AddView(sub_view);
+  layout->AddView(scroll_view);
   if (GetBubbleFrameView()) {
     SizeToContents();
     // SizeToContents() will perform a layout, but only if the size changed.
@@ -1581,6 +1597,21 @@
   return incognito_available && !browser_->profile()->IsGuestSession();
 }
 
+int ProfileChooserView::GetMaxHeight() const {
+  gfx::Rect anchor_rect = GetAnchorRect();
+  gfx::Rect screen_space =
+      display::Screen::GetScreen()
+          ->GetDisplayNearestPoint(anchor_rect.CenterPoint())
+          .work_area();
+  int available_space = screen_space.bottom() - anchor_rect.bottom();
+#if defined(OS_WIN)
+  // On Windows the bubble can also be show to the top of the anchor.
+  available_space =
+      std::max(available_space, anchor_rect.y() - screen_space.y());
+#endif
+  return std::max(kMinimumScrollableContentHeight, available_space);
+}
+
 void ProfileChooserView::PostActionPerformed(
     ProfileMetrics::ProfileDesktopMenu action_performed) {
   ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_);
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.h b/chrome/browser/ui/views/profiles/profile_chooser_view.h
index 28d9c84..644d9410 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.h
@@ -175,6 +175,10 @@
 
   bool ShouldShowGoIncognito() const;
 
+  // Return maximal height for the view after which it becomes scrollable.
+  // TODO(crbug.com/870303): remove when a general solution is available.
+  int GetMaxHeight() const;
+
   // Clean-up done after an action was performed in the ProfileChooser.
   void PostActionPerformed(ProfileMetrics::ProfileDesktopMenu action_performed);
 
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc
index d52ea1ed..5bbf96d 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.cc
@@ -141,8 +141,9 @@
 
   switch (current_level) {
     case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
-      // While it's unexpected that the level could move back down to none, it's
-      // not a challenge to do the right thing.
+    case UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW:
+      // While it's unexpected that the level could move back down, it's not a
+      // challenge to do the right thing.
       CloseRelaunchNotification();
       break;
     case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
@@ -260,8 +261,10 @@
 void RelaunchNotificationController::CloseRelaunchNotification() {
   DCHECK_NE(last_notification_style_, NotificationStyle::kNone);
 
-  // Nothing needs to be closed if the annoyance level is none or critical.
+  // Nothing needs to be closed if the annoyance level is none, very low, or
+  // critical.
   if (last_level_ == UpgradeDetector::UPGRADE_ANNOYANCE_NONE ||
+      last_level_ == UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW ||
       last_level_ == UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL) {
     return;
   }
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h
index 87046f5..56d7097 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h
@@ -148,10 +148,9 @@
   // notification.
   NotificationStyle last_notification_style_;
 
-  // The last observed annoyance level for which a notification was shown. This
-  // member is unconditionally UPGRADE_ANNOYANCE_NONE when the controller is
-  // dormant (browser.relaunch_notification is 0). It is any other value only
-  // when a notification has been shown.
+  // The last observed annoyance level. This member is unconditionally
+  // UPGRADE_ANNOYANCE_NONE when the controller is dormant
+  // (browser.relaunch_notification is 0).
   UpgradeDetector::UpgradeNotificationAnnoyanceLevel last_level_;
 
   // The last observed high annoyance deadline.
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
index f8df22f..7ad1032 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
@@ -174,6 +174,8 @@
       upgrade_detector(), GetMockTickClock(), &mock_controller_delegate);
 
   fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  fake_upgrade_detector().BroadcastLevelChange(
       UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
   fake_upgrade_detector().BroadcastLevelChange(
       UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
@@ -185,7 +187,7 @@
 
 // With the browser.relaunch_notification preference set to 1, the controller
 // should be observing the UpgradeDetector and should show "Requested"
-// notifications on each level change.
+// notifications on each level change above "very low".
 TEST_F(RelaunchNotificationControllerTest, RecommendedByPolicy) {
   SetNotificationPref(1);
   ::testing::StrictMock<MockControllerDelegate> mock_controller_delegate;
@@ -193,10 +195,13 @@
   FakeRelaunchNotificationController controller(
       upgrade_detector(), GetMockTickClock(), &mock_controller_delegate);
 
-  // Nothing shown if the level is broadcast at NONE.
+  // Nothing shown if the level is broadcast at NONE or VERY_LOW.
   fake_upgrade_detector().BroadcastLevelChange(
       UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
   ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+  fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
 
   // Show for each level change, but not for repeat notifications.
   EXPECT_CALL(mock_controller_delegate, ShowRelaunchRecommendedBubble());
@@ -236,7 +241,22 @@
   FastForwardBy(upgrade_detector()->GetHighAnnoyanceLevelDelta());
   ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
 
-  // And closed if the level drops back to none.
+  // And closed if the level drops back to very low.
+  EXPECT_CALL(mock_controller_delegate, CloseWidget());
+  fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+  fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  // Back up to elevated brings the bubble back.
+  EXPECT_CALL(mock_controller_delegate, ShowRelaunchRecommendedBubble());
+  fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  // And it is closed if the level drops back to none.
   EXPECT_CALL(mock_controller_delegate, CloseWidget());
   fake_upgrade_detector().BroadcastLevelChange(
       UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
@@ -304,7 +324,7 @@
   ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
 }
 
-// Flipping the policy should have no effect when at level NONE
+// Flipping the policy should have no effect when at level NONE or VERY_LOW.
 TEST_F(RelaunchNotificationControllerTest, PolicyChangesNoUpgrade) {
   ::testing::StrictMock<MockControllerDelegate> mock_controller_delegate;
 
@@ -322,6 +342,22 @@
 
   SetNotificationPref(0);
   ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  SetNotificationPref(1);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  SetNotificationPref(2);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  SetNotificationPref(3);  // Bogus value!
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  SetNotificationPref(0);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
 }
 
 // Policy changes at an elevated level should show the appropriate notification.
@@ -422,6 +458,37 @@
   ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
 }
 
+// NotificationPeriod changes should do nothing at any policy setting when the
+// annoyance level is at very low.
+TEST_F(RelaunchNotificationControllerTest, VeryLowPeriodChange) {
+  ::testing::StrictMock<MockControllerDelegate> mock_controller_delegate;
+
+  FakeRelaunchNotificationController controller(
+      upgrade_detector(), GetMockTickClock(), &mock_controller_delegate);
+
+  fake_upgrade_detector().BroadcastLevelChange(
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  // Reduce the period.
+  fake_upgrade_detector().BroadcastHighThresholdChange(
+      base::TimeDelta::FromDays(1));
+  FastForwardBy(fake_upgrade_detector().high_threshold());
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  SetNotificationPref(1);
+  fake_upgrade_detector().BroadcastHighThresholdChange(
+      base::TimeDelta::FromHours(23));
+  FastForwardBy(fake_upgrade_detector().high_threshold());
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+
+  SetNotificationPref(2);
+  fake_upgrade_detector().BroadcastHighThresholdChange(
+      base::TimeDelta::FromHours(22));
+  FastForwardBy(fake_upgrade_detector().high_threshold());
+  ::testing::Mock::VerifyAndClear(&mock_controller_delegate);
+}
+
 // NotificationPeriod changes impact reshows of the relaunch recommended bubble.
 TEST_F(RelaunchNotificationControllerTest, PeriodChangeRecommended) {
   SetNotificationPref(1);
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 0d8d70e..012daf29 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -366,6 +366,10 @@
   return GetFrameView()->IsSingleTabModeAvailable();
 }
 
+bool BrowserTabStripController::ShouldDrawStrokes() const {
+  return GetFrameView()->ShouldDrawStrokes();
+}
+
 void BrowserTabStripController::OnStartedDraggingTabs() {
   if (!immersive_reveal_lock_.get()) {
     // The top-of-window views should be revealed while the user is dragging
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
index 2b8c0b36..7dcc9c0 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -73,6 +73,7 @@
   bool IsIncognito() override;
   void StackedLayoutMaybeChanged() override;
   bool IsSingleTabModeAvailable() override;
+  bool ShouldDrawStrokes() const override;
   void OnStartedDraggingTabs() override;
   void OnStoppedDraggingTabs() override;
   SkColor GetFrameColor() const override;
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index e05a787..06323d5 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -140,6 +140,10 @@
   return false;
 }
 
+bool FakeBaseTabStripController::ShouldDrawStrokes() const {
+  return false;
+}
+
 void FakeBaseTabStripController::OnStartedDraggingTabs() {
 }
 
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
index e5fafd7..f7acb66 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -49,6 +49,7 @@
   bool IsIncognito() override;
   void StackedLayoutMaybeChanged() override;
   bool IsSingleTabModeAvailable() override;
+  bool ShouldDrawStrokes() const override;
   void OnStartedDraggingTabs() override;
   void OnStoppedDraggingTabs() override;
   SkColor GetFrameColor() const override;
diff --git a/chrome/browser/ui/views/tabs/glow_hover_controller.cc b/chrome/browser/ui/views/tabs/glow_hover_controller.cc
index d0af8b41..2dcf1d4 100644
--- a/chrome/browser/ui/views/tabs/glow_hover_controller.cc
+++ b/chrome/browser/ui/views/tabs/glow_hover_controller.cc
@@ -6,7 +6,9 @@
 
 #include "ui/views/view.h"
 
-// Amount to scale the opacity.
+// Amount to scale the opacity. The spec is in terms of a Sketch radial gradient
+// from color A (#FFF, 0.9) at center to color B (#FFF, 0.0) at edge, with a
+// gradient opacity of 0.5. So this premultiplies for a center opacity of 0.45.
 static const double kSubtleOpacityScale = 0.45;
 static const double kPronouncedOpacityScale = 1.0;
 
@@ -14,7 +16,10 @@
 static const int kTrackHoverDurationMs = 200;
 
 GlowHoverController::GlowHoverController(views::View* view)
-    : view_(view), animation_(this), opacity_scale_(kSubtleOpacityScale) {
+    : view_(view),
+      animation_(this),
+      opacity_scale_(kSubtleOpacityScale),
+      subtle_opacity_scale_(kSubtleOpacityScale) {
   animation_.set_delegate(this);
 }
 
@@ -31,10 +36,14 @@
     view_->SchedulePaint();
 }
 
+void GlowHoverController::SetSubtleOpacityScale(double opacity_scale) {
+  subtle_opacity_scale_ = opacity_scale;
+}
+
 void GlowHoverController::Show(Style style) {
   switch (style) {
     case SUBTLE:
-      opacity_scale_ = kSubtleOpacityScale;
+      opacity_scale_ = subtle_opacity_scale_;
       animation_.SetSlideDuration(kTrackHoverDurationMs);
       animation_.SetTweenType(gfx::Tween::EASE_OUT);
       animation_.Show();
diff --git a/chrome/browser/ui/views/tabs/glow_hover_controller.h b/chrome/browser/ui/views/tabs/glow_hover_controller.h
index 5045dc8..7fcc29d 100644
--- a/chrome/browser/ui/views/tabs/glow_hover_controller.h
+++ b/chrome/browser/ui/views/tabs/glow_hover_controller.h
@@ -39,6 +39,9 @@
   // constructor.
   void SetLocation(const gfx::Point& location);
 
+  // Set opacity scale to use when Show is called with SUBTLE.
+  void SetSubtleOpacityScale(double opacity_scale);
+
   const gfx::Point& location() const { return location_; }
 
   // Initiates showing the hover.
@@ -73,6 +76,7 @@
   // Location of the glow, relative to view.
   gfx::Point location_;
   double opacity_scale_;
+  double subtle_opacity_scale_;
 
   DISALLOW_COPY_AND_ASSIGN(GlowHoverController);
 };
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index 0b619643..40ce088 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -109,7 +109,7 @@
     set_ink_drop_visible_opacity(0.08f);
 
     SetFocusPainter(nullptr);
-    focus_ring_ = views::FocusRing::Install(this);
+    SetInstallFocusRingOnFocus(true);
   }
 
   // In newer material UI, the button is placed vertically exactly in the
@@ -346,7 +346,7 @@
 
     SkPath path;
     path.addOval(gfx::RectToSkRect(contents_bounds));
-    focus_ring_->SetPath(path);
+    focus_ring()->SetPath(path);
   }
 }
 
@@ -417,6 +417,9 @@
   const gfx::Rect contents_bounds = GetContentsBounds();
 
   if (MD::IsRefreshUi()) {
+    // TODO(pkasting): This should really be a circle with (potentially) its top
+    // half extended rectangularly upward... try to reuse
+    // GetTouchOptimizedButtonPath().
     path->addRect(0, extend_to_top ? 0 : button_y,
                   contents_bounds.width() * scale,
                   button_y + contents_bounds.height() * scale);
@@ -470,7 +473,7 @@
       }
 
       const bool succeeded = canvas->InitPaintFlagsForTiling(
-          *tp->GetImageSkiaNamed(bg_id), x, GetContentsBounds().y() + offset_y,
+          *tp->GetImageSkiaNamed(bg_id), x, contents_bounds.y() + offset_y,
           x_scale * scale, scale, 0, 0, SkShader::kRepeat_TileMode,
           SkShader::kRepeat_TileMode, &flags);
       DCHECK(succeeded);
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h
index 3c64fea..f4326ea8 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.h
+++ b/chrome/browser/ui/views/tabs/new_tab_button.h
@@ -9,7 +9,6 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "ui/views/controls/button/image_button.h"
-#include "ui/views/controls/focus_ring.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -166,9 +165,6 @@
   // open and get called back when it closes.
   ScopedObserver<views::Widget, WidgetObserver> new_tab_promo_observer_{this};
 
-  // The FocusRing for this new tab button.
-  std::unique_ptr<views::FocusRing> focus_ring_;
-
   DISALLOW_COPY_AND_ASSIGN(NewTabButton);
 };
 
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 58a4c7db..3c4234af 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -478,21 +478,6 @@
   return path;
 }
 
-float Lerp(float v0, float v1, float t) {
-  return v0 + (v1 - v0) * t;
-}
-
-// Produces lerp parameter from a range and value within the range, then uses
-// it to Lerp from v0 to v1.
-float LerpFromRange(float v0,
-                    float v1,
-                    float range_start,
-                    float range_end,
-                    float value_in_range) {
-  const float t = (value_in_range - range_start) / (range_end - range_start);
-  return Lerp(v0, v1, t);
-}
-
 }  // namespace
 
 // Tab -------------------------------------------------------------------------
@@ -551,6 +536,8 @@
   title_animation_.SetContainer(animation_container_.get());
 
   hover_controller_.SetAnimationContainer(animation_container_.get());
+
+  UpdateOpacities();
 }
 
 Tab::~Tab() {
@@ -865,6 +852,7 @@
 
 void Tab::OnMouseEntered(const ui::MouseEvent& event) {
   mouse_hovered_ = true;
+  hover_controller_.SetSubtleOpacityScale(radial_highlight_opacity_);
   hover_controller_.Show(GlowHoverController::SUBTLE);
   Layout();
 }
@@ -980,6 +968,12 @@
 
 void Tab::OnThemeChanged() {
   OnButtonColorMaybeChanged();
+  UpdateOpacities();
+}
+
+void Tab::SetClosing(bool closing) {
+  closing_ = closing;
+  ActiveStateChanged();
 }
 
 SkColor Tab::GetAlertIndicatorColor(TabAlertState state) const {
@@ -1673,13 +1667,16 @@
 
   // Wrapping in closure to only compute offset when needed (animate or hover).
   const auto offset = [=] {
-    // Opacity boost varies on tab width.
-    constexpr float kHoverOpacityMin = 0.5f;
-    constexpr float kHoverOpacityMax = 0.65f;
-    const float hoverOpacity = LerpFromRange(
-        kHoverOpacityMin, kHoverOpacityMax, float{GetStandardWidth()},
-        float{GetMinimumInactiveWidth()}, float{bounds().width()});
-    return is_selected ? (kSelectedTabThrobScale * hoverOpacity) : hoverOpacity;
+    // Opacity boost varies on tab width.  The interpolation is nonlinear so
+    // that most tabs will fall on the low end of the opacity range, but very
+    // narrow tabs will still stand out on the high end.
+    const float range_start = float{GetStandardWidth()};
+    const float range_end = float{GetMinimumInactiveWidth()};
+    const float value_in_range = float{bounds().width()};
+    const float t = (value_in_range - range_start) / (range_end - range_start);
+    const float opacity = gfx::Tween::FloatValueBetween(
+        t * t, hover_opacity_min_, hover_opacity_max_);
+    return is_selected ? (kSelectedTabThrobScale * opacity) : opacity;
   };
 
   if (pulse_animation_.is_animating())
@@ -1711,11 +1708,7 @@
     title_->SetEnabledColor(title_color);
     alert_indicator_button_->OnParentTabButtonColorChanged();
   }
-  SkColor icon_color =
-      MD::GetMode() == ui::MaterialDesignController::MATERIAL_TOUCH_OPTIMIZED
-          ? GetCloseTabButtonColor(views::Button::STATE_NORMAL)
-          : button_color_;
-  close_button_->SetIconColors(icon_color);
+  UpdateCloseButtonColors(title_color);
 }
 
 void Tab::UpdateTabIconNeedsAttentionBlocked() {
@@ -1730,5 +1723,95 @@
   }
 }
 
+void Tab::UpdateOpacities() {
+  // The contrast ratio for the hover effect on standard-width tabs.
+  // In the default Refresh color scheme, this corresponds to a hover
+  // opacity of 0.4.
+  constexpr float kDesiredContrastHoveredStandardWidthTab = 1.11f;
+
+  // The contrast ratio for the hover effect on min-width tabs.
+  // In the default Refresh color scheme, this corresponds to a hover
+  // opacity of 0.65.
+  constexpr float kDesiredContrastHoveredMinWidthTab = 1.19f;
+
+  // The contrast ratio for the radial gradient effect on hovered tabs.
+  // In the default Refresh color scheme, this corresponds to a hover
+  // opacity of 0.45.
+  constexpr float kDesiredContrastRadialGradient = 1.13728f;
+
+  const SkColor active_tab_bg_color =
+      controller_->GetTabBackgroundColor(TAB_ACTIVE);
+  const SkColor inactive_tab_bg_color =
+      controller_->GetTabBackgroundColor(TAB_INACTIVE);
+
+  const SkAlpha hover_base_alpha_wide =
+      color_utils::GetBlendValueWithMinimumContrast(
+          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
+          kDesiredContrastHoveredStandardWidthTab);
+  const SkAlpha hover_base_alpha_narrow =
+      color_utils::GetBlendValueWithMinimumContrast(
+          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
+          kDesiredContrastHoveredMinWidthTab);
+  const SkAlpha radial_highlight_alpha =
+      color_utils::GetBlendValueWithMinimumContrast(
+          inactive_tab_bg_color, active_tab_bg_color, inactive_tab_bg_color,
+          kDesiredContrastRadialGradient);
+
+  hover_opacity_min_ = hover_base_alpha_wide / 255.0f;
+  hover_opacity_max_ = hover_base_alpha_narrow / 255.0f;
+  radial_highlight_opacity_ = radial_highlight_alpha / 255.0f;
+}
+
+void Tab::UpdateCloseButtonColors(SkColor title_color) {
+  // These ratios are calculated from the default colors specified in the
+  // Material Refresh design document. Active/inactive are the contrast ratios
+  // of the close X against the tab background. Hovered/pressed are the contrast
+  // ratios of the highlight circle against the tab background.
+  constexpr float kMinimumActiveContrastRatio = 6.05f;
+  constexpr float kMinimumInactiveContrastRatio = 4.61f;
+  constexpr float kMinimumHoveredContrastRatio = 5.02f;
+  constexpr float kMinimumPressedContrastRatio = 4.41f;
+
+  const SkColor tab_bg_color = controller_->GetTabBackgroundColor(
+      IsActive() ? TAB_ACTIVE : TAB_INACTIVE);
+  const SkColor base_icon_color =
+      MD::GetMode() == ui::MaterialDesignController::MATERIAL_TOUCH_OPTIMIZED
+          ? GetCloseTabButtonColor(views::Button::STATE_NORMAL)
+          : title_color;
+  const SkColor base_hovered_pressed_icon_color =
+      MD::IsNewerMaterialUi() ? base_icon_color : SK_ColorWHITE;
+  const SkColor base_hovered_color =
+      GetCloseTabButtonColor(views::Button::STATE_HOVERED);
+  const SkColor base_pressed_color =
+      GetCloseTabButtonColor(views::Button::STATE_PRESSED);
+
+  const auto get_color_for_contrast_ratio = [](SkColor fg_color,
+                                               SkColor bg_color,
+                                               float contrast_ratio) {
+    const SkAlpha blend_alpha = color_utils::GetBlendValueWithMinimumContrast(
+        bg_color, fg_color, bg_color, contrast_ratio);
+    return color_utils::AlphaBlend(fg_color, bg_color, blend_alpha);
+  };
+
+  const SkColor generated_icon_color = get_color_for_contrast_ratio(
+      base_icon_color, tab_bg_color,
+      IsActive() ? kMinimumActiveContrastRatio : kMinimumInactiveContrastRatio);
+  const SkColor generated_hovered_color = get_color_for_contrast_ratio(
+      base_hovered_color, tab_bg_color, kMinimumHoveredContrastRatio);
+  const SkColor generated_pressed_color = get_color_for_contrast_ratio(
+      base_pressed_color, tab_bg_color, kMinimumPressedContrastRatio);
+
+  const SkColor generated_hovered_icon_color =
+      color_utils::GetColorWithMinimumContrast(base_hovered_pressed_icon_color,
+                                               generated_hovered_color);
+  const SkColor generated_pressed_icon_color =
+      color_utils::GetColorWithMinimumContrast(base_hovered_pressed_icon_color,
+                                               generated_pressed_color);
+  close_button_->SetIconColors(
+      generated_icon_color, generated_hovered_icon_color,
+      generated_pressed_icon_color, generated_hovered_color,
+      generated_pressed_color);
+}
+
 Tab::BackgroundCache::BackgroundCache() = default;
 Tab::BackgroundCache::~BackgroundCache() = default;
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 8068e7a..3ace9b4c 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -108,7 +108,7 @@
   TabController* controller() const { return controller_; }
 
   // Used to set/check whether this Tab is being animated closed.
-  void set_closing(bool closing) { closing_ = closing; }
+  void SetClosing(bool closing);
   bool closing() const { return closing_; }
 
   // See description above field.
@@ -310,6 +310,12 @@
   // state; it is the responsibility of the caller to request a paint.
   void UpdateTabIconNeedsAttentionBlocked();
 
+  // Computes and stores opacities derived from contrast ratios.
+  void UpdateOpacities();
+
+  // Generate and update close button colors for proper contrast.
+  void UpdateCloseButtonColors(SkColor title_color);
+
   // The controller, never NULL.
   TabController* const controller_;
 
@@ -383,6 +389,11 @@
   // the view bounds.
   bool mouse_hovered_ = false;
 
+  // These computed values are stored for fast use during mouse moves & hover.
+  float hover_opacity_min_;
+  float hover_opacity_max_;
+  float radial_highlight_opacity_;
+
   class BackgroundCache {
    public:
     BackgroundCache();
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.cc b/chrome/browser/ui/views/tabs/tab_close_button.cc
index 336ec40..ded9d87 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_close_button.cc
@@ -21,11 +21,10 @@
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/rect_based_targeting_utils.h"
-#include "ui/views/style/platform_style.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
@@ -33,6 +32,11 @@
 
 using MD = ui::MaterialDesignController;
 
+namespace {
+constexpr int kGlyphWidth = 16;
+constexpr int kTouchGlyphWidth = 24;
+}  //  namespace
+
 TabCloseButton::TabCloseButton(views::ButtonListener* listener,
                                MouseEventCallback mouse_event_callback)
     : views::ImageButton(listener),
@@ -42,7 +46,6 @@
   // Disable animation so that the red danger sign shows up immediately
   // to help avoid mis-clicks.
   SetAnimationDuration(0);
-  SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
 
   if (focus_ring())
     SetFocusPainter(nullptr);
@@ -52,14 +55,19 @@
 
 // static
 int TabCloseButton::GetWidth() {
-  const gfx::VectorIcon& close_icon = MD::IsTouchOptimizedUiEnabled()
-                                          ? kTabCloseButtonTouchIcon
-                                          : kTabCloseNormalIcon;
-  return gfx::GetDefaultSizeOfVectorIcon(close_icon);
+  return MD::IsTouchOptimizedUiEnabled() ? kTouchGlyphWidth : kGlyphWidth;
 }
 
-void TabCloseButton::SetIconColors(SkColor color) {
-  GenerateImages(color, MD::IsNewerMaterialUi() ? color : SK_ColorWHITE);
+void TabCloseButton::SetIconColors(SkColor icon_color,
+                                   SkColor hovered_icon_color,
+                                   SkColor pressed_icon_color,
+                                   SkColor hovered_color,
+                                   SkColor pressed_color) {
+  icon_colors_[views::Button::STATE_NORMAL] = icon_color;
+  icon_colors_[views::Button::STATE_HOVERED] = hovered_icon_color;
+  icon_colors_[views::Button::STATE_PRESSED] = pressed_icon_color;
+  highlight_colors_[views::Button::STATE_HOVERED] = hovered_color;
+  highlight_colors_[views::Button::STATE_PRESSED] = pressed_color;
 }
 
 views::View* TabCloseButton::GetTooltipHandlerForPoint(
@@ -114,20 +122,10 @@
 void TabCloseButton::PaintButtonContents(gfx::Canvas* canvas) {
   canvas->SaveLayerAlpha(GetOpacity());
   ButtonState button_state = state();
-  if (button_state != views::Button::STATE_NORMAL) {
-    // Draw the background circle highlight.
-    gfx::Path path;
-    SkColor background_color =
-        static_cast<Tab*>(parent())->GetCloseTabButtonColor(button_state);
-    gfx::Point center = GetContentsBounds().CenterPoint();
-    path.setFillType(SkPath::kEvenOdd_FillType);
-    path.addCircle(center.x(), center.y(), GetWidth() / 2);
-    cc::PaintFlags flags;
-    flags.setAntiAlias(true);
-    flags.setColor(background_color);
-    canvas->DrawPath(path, flags);
-  }
-  views::ImageButton::PaintButtonContents(canvas);
+  // Draw the background circle highlight.
+  if (button_state != views::Button::STATE_NORMAL)
+    DrawHighlight(canvas, button_state);
+  DrawCloseGlyph(canvas, button_state);
   canvas->Restore();
 }
 
@@ -164,6 +162,32 @@
   return true;
 }
 
+void TabCloseButton::DrawHighlight(gfx::Canvas* canvas, ButtonState state) {
+  gfx::Path path;
+  gfx::Point center = GetContentsBounds().CenterPoint();
+  path.setFillType(SkPath::kEvenOdd_FillType);
+  path.addCircle(center.x(), center.y(), GetWidth() / 2);
+  cc::PaintFlags flags;
+  flags.setAntiAlias(true);
+  flags.setColor(highlight_colors_[state]);
+  canvas->DrawPath(path, flags);
+}
+
+void TabCloseButton::DrawCloseGlyph(gfx::Canvas* canvas, ButtonState state) {
+  cc::PaintFlags flags;
+  constexpr float kStrokeWidth = 1.5f;
+  float touch_scale = float{GetWidth()} / kGlyphWidth;
+  float size = (kGlyphWidth - 8) * touch_scale - kStrokeWidth;
+  gfx::RectF glyph_bounds(GetContentsBounds());
+  glyph_bounds.ClampToCenteredSize(gfx::SizeF(size, size));
+  flags.setAntiAlias(true);
+  flags.setStrokeWidth(kStrokeWidth);
+  flags.setStrokeCap(cc::PaintFlags::kRound_Cap);
+  flags.setColor(icon_colors_[state]);
+  canvas->DrawLine(glyph_bounds.origin(), glyph_bounds.bottom_right(), flags);
+  canvas->DrawLine(glyph_bounds.bottom_left(), glyph_bounds.top_right(), flags);
+}
+
 SkAlpha TabCloseButton::GetOpacity() {
   Tab* tab = static_cast<Tab*>(parent());
   if (base::FeatureList::IsEnabled(features::kCloseButtonsInactiveTabs) ||
@@ -173,19 +197,3 @@
   return gfx::Tween::IntValueBetween(animation_value, SK_AlphaTRANSPARENT,
                                      SK_AlphaOPAQUE);
 }
-
-void TabCloseButton::GenerateImages(SkColor normal_icon_color,
-                                    SkColor hover_pressed_icon_color) {
-  const gfx::VectorIcon& button_icon = MD::IsTouchOptimizedUiEnabled()
-                                           ? kTabCloseButtonTouchIcon
-                                           : kTabCloseNormalIcon;
-  const gfx::ImageSkia normal =
-      gfx::CreateVectorIcon(button_icon, normal_icon_color);
-  const gfx::ImageSkia hover_pressed =
-      normal_icon_color != hover_pressed_icon_color
-          ? gfx::CreateVectorIcon(button_icon, hover_pressed_icon_color)
-          : normal;
-  SetImage(views::Button::STATE_NORMAL, normal);
-  SetImage(views::Button::STATE_HOVERED, hover_pressed);
-  SetImage(views::Button::STATE_PRESSED, hover_pressed);
-}
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.h b/chrome/browser/ui/views/tabs/tab_close_button.h
index 3124f16..499e7cd 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.h
+++ b/chrome/browser/ui/views/tabs/tab_close_button.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_CLOSE_BUTTON_H_
 
 #include "base/callback_forward.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/masked_targeter_delegate.h"
 
@@ -31,10 +32,14 @@
   static int GetWidth();
 
   // This function must be called before the tab is painted so it knows what
-  // color to use. It must also be called when the background color of the tab
+  // colors to use. It must also be called when the background color of the tab
   // changes (this class does not track tab activation state), and when the
   // theme changes.
-  void SetIconColors(SkColor color);
+  void SetIconColors(SkColor icon_color,
+                     SkColor hovered_icon_color,
+                     SkColor pressed_icon_color,
+                     SkColor hovered_color,
+                     SkColor pressed_color);
 
   // views::View:
   View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
@@ -53,15 +58,21 @@
   views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
   bool GetHitTestMask(gfx::Path* mask) const override;
 
+  // Draw the highlight circle.
+  void DrawHighlight(gfx::Canvas* canvas, ButtonState state);
+
+  // Draw the close "X" glyph.
+  void DrawCloseGlyph(gfx::Canvas* canvas, ButtonState state);
+
   // In material refresh mode, calculates opacity based on the current state of
   // the hover animation on the parent tab.
   SkAlpha GetOpacity();
 
-  void GenerateImages(SkColor normal_icon_color,
-                      SkColor hover_pressed_icon_color);
-
   MouseEventCallback mouse_event_callback_;
 
+  SkColor icon_colors_[views::Button::STATE_PRESSED + 1];
+  SkColor highlight_colors_[views::Button::STATE_PRESSED + 1];
+
   DISALLOW_COPY_AND_ASSIGN(TabCloseButton);
 };
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index ed07e0a..4cfe393 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -333,41 +333,37 @@
 }
 
 bool TabStrip::IsRectInWindowCaption(const gfx::Rect& rect) {
-  views::View* v = GetEventHandlerForRect(rect);
-
-  // If there is no control at this location, claim the hit was in the title
-  // bar to get a move action.
+  // If there is no control at this location, the hit is in the caption area.
+  const views::View* v = GetEventHandlerForRect(rect);
   if (v == this)
     return true;
 
-  // Set the hit test overlap to 1 dip above the top edge of the tab separator.
-  const int inactive_tab_hit_test_overlap =
+  // Under refresh, a thin strip at the top of inactive tabs and the new tab
+  // button is treated as part of the window drag handle, to increase
+  // draggability.  This region starts 1 DIP above the top of the separator.
+  const int drag_handle_extension =
       (height() - Tab::GetTabSeparatorHeight()) / 2 - 1;
-  // If there is a tab at this location, this hit is not likely in the title
-  // bar, except under the conditions below.
+  // TODO(pkasting): https://crbug.com/862276  Set this condition false when tab
+  // shapes are visible.
+  const bool extend_drag_handle =
+      MD::IsRefreshUi() && !SizeTabButtonToTopOfTabStrip();
+
+  // A hit on the tab is not in the caption unless it is in the thin strip
+  // mentioned above.
   const int tab_index = tabs_.GetIndexOfView(v);
   if (IsValidModelIndex(tab_index)) {
     Tab* tab = tab_at(tab_index);
-    // Under refresh, a 7 dip area at the top of an inactive tab should be
-    // considered part of the window caption. This makes the window drag region
-    // a little larger which makes it easier to target.
-    if (MD::IsRefreshUi() && !SizeTabButtonToTopOfTabStrip() &&
-        !tab->IsActive()) {
-      return gfx::Rect(tab->bounds().origin(),
-                       gfx::Size(tab->width(), inactive_tab_hit_test_overlap))
-          .Intersects(rect);
-    }
-    return false;
+    gfx::Rect tab_drag_handle = tab->bounds();
+    tab_drag_handle.set_height(drag_handle_extension);
+    return extend_drag_handle && !tab->IsActive() &&
+           tab_drag_handle.Intersects(rect);
   }
 
-  // Under refresh, check if the rect intersects a thin 7 dip strip along the
-  // top of the new tab button. This also makes the window drag region above the
-  // new tab button a little larger for ease of window dragging.
-  if (MD::IsRefreshUi() && !SizeTabButtonToTopOfTabStrip() &&
-      gfx::Rect(
-          new_tab_button_->bounds().origin(),
-          gfx::Size(new_tab_button_->width(), inactive_tab_hit_test_overlap))
-          .Intersects(rect))
+  // Similarly, a hit in the new tab button is considered to be in the caption
+  // if it's in this thin strip.
+  gfx::Rect new_tab_button_drag_handle = new_tab_button_->bounds();
+  new_tab_button_drag_handle.set_height(drag_handle_extension);
+  if (extend_drag_handle && new_tab_button_drag_handle.Intersects(rect))
     return true;
 
   // Check to see if the rect intersects the non-button parts of the new tab
@@ -377,14 +373,8 @@
   View::ConvertRectToTarget(this, new_tab_button_, &rect_in_new_tab_coords_f);
   gfx::Rect rect_in_new_tab_coords =
       gfx::ToEnclosingRect(rect_in_new_tab_coords_f);
-  if (new_tab_button_->GetLocalBounds().Intersects(rect_in_new_tab_coords) &&
-      !new_tab_button_->HitTestRect(rect_in_new_tab_coords))
-    return true;
-
-  // All other regions, including the new Tab button, should be considered part
-  // of the containing Window's client area so that regular events can be
-  // processed for them.
-  return false;
+  return new_tab_button_->GetLocalBounds().Intersects(rect_in_new_tab_coords) &&
+         !new_tab_button_->HitTestRect(rect_in_new_tab_coords);
 }
 
 bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
@@ -582,7 +572,7 @@
     PrepareForAnimation();
 
   Tab* tab = tab_at(model_index);
-  tab->set_closing(true);
+  tab->SetClosing(true);
 
   int old_x = tabs_.ideal_bounds(model_index).x();
   RemoveTabFromViewModel(model_index);
@@ -847,17 +837,6 @@
     DoLayout();
 }
 
-bool TabStrip::ShouldDrawStrokes() const {
-  if (!MD::IsRefreshUi())
-    return true;
-
-  // Refresh normally avoids strokes and relies on the active tab contrasting
-  // sufficiently with the frame background.  When there isn't enough contrast,
-  // fall back to a stroke.
-  return color_utils::GetContrastRatio(GetTabBackgroundColor(TAB_ACTIVE),
-                                       controller_->GetFrameColor()) < 1.3;
-}
-
 const ui::ListSelectionModel& TabStrip::GetSelectionModel() const {
   return controller_->GetSelectionModel();
 }
@@ -1144,7 +1123,7 @@
 }
 
 int TabStrip::GetStrokeThickness() const {
-  return ShouldDrawStrokes() ? 1 : 0;
+  return controller_->ShouldDrawStrokes() ? 1 : 0;
 }
 
 bool TabStrip::CanPaintThrobberToLayer() const {
@@ -1238,21 +1217,23 @@
     // of hovered background tabs due to the painting order. This manifests as
     // the lower left curve the tab being visibly overwritten. This code detects
     // the hovered cases and defers painting of the given tab to below.
-    auto check_hovered_or_paint = [&paint_info, &hovered_tab,
-                                   &hovered_tabs](Tab* tab) {
-      if (MD::IsRefreshUi() && tab->mouse_hovered())
-        hovered_tab = tab;
-      else if (MD::IsRefreshUi() && tab->hover_controller()->ShouldDraw())
-        hovered_tabs.push_back(tab);
-      else
-        tab->Paint(paint_info);
-    };
+    const auto check_hovered_selected_or_paint =
+        [&paint_info, &hovered_tab, &hovered_tabs, &selected_tabs](Tab* tab) {
+          if (MD::IsRefreshUi() && tab->mouse_hovered())
+            hovered_tab = tab;
+          else if (MD::IsRefreshUi() && tab->hover_controller()->ShouldDraw())
+            hovered_tabs.push_back(tab);
+          else if (tab->IsSelected())
+            selected_tabs.push_back(tab);
+          else
+            tab->Paint(paint_info);
+        };
 
-    auto paint_closing_tabs = [=](int index) {
+    const auto paint_closing_tabs = [=](int index) {
       if (tabs_closing_map_.find(index) == tabs_closing_map_.end())
         return;
       for (Tab* tab : base::Reversed(tabs_closing_map_[index]))
-        check_hovered_or_paint(tab);
+        check_hovered_selected_or_paint(tab);
     };
 
     paint_closing_tabs(tab_count());
@@ -1271,10 +1252,8 @@
       } else if (tab->IsActive()) {
         active_tab = tab;
         active_tab_index = i;
-      } else if (tab->IsSelected()) {
-        selected_tabs.push_back(tab);
       } else if (!stacked_layout_) {
-        check_hovered_or_paint(tab);
+        check_hovered_selected_or_paint(tab);
       }
       paint_closing_tabs(i);
     }
@@ -1338,7 +1317,7 @@
   if (active_tab && is_dragging)
     active_tab->Paint(paint_info);
 
-  if (ShouldDrawStrokes()) {
+  if (controller_->ShouldDrawStrokes()) {
     // Keep the recording scales consistent for the tab strip and its children.
     // See https://crbug.com/753911
     ui::PaintRecorder recorder(paint_info.context(),
@@ -1833,12 +1812,18 @@
 }
 
 void TabStrip::RemoveTabFromViewModel(int index) {
+  Tab* closing_tab = tab_at(index);
+  bool closing_tab_was_active = closing_tab->IsActive();
+
   // We still need to paint the tab until we actually remove it. Put it
   // in tabs_closing_map_ so we can find it.
-  tabs_closing_map_[index].push_back(tab_at(index));
+  tabs_closing_map_[index].push_back(closing_tab);
   UpdateTabsClosingMap(index + 1, -1);
   tabs_.Remove(index);
   selected_tabs_.DecrementFrom(index);
+
+  if (closing_tab_was_active)
+    closing_tab->ActiveStateChanged();
 }
 
 void TabStrip::RemoveAndDeleteTab(Tab* tab) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 0554dbbb..de720eb 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -215,9 +215,6 @@
   // ongoing this does a layout.
   void StopAnimating(bool layout);
 
-  // Returns whether or not strokes should be drawn around and under the tabs.
-  bool ShouldDrawStrokes() const;
-
   // TabController:
   const ui::ListSelectionModel& GetSelectionModel() const override;
   bool SupportsMultipleSelection() override;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_controller.h b/chrome/browser/ui/views/tabs/tab_strip_controller.h
index c64cf0d..5bfb282c4 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_controller.h
@@ -108,6 +108,9 @@
   // Whether the special painting mode for one tab is allowed.
   virtual bool IsSingleTabModeAvailable() = 0;
 
+  // Returns whether or not strokes should be drawn around and under the tabs.
+  virtual bool ShouldDrawStrokes() const = 0;
+
   // Notifies controller that the user started dragging this tabstrip's tabs.
   virtual void OnStartedDraggingTabs() = 0;
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index 034f7be..d310e70a 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -34,7 +34,6 @@
 #include "ui/views/controls/menu/menu_model_adapter.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/mouse_constants.h"
-#include "ui/views/style/platform_style.h"
 
 using views::LabelButtonBorder;
 
@@ -67,7 +66,6 @@
   view_controller_->SetDelegate(this);
   SetHorizontalAlignment(gfx::ALIGN_CENTER);
   set_drag_controller(delegate_);
-  SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
 
   set_context_menu_controller(this);
 
@@ -141,7 +139,7 @@
   auto ink_drop = CreateToolbarInkDrop<MenuButton>(this);
 
   ink_drop->SetShowHighlightOnHover(!delegate_->ShownInsideMenu());
-  ink_drop->SetShowHighlightOnFocus(!views::PlatformStyle::kPreferFocusRings);
+  ink_drop->SetShowHighlightOnFocus(!focus_ring());
   return ink_drop;
 }
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index be1c7ae..f3d2418 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -25,7 +25,6 @@
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/menu_model_adapter.h"
 #include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/style/platform_style.h"
 #include "ui/views/widget/widget.h"
 
 ToolbarButton::ToolbarButton(views::ButtonListener* listener)
@@ -43,7 +42,6 @@
   set_context_menu_controller(this);
   SetInkDropMode(InkDropMode::ON);
   SetFocusPainter(nullptr);
-  SetInstallFocusRingOnFocus(views::PlatformStyle::kPreferFocusRings);
 
   // Make sure icons are flipped by default so that back, forward, etc. follows
   // UI direction.
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
index 1441c13..dbc5fed 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.cc
@@ -4,14 +4,55 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/login/localized_values_builder.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace {
 
 const char kJsScreenPath[] = "login.SyncConsentScreen";
 
+// This helper function gets strings from WebUI and a set of known string
+// resource ids, and converts strings back to IDs. It CHECKs if string is not
+// found in resources.
+void GetConsentIDs(const std::unordered_set<int>& known_ids,
+                   const login::StringList& consent_description,
+                   const std::string& consent_confirmation,
+                   std::vector<int>* consent_description_ids,
+                   int* consent_confirmation_id) {
+  std::unordered_map<std::string, int> known_strings;
+  for (const int& id : known_ids) {
+    // When the strings are passed to the HTML, the Unicode NBSP symbol
+    // (\u00A0) will be automatically replaced with "&nbsp;". This change must
+    // be mirrored in the string-to-ids map. Note that "\u00A0" is actually two
+    // characters, so we must use base::ReplaceSubstrings* rather than
+    // base::ReplaceChars.
+    // TODO(alemate): Find a more elegant solution.
+    std::string sanitized_string =
+        base::UTF16ToUTF8(l10n_util::GetStringUTF16(id));
+    base::ReplaceSubstringsAfterOffset(&sanitized_string, 0,
+                                       "\u00A0" /* NBSP */, "&nbsp;");
+
+    known_strings[sanitized_string] = id;
+  }
+  // The strings returned by the WebUI are not free-form, they must belong into
+  // a pre-determined set of strings (stored in |string_to_grd_id_map_|). As
+  // this has privacy and legal implications, CHECK the integrity of the strings
+  // received from the renderer process before recording the consent.
+  for (const std::string& text : consent_description) {
+    auto iter = known_strings.find(text);
+    CHECK(iter != known_strings.end()) << "Unexpected string:\n" << text;
+    consent_description_ids->push_back(iter->second);
+  }
+
+  auto iter = known_strings.find(consent_confirmation);
+  CHECK(iter != known_strings.end()) << "Unexpected string:\n"
+                                     << consent_confirmation;
+  *consent_confirmation_id = iter->second;
+}
+
 }  // namespace
 
 namespace chromeos {
@@ -23,55 +64,78 @@
 
 SyncConsentScreenHandler::~SyncConsentScreenHandler() {}
 
+void SyncConsentScreenHandler::RememberLocalizedValue(
+    const std::string& name,
+    const int resource_id,
+    ::login::LocalizedValuesBuilder* builder) {
+  CHECK(known_string_ids_.count(resource_id) == 0);
+  known_string_ids_.insert(resource_id);
+  builder->Add(name, resource_id);
+}
+
 void SyncConsentScreenHandler::DeclareLocalizedValues(
     ::login::LocalizedValuesBuilder* builder) {
-  builder->Add("syncConsentScreenTitle", IDS_LOGIN_SYNC_CONSENT_SCREEN_TITLE);
-  builder->Add("syncConsentScreenChromeSyncName",
-               IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_NAME);
-  builder->Add("syncConsentScreenChromeSyncDescription",
-               IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_DESCRIPTION);
-  builder->Add("syncConsentScreenPersonalizeGoogleServicesName",
-               IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_NAME);
-  builder->Add(
+  known_string_ids_.clear();
+
+  RememberLocalizedValue("syncConsentScreenTitle",
+                         IDS_LOGIN_SYNC_CONSENT_SCREEN_TITLE, builder);
+  RememberLocalizedValue("syncConsentScreenChromeSyncName",
+                         IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_NAME,
+                         builder);
+  RememberLocalizedValue("syncConsentScreenChromeSyncDescription",
+                         IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_DESCRIPTION,
+                         builder);
+  RememberLocalizedValue(
+      "syncConsentScreenPersonalizeGoogleServicesName",
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_NAME, builder);
+  RememberLocalizedValue(
       "syncConsentScreenPersonalizeGoogleServicesDescription",
-      IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_DESCRIPTION);
-  builder->Add("syncConsentReviewSyncOptionsText",
-               IDS_LOGIN_SYNC_CONSENT_SCREEN_REVIEW_SYNC_OPTIONS_LATER);
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_DESCRIPTION,
+      builder);
+  RememberLocalizedValue(
+      "syncConsentReviewSyncOptionsText",
+      IDS_LOGIN_SYNC_CONSENT_SCREEN_REVIEW_SYNC_OPTIONS_LATER, builder);
 
-  builder->Add("syncConsentNewScreenTitle",
-               IDS_LOGIN_SYNC_CONSENT_GET_GOOGLE_SMARTS);
-  builder->Add("syncConsentNewBookmarksDesc",
-               IDS_LOGIN_SYNC_CONSENT_YOUR_BOOKMARKS_ON_ALL_DEVICES);
-  builder->Add("syncConsentNewServicesDesc",
-               IDS_LOGIN_SYNC_CONSENT_PERSONALIZED_GOOGLE_SERVICES);
-  builder->Add("syncConsentNewImproveChrome",
-               IDS_LOGIN_SYNC_CONSENT_IMPROVE_CHROME);
-  builder->Add("syncConsentNewGoogleMayUse",
-               IDS_LOGIN_SYNC_CONSENT_GOOGLE_MAY_USE);
-  builder->Add("syncConsentNewMoreOptions",
-               IDS_LOGIN_SYNC_CONSENT_MORE_OPTIONS);
-  builder->Add("syncConsentNewYesIAmIn", IDS_LOGIN_SYNC_CONSENT_YES_I_AM_IN);
-  builder->Add("syncConsentNewSyncOptions",
-               IDS_LOGIN_SYNC_CONSENT_SYNC_OPTIONS);
-  builder->Add("syncConsentNewSyncOptionsSubtitle",
-               IDS_LOGIN_SYNC_CONSENT_SYNC_OPTIONS_SUBTITLE);
-  builder->Add("syncConsentNewChooseOption",
-               IDS_LOGIN_SYNC_CONSENT_CHOOSE_OPTION);
-  builder->Add("syncConsentNewOptionReview",
-               IDS_LOGIN_SYNC_CONSENT_OPTION_REVIEW);
-  builder->Add("syncConsentNewOptionReviewDsc",
-               IDS_LOGIN_SYNC_CONSENT_OPTION_REVIEW_DSC);
-  builder->Add("syncConsentNewOptionJustSync",
-               IDS_LOGIN_SYNC_CONSENT_OPTION_JUST_SYNC);
-  builder->Add("syncConsentNewOptionJustSyncDsc",
-               IDS_LOGIN_SYNC_CONSENT_OPTION_JUST_SYNC_DSC);
-  builder->Add("syncConsentNewOptionSyncAndPersonalization",
-               IDS_LOGIN_SYNC_CONSENT_OPTION_SYNC_AND_PERSONALIZATION);
-  builder->Add("syncConsentNewOptionSyncAndPersonalizationDsc",
-               IDS_LOGIN_SYNC_CONSENT_OPTION_SYNC_AND_PERSONALIZATION_DSC);
+  RememberLocalizedValue("syncConsentNewScreenTitle",
+                         IDS_LOGIN_SYNC_CONSENT_GET_GOOGLE_SMARTS, builder);
+  RememberLocalizedValue("syncConsentNewBookmarksDesc",
+                         IDS_LOGIN_SYNC_CONSENT_YOUR_BOOKMARKS_ON_ALL_DEVICES,
+                         builder);
+  RememberLocalizedValue("syncConsentNewServicesDesc",
+                         IDS_LOGIN_SYNC_CONSENT_PERSONALIZED_GOOGLE_SERVICES,
+                         builder);
+  RememberLocalizedValue("syncConsentNewImproveChrome",
+                         IDS_LOGIN_SYNC_CONSENT_IMPROVE_CHROME, builder);
+  RememberLocalizedValue("syncConsentNewGoogleMayUse",
+                         IDS_LOGIN_SYNC_CONSENT_GOOGLE_MAY_USE, builder);
+  RememberLocalizedValue("syncConsentNewMoreOptions",
+                         IDS_LOGIN_SYNC_CONSENT_MORE_OPTIONS, builder);
+  RememberLocalizedValue("syncConsentNewYesIAmIn",
+                         IDS_LOGIN_SYNC_CONSENT_YES_I_AM_IN, builder);
+  RememberLocalizedValue("syncConsentNewSyncOptions",
+                         IDS_LOGIN_SYNC_CONSENT_SYNC_OPTIONS, builder);
+  RememberLocalizedValue("syncConsentNewSyncOptionsSubtitle",
+                         IDS_LOGIN_SYNC_CONSENT_SYNC_OPTIONS_SUBTITLE, builder);
+  RememberLocalizedValue("syncConsentNewChooseOption",
+                         IDS_LOGIN_SYNC_CONSENT_CHOOSE_OPTION, builder);
+  RememberLocalizedValue("syncConsentNewOptionReview",
+                         IDS_LOGIN_SYNC_CONSENT_OPTION_REVIEW, builder);
+  RememberLocalizedValue("syncConsentNewOptionReviewDsc",
+                         IDS_LOGIN_SYNC_CONSENT_OPTION_REVIEW_DSC, builder);
+  RememberLocalizedValue("syncConsentNewOptionJustSync",
+                         IDS_LOGIN_SYNC_CONSENT_OPTION_JUST_SYNC, builder);
+  RememberLocalizedValue("syncConsentNewOptionJustSyncDsc",
+                         IDS_LOGIN_SYNC_CONSENT_OPTION_JUST_SYNC_DSC, builder);
+  RememberLocalizedValue("syncConsentNewOptionSyncAndPersonalization",
+                         IDS_LOGIN_SYNC_CONSENT_OPTION_SYNC_AND_PERSONALIZATION,
+                         builder);
+  RememberLocalizedValue(
+      "syncConsentNewOptionSyncAndPersonalizationDsc",
+      IDS_LOGIN_SYNC_CONSENT_OPTION_SYNC_AND_PERSONALIZATION_DSC, builder);
 
-  builder->Add("syncConsentAcceptAndContinue",
-               IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE);
+  RememberLocalizedValue("syncConsentAcceptAndContinue",
+                         IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE,
+                         builder);
 }
 
 void SyncConsentScreenHandler::Bind(SyncConsentScreen* screen) {
@@ -91,6 +155,13 @@
 
 void SyncConsentScreenHandler::Initialize() {}
 
+void SyncConsentScreenHandler::RegisterMessages() {
+  AddPrefixedCallback("continueAndReview",
+                      &SyncConsentScreenHandler::HandleContinueAndReview);
+  AddPrefixedCallback("continueWithDefaults",
+                      &SyncConsentScreenHandler::HandleContinueWithDefaults);
+}
+
 void SyncConsentScreenHandler::GetAdditionalParameters(
     base::DictionaryValue* parameters) {
   parameters->Set("syncConsentMakeBetter",
@@ -98,4 +169,40 @@
   BaseScreenHandler::GetAdditionalParameters(parameters);
 }
 
+void SyncConsentScreenHandler::HandleContinueAndReview(
+    const login::StringList& consent_description,
+    const std::string& consent_confirmation) {
+  std::vector<int> consent_description_ids;
+  int consent_confirmation_id;
+  GetConsentIDs(known_string_ids_, consent_description, consent_confirmation,
+                &consent_description_ids, &consent_confirmation_id);
+  screen_->OnContinueAndReview(consent_description_ids,
+                               consent_confirmation_id);
+
+  SyncConsentScreen::SyncConsentScreenTestDelegate* test_delegate =
+      screen_->GetDelegateForTesting();
+  if (test_delegate) {
+    test_delegate->OnConsentRecordedStrings(consent_description,
+                                            consent_confirmation);
+  }
+}
+
+void SyncConsentScreenHandler::HandleContinueWithDefaults(
+    const login::StringList& consent_description,
+    const std::string& consent_confirmation) {
+  std::vector<int> consent_description_ids;
+  int consent_confirmation_id;
+  GetConsentIDs(known_string_ids_, consent_description, consent_confirmation,
+                &consent_description_ids, &consent_confirmation_id);
+  screen_->OnContinueWithDefaults(consent_description_ids,
+                                  consent_confirmation_id);
+
+  SyncConsentScreen::SyncConsentScreenTestDelegate* test_delegate =
+      screen_->GetDelegateForTesting();
+  if (test_delegate) {
+    test_delegate->OnConsentRecordedStrings(consent_description,
+                                            consent_confirmation);
+  }
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
index 38cfde3..a961210c 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_SYNC_CONSENT_SCREEN_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_SYNC_CONSENT_SCREEN_HANDLER_H_
 
+#include <unordered_set>
+
 #include "base/macros.h"
 #include "chrome/browser/chromeos/login/screens/sync_consent_screen_view.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
@@ -33,8 +35,24 @@
  private:
   // BaseScreenHandler:
   void Initialize() override;
+  void RegisterMessages() override;
   void GetAdditionalParameters(base::DictionaryValue* parameters) override;
 
+  // WebUI message handlers
+  void HandleContinueAndReview(const ::login::StringList& consent_description,
+                               const std::string& consent_confirmation);
+  void HandleContinueWithDefaults(
+      const ::login::StringList& consent_description,
+      const std::string& consent_confirmation);
+
+  // Adds resource |resource_id| both to |builder| and to |known_string_ids_|.
+  void RememberLocalizedValue(const std::string& name,
+                              const int resource_id,
+                              ::login::LocalizedValuesBuilder* builder);
+
+  // Resource IDs of the displayed strings.
+  std::unordered_set<int> known_string_ids_;
+
   SyncConsentScreen* screen_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SyncConsentScreenHandler);
diff --git a/chrome/browser/ui/webui/conflicts/conflicts_handler.cc b/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
index ab34217..fe468d3 100644
--- a/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
+++ b/chrome/browser/ui/webui/conflicts/conflicts_handler.cc
@@ -75,6 +75,8 @@
         return "Disallowed - Added to the blacklist";
       case BlockingDecision::kBlocked:
         return "Disallowed - Blocked";
+      case BlockingDecision::kBypassedBlocking:
+        return "Disallowed - Bypassed blocking";
       case BlockingDecision::kUnknown:
         NOTREACHED();
         break;
diff --git a/chrome/browser/ui/webui/media/media_engagement_ui.cc b/chrome/browser/ui/webui/media/media_engagement_ui.cc
index 00d7e98..16bf3602 100644
--- a/chrome/browser/ui/webui/media/media_engagement_ui.cc
+++ b/chrome/browser/ui/webui/media/media_engagement_ui.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/macros.h"
+#include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/media_engagement_score.h"
 #include "chrome/browser/media/media_engagement_service.h"
@@ -16,12 +17,20 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "components/component_updater/component_updater_service.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/web_preferences.h"
 #include "media/base/media_switches.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+#if !defined(OS_ANDROID)
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#endif
+
 namespace {
 
 namespace {
@@ -37,10 +46,13 @@
     : public media::mojom::MediaEngagementScoreDetailsProvider {
  public:
   MediaEngagementScoreDetailsProviderImpl(
-      Profile* profile,
+      content::WebUI* web_ui,
       mojo::InterfaceRequest<media::mojom::MediaEngagementScoreDetailsProvider>
           request)
-      : profile_(profile), binding_(this, std::move(request)) {
+      : web_ui_(web_ui),
+        profile_(Profile::FromWebUI(web_ui)),
+        binding_(this, std::move(request)) {
+    DCHECK(web_ui_);
     DCHECK(profile_);
     service_ = MediaEngagementService::Get(profile_);
   }
@@ -65,12 +77,30 @@
         base::FeatureList::IsEnabled(
             media::kMediaEngagementBypassAutoplayPolicies),
         base::FeatureList::IsEnabled(media::kPreloadMediaEngagementData),
-        media::GetEffectiveAutoplayPolicy(
-            *base::CommandLine::ForCurrentProcess()),
-        GetPreloadVersion()));
+        base::FeatureList::IsEnabled(media::kAutoplaySoundSettings),
+        GetBlockAutoplayPref(),
+        base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kAutoplayPolicy),
+        GetAppliedAutoplayPolicy(), GetPreloadVersion()));
   }
 
  private:
+  const std::string GetAppliedAutoplayPolicy() {
+    switch (web_ui_->GetWebContents()
+                ->GetRenderViewHost()
+                ->GetWebkitPreferences()
+                .autoplay_policy) {
+      case content::AutoplayPolicy::kNoUserGestureRequired:
+        return "no-user-gesture-required";
+      case content::AutoplayPolicy::kUserGestureRequired:
+        return "user-gesture-required";
+      case content::AutoplayPolicy::kUserGestureRequiredForCrossOrigin:
+        return "user-gesture-required-for-cross-origin";
+      case content::AutoplayPolicy::kDocumentUserActivationRequired:
+        return "document-user-activation-required";
+    }
+  }
+
   const std::string GetPreloadVersion() {
     component_updater::ComponentUpdateService* cus =
         g_browser_process->component_updater();
@@ -84,6 +114,17 @@
     return std::string();
   }
 
+  // Pref is not available on Android.
+  bool GetBlockAutoplayPref() {
+#if defined(OS_ANDROID)
+    return false;
+#else
+    return profile_->GetPrefs()->GetBoolean(prefs::kBlockAutoplayEnabled);
+#endif
+  }
+
+  content::WebUI* web_ui_;
+
   Profile* profile_;
 
   MediaEngagementService* service_;
@@ -118,5 +159,5 @@
 void MediaEngagementUI::BindMediaEngagementScoreDetailsProvider(
     media::mojom::MediaEngagementScoreDetailsProviderRequest request) {
   ui_handler_ = std::make_unique<MediaEngagementScoreDetailsProviderImpl>(
-      Profile::FromWebUI(web_ui()), std::move(request));
+      web_ui(), std::move(request));
 }
diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc
index ac99d1d3..deec3bb 100644
--- a/chrome/browser/upgrade_detector.cc
+++ b/chrome/browser/upgrade_detector.cc
@@ -44,6 +44,7 @@
   switch (upgrade_notification_stage_) {
     case UPGRADE_ANNOYANCE_NONE:
       return gfx::Image();
+    case UPGRADE_ANNOYANCE_VERY_LOW:
     case UPGRADE_ANNOYANCE_LOW:
       color = gfx::kGoogleGreen700;
       break;
@@ -55,7 +56,8 @@
       color = gfx::kGoogleRed700;
       break;
   }
-  DCHECK_NE(gfx::kPlaceholderColor, color);
+  DCHECK_NE(gfx::kPlaceholderColor, color)
+      << static_cast<int>(upgrade_notification_stage_);
 
   return gfx::Image(gfx::CreateVectorIcon(kBrowserToolsUpdateIcon, color));
 }
diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h
index 084b3318..bff30d1 100644
--- a/chrome/browser/upgrade_detector.h
+++ b/chrome/browser/upgrade_detector.h
@@ -43,13 +43,10 @@
     UPGRADE_ANNOYANCE_HIGH = 3,      // Red.
     // UPGRADE_ANNOYANCE_SEVERE = 4,  // Removed in 2018-03 for lack of use.
     UPGRADE_ANNOYANCE_CRITICAL = 5,  // Red exclamation mark.
-    UPGRADE_ANNOYANCE_LAST = UPGRADE_ANNOYANCE_CRITICAL  // The last value
+    UPGRADE_ANNOYANCE_VERY_LOW = 6,  // Green early warning for canary and dev.
+    UPGRADE_ANNOYANCE_MAX_VALUE = UPGRADE_ANNOYANCE_VERY_LOW
   };
 
-  // The number of UpgradeNotificationAnnoyanceLevel enum values.
-  static constexpr int kUpgradeNotificationAnnoyanceLevelCount =
-      UPGRADE_ANNOYANCE_LAST + 1;
-
   // Returns the singleton implementation instance.
   static UpgradeDetector* GetInstance();
 
@@ -97,9 +94,9 @@
   bool is_rollback() const { return is_rollback_; }
 #endif  // defined(OS_CHROMEOS)
 
-  // Retrieves the right icon based on the degree of severity (see
-  // UpgradeNotificationAnnoyanceLevel, each level has an an accompanying icon
-  // to go with it) to display within the app menu.
+  // Retrieves the right icon based on the degree of severity (each
+  // UpgradeNotificationAnnoyanceLevel has an an accompanying icon) to display
+  // within the app menu.
   gfx::Image GetIcon();
 
   UpgradeNotificationAnnoyanceLevel upgrade_notification_stage() const {
diff --git a/chrome/browser/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector_impl.cc
index bd7dd30..369546ce 100644
--- a/chrome/browser/upgrade_detector_impl.cc
+++ b/chrome/browser/upgrade_detector_impl.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/build_time.h"
@@ -28,7 +29,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_brand.h"
-#include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/network_time/network_time_tracker.h"
@@ -47,6 +47,8 @@
 namespace {
 
 // The default thresholds for reaching annoyance levels.
+constexpr base::TimeDelta kDefaultVeryLowThreshold =
+    base::TimeDelta::FromHours(1);
 constexpr base::TimeDelta kDefaultLowThreshold = base::TimeDelta::FromDays(2);
 constexpr base::TimeDelta kDefaultElevatedThreshold =
     base::TimeDelta::FromDays(4);
@@ -102,16 +104,6 @@
   return kCheckForUpgrade;
 }
 
-// Return true if the browser is updating on the dev or canary channels.
-bool IsUnstableChannel() {
-  // Unbranded (Chromium) builds are on the UNKNOWN channel, so check explicitly
-  // for the Google Chrome channels that are considered "unstable". This ensures
-  // that Chromium builds get the default behavior.
-  const version_info::Channel channel = chrome::GetChannel();
-  return channel == version_info::Channel::DEV ||
-         channel == version_info::Channel::CANARY;
-}
-
 // Gets the currently installed version. On Windows, if |critical_update| is not
 // NULL, also retrieves the critical update version info if available.
 base::Version GetCurrentlyInstalledVersionImpl(base::Version* critical_update) {
@@ -324,84 +316,51 @@
 
 void UpgradeDetectorImpl::InitializeThresholds() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!stages_.empty())
+  if (!stages_[0].is_zero())
     return;
 
   DoInitializeThresholds();
+
 #if DCHECK_IS_ON()
-  // |stages_| must have at least one element, and must be sorted in decreasing
-  // order of time.
-  DCHECK(!stages_.empty());
-  for (auto scan = stages_.begin() + 1; scan != stages_.end(); ++scan)
-    DCHECK_GT((scan - 1)->first, scan->first);
-
-  // elevated_threshold_ must be greater than low_threshold (the last item in)
-  // |stages_|.
-  DCHECK_GT(elevated_threshold_, stages_.back().first);
-
-  // high_threshold_ must be greater than elevated_threshold_.
-  DCHECK_GT(high_threshold_, elevated_threshold_);
-
-  // If elevated_threshold_ and high_threshold_ are present in |stages_|, they
-  // must be equal.
-  if (stages_.size() != 1) {
-    DCHECK(!IsUnstableChannel());
-    DCHECK_EQ(stages_.size(), 3U);
-    DCHECK_EQ(stages_[1].first, elevated_threshold_);
-    DCHECK_EQ(stages_[0].first, high_threshold_);
-  } else {
-    DCHECK(IsUnstableChannel());
+  // |stages_| must be sorted in decreasing order of time.
+  for (std::array<base::TimeDelta, kNumStages>::iterator scan =
+           stages_.begin() + 1;
+       scan != stages_.end(); ++scan) {
+    DCHECK_GE(*(scan - 1), *scan);
   }
 #endif  // DCHECK_IS_ON()
 }
 
 void UpgradeDetectorImpl::DoInitializeThresholds() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(stages_.empty());
-
-  base::TimeDelta low_threshold;
+  DCHECK(stages_[0].is_zero());
 
   // Use a custom notification period for the "high" level, dividing it evenly
   // to set the "low" and "elevated" levels. Such overrides trump all else.
   const base::TimeDelta custom_high = GetRelaunchNotificationPeriod();
   if (!custom_high.is_zero()) {
-    low_threshold = custom_high / 3;
-    elevated_threshold_ = custom_high - low_threshold;
-    high_threshold_ = custom_high;
-    // Stages must be sorted by decreasing TimeDelta.
-    stages_.emplace_back(high_threshold_, UPGRADE_ANNOYANCE_HIGH);
-    stages_.emplace_back(elevated_threshold_, UPGRADE_ANNOYANCE_ELEVATED);
-    stages_.emplace_back(low_threshold, UPGRADE_ANNOYANCE_LOW);
+    stages_[kStagesIndexHigh] = custom_high;
+    stages_[kStagesIndexLow] = custom_high / 3;
+    stages_[kStagesIndexElevated] = custom_high - stages_[kStagesIndexLow];
+    // "Very low" is one hour, unless "low" is even less.
+    stages_[kStagesIndexVeryLow] =
+        std::min(stages_[kStagesIndexLow], kDefaultVeryLowThreshold);
     return;
   }
 
   // Use the default values when no override is set.
-  low_threshold = kDefaultLowThreshold;
-  elevated_threshold_ = kDefaultElevatedThreshold;
-  high_threshold_ = kDefaultHighThreshold;
+  stages_[kStagesIndexHigh] = kDefaultHighThreshold;
+  stages_[kStagesIndexElevated] = kDefaultElevatedThreshold;
+  stages_[kStagesIndexLow] = kDefaultLowThreshold;
+  stages_[kStagesIndexVeryLow] = kDefaultVeryLowThreshold;
 
   // When testing, scale everything back so that a day passes in ten seconds.
   if (is_testing_) {
     static constexpr int64_t scale_factor =
         base::TimeDelta::FromDays(1) / base::TimeDelta::FromSeconds(10);
-    low_threshold /= scale_factor;
-    elevated_threshold_ /= scale_factor;
-    high_threshold_ /= scale_factor;
+    for (auto& stage : stages_)
+      stage /= scale_factor;
   }
-
-  // Canary and dev channels are extra special, and reach "low" annoyance after
-  // one hour (one second in testing) and never advance beyond that.
-  if (IsUnstableChannel()) {
-    low_threshold = is_testing_ ? base::TimeDelta::FromSeconds(1)
-                                : base::TimeDelta::FromHours(1);
-    // High and elevated thresholds are not added to |stages_| on unstable
-    // channels.
-  } else {
-    // Stages must be sorted by decreasing TimeDelta.
-    stages_.emplace_back(high_threshold_, UPGRADE_ANNOYANCE_HIGH);
-    stages_.emplace_back(elevated_threshold_, UPGRADE_ANNOYANCE_ELEVATED);
-  }
-  stages_.emplace_back(low_threshold, UPGRADE_ANNOYANCE_LOW);
 }
 
 void UpgradeDetectorImpl::CheckForUpgrade() {
@@ -507,14 +466,15 @@
     new_stage = UPGRADE_ANNOYANCE_CRITICAL;
   } else {
     // |stages_| must be sorted by decreasing TimeDelta.
-    auto it = std::find_if(stages_.begin(), stages_.end(),
-                           [time_passed](const DeltaAndStage& delta_and_stage) {
-                             return time_passed >= delta_and_stage.first;
-                           });
+    std::array<base::TimeDelta, kNumStages>::iterator it =
+        std::find_if(stages_.begin(), stages_.end(),
+                     [time_passed](const base::TimeDelta& delta) {
+                       return time_passed >= delta;
+                     });
     if (it != stages_.end())
-      new_stage = it->second;
+      new_stage = StageIndexToAnnoyanceLevel(it - stages_.begin());
     if (it != stages_.begin())
-      next_delay = (it - 1)->first - time_passed;
+      next_delay = *(it - 1) - time_passed;
   }
 
   set_upgrade_notification_stage(new_stage);
@@ -543,30 +503,51 @@
 
 base::TimeDelta UpgradeDetectorImpl::GetThresholdForLevel(
     UpgradeNotificationAnnoyanceLevel level) {
-  DCHECK(!stages_.empty());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!stages_[0].is_zero());
+  return stages_[AnnoyanceLevelToStagesIndex(level)];
+}
+
+// static
+UpgradeDetectorImpl::LevelIndex
+UpgradeDetectorImpl::AnnoyanceLevelToStagesIndex(
+    UpgradeNotificationAnnoyanceLevel level) {
   switch (level) {
+    case UPGRADE_ANNOYANCE_NONE:
+      break;  // Invalid input.
+    case UPGRADE_ANNOYANCE_VERY_LOW:
+      return kStagesIndexVeryLow;
     case UPGRADE_ANNOYANCE_LOW:
-      // Low is always the last item in |stages_|.
-      return stages_.back().first;
+      return kStagesIndexLow;
     case UPGRADE_ANNOYANCE_ELEVATED:
-      // Elevated is not present in |stages_| on unstable channels.
-      return elevated_threshold_;
+      return kStagesIndexElevated;
     case UPGRADE_ANNOYANCE_HIGH:
       break;
-    case UPGRADE_ANNOYANCE_NONE:
     case UPGRADE_ANNOYANCE_CRITICAL:
-      NOTREACHED();
-      break;
+      break;  // Invalid input.
   }
-  // High is not present in |stages_| on unstable channels.
-  return high_threshold_;
+  DCHECK_EQ(level, UPGRADE_ANNOYANCE_HIGH);
+  return kStagesIndexHigh;
+}
+
+// static
+UpgradeDetector::UpgradeNotificationAnnoyanceLevel
+UpgradeDetectorImpl::StageIndexToAnnoyanceLevel(size_t index) {
+  static constexpr UpgradeNotificationAnnoyanceLevel kIndexToLevel[] = {
+      UpgradeDetector::UPGRADE_ANNOYANCE_HIGH,
+      UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED,
+      UpgradeDetector::UPGRADE_ANNOYANCE_LOW,
+      UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW};
+  static_assert(base::size(kIndexToLevel) == kNumStages, "mismatch");
+  DCHECK_LT(index, base::size(kIndexToLevel));
+  return kIndexToLevel[index];
 }
 
 void UpgradeDetectorImpl::OnRelaunchNotificationPeriodPrefChanged() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Force a recomputation of the thresholds.
-  stages_.clear();
+  stages_.fill(base::TimeDelta());
   InitializeThresholds();
 
   // Broadcast the appropriate notification if an upgrade has been detected.
@@ -599,9 +580,7 @@
 
 base::TimeDelta UpgradeDetectorImpl::GetHighAnnoyanceLevelDelta() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // Elevated and high thresholds are not present in |stages_| for unstable
-  // channels, but their delta is still valid in such case.
-  return high_threshold_ - elevated_threshold_;
+  return stages_[kStagesIndexHigh] - stages_[kStagesIndexElevated];
 }
 
 base::TimeTicks UpgradeDetectorImpl::GetHighAnnoyanceDeadline() {
@@ -609,9 +588,7 @@
   const base::TimeTicks detected_time = upgrade_detected_time();
   if (detected_time.is_null())
     return detected_time;
-  // While dev and canary will never reach high annoyance (see comment in
-  // NotifyOnUpgradeWithTimePassed), they do obey its default deadline.
-  return detected_time + high_threshold_;
+  return detected_time + stages_[kStagesIndexHigh];
 }
 
 // static
diff --git a/chrome/browser/upgrade_detector_impl.h b/chrome/browser/upgrade_detector_impl.h
index a5ce541..bd918705 100644
--- a/chrome/browser/upgrade_detector_impl.h
+++ b/chrome/browser/upgrade_detector_impl.h
@@ -5,8 +5,7 @@
 #ifndef CHROME_BROWSER_UPGRADE_DETECTOR_IMPL_H_
 #define CHROME_BROWSER_UPGRADE_DETECTOR_IMPL_H_
 
-#include <utility>
-#include <vector>
+#include <array>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -62,14 +61,27 @@
   base::TimeDelta GetThresholdForLevel(UpgradeNotificationAnnoyanceLevel level);
 
  private:
+  // The index of a level in stages_.
+  enum LevelIndex {
+    kStagesIndexHigh = 0,
+    kStagesIndexElevated = 1,
+    kStagesIndexLow = 2,
+    kStagesIndexVeryLow = 3,
+    kNumStages
+  };
+
   friend class base::NoDestructor<UpgradeDetectorImpl>;
 
   // A callback that receives the results of |DetectUpgradeTask|.
   using UpgradeDetectedCallback = base::OnceCallback<void(UpgradeAvailable)>;
 
-  using DeltaAndStage =
-      std::pair<base::TimeDelta, UpgradeNotificationAnnoyanceLevel>;
-  using Stages = std::vector<DeltaAndStage>;
+  // Returns the index of |level| in |stages_|.
+  static LevelIndex AnnoyanceLevelToStagesIndex(
+      UpgradeNotificationAnnoyanceLevel level);
+
+  // Returns the annoyance level of |index| in |stages_|.
+  static UpgradeNotificationAnnoyanceLevel StageIndexToAnnoyanceLevel(
+      size_t index);
 
   // UpgradeDetector:
   void OnRelaunchNotificationPeriodPrefChanged() override;
@@ -133,9 +145,7 @@
 
   // The various deltas from detection time to the different annoyance levels;
   // lazy-initialized by InitializeThresholds.
-  base::TimeDelta high_threshold_;
-  base::TimeDelta elevated_threshold_;
-  Stages stages_;
+  std::array<base::TimeDelta, kNumStages> stages_;
 
   // The date the binaries were built.
   base::Time build_date_;
diff --git a/chrome/browser/upgrade_detector_impl_unittest.cc b/chrome/browser/upgrade_detector_impl_unittest.cc
index f33be88..c8d55a7 100644
--- a/chrome/browser/upgrade_detector_impl_unittest.cc
+++ b/chrome/browser/upgrade_detector_impl_unittest.cc
@@ -26,6 +26,8 @@
 #include "chrome/install_static/test/scoped_install_details.h"
 #endif  // defined(OS_WIN)
 
+using ::testing::AnyNumber;
+
 namespace {
 
 class TestUpgradeDetectorImpl : public UpgradeDetectorImpl {
@@ -192,6 +194,13 @@
   RunUntilIdle();
 }
 
+// Tests that the proper notifications are sent for the expected stages as the
+// RelaunchNotificationPeriod policy is changed. The period is set to one day,
+// such that the thresholds for the annoyance levels are expected to be:
+// very low: 1h
+// low: 8h
+// elevated: 16h
+// high: 24h
 TEST_F(UpgradeDetectorImplTest, TestPeriodChanges) {
   // Fast forward a little bit to get away from zero ticks, which has special
   // meaning in the detector.
@@ -202,11 +211,20 @@
 
   // Changing the period when no upgrade has been detected updates the
   // thresholds and nothing else.
-  SetNotificationPeriodPref(base::TimeDelta::FromHours(3));
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
 
   EXPECT_EQ(upgrade_detector.GetThresholdForLevel(
                 UpgradeDetector::UPGRADE_ANNOYANCE_HIGH),
-            base::TimeDelta::FromHours(3));
+            base::TimeDelta::FromDays(1));
+  EXPECT_EQ(upgrade_detector.GetThresholdForLevel(
+                UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED),
+            base::TimeDelta::FromHours(16));
+  EXPECT_EQ(upgrade_detector.GetThresholdForLevel(
+                UpgradeDetector::UPGRADE_ANNOYANCE_LOW),
+            base::TimeDelta::FromHours(8));
+  EXPECT_EQ(upgrade_detector.GetThresholdForLevel(
+                UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW),
+            base::TimeDelta::FromHours(1));
   ::testing::Mock::VerifyAndClear(&mock_observer);
 
   // Back to default.
@@ -223,12 +241,46 @@
 
   // Fast forward an amount that is still in the "don't annoy me" period at the
   // default period.
-  FastForwardBy(base::TimeDelta::FromHours(1));
+  FastForwardBy(base::TimeDelta::FromMinutes(59));
   ::testing::Mock::VerifyAndClear(&mock_observer);
 
+  // Drop the period and notice that nothing changes (still below "very low").
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
+  ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+
+  // Fast forward to the "very low" annoyance level.
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended());
+  FastForwardBy(base::TimeDelta::FromMinutes(1));
+  ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+
+  // Drop the period; staying within "very low".
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
+  ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+
+  // Bring it back up.
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended());
+  SetNotificationPeriodPref(base::TimeDelta());
+  ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+
+  // Fast forward an amount that is still in the "very low" level at the default
+  // period.
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended()).Times(AnyNumber());
+  FastForwardBy(base::TimeDelta::FromHours(7));
+  ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+
   // Drop the period so that the current time is in the "low" annoyance level.
   EXPECT_CALL(mock_observer, OnUpgradeRecommended());
-  SetNotificationPeriodPref(base::TimeDelta::FromHours(3));
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
             UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
@@ -238,16 +290,19 @@
   SetNotificationPeriodPref(base::TimeDelta());
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
-            UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 
-  // Fast forward an amount that is still in the "don't annoy me" period at the
+  // Fast forward an amount that is still in the "very low" period at the
   // default period.
-  FastForwardBy(base::TimeDelta::FromHours(1));
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended()).Times(AnyNumber());
+  FastForwardBy(base::TimeDelta::FromHours(8));
   ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 
   // Drop the period so that the current time is in the "elevated" level.
   EXPECT_CALL(mock_observer, OnUpgradeRecommended());
-  SetNotificationPeriodPref(base::TimeDelta::FromHours(3));
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
             UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
@@ -257,16 +312,19 @@
   SetNotificationPeriodPref(base::TimeDelta());
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
-            UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 
-  // Fast forward an amount that is still in the "don't annoy me" period at the
-  // default period.
-  FastForwardBy(base::TimeDelta::FromHours(1));
+  // Fast forward an amount that is still in the "very low" level at the default
+  // period.
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended()).Times(AnyNumber());
+  FastForwardBy(base::TimeDelta::FromHours(8));
   ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 
   // Drop the period so that the current time is in the "high" level.
   EXPECT_CALL(mock_observer, OnUpgradeRecommended());
-  SetNotificationPeriodPref(base::TimeDelta::FromHours(3));
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
             UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
@@ -274,22 +332,27 @@
   // Expect no new notifications even if some time passes.
   FastForwardBy(base::TimeDelta::FromHours(1));
   ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
 
   // Bring the period back up.
   EXPECT_CALL(mock_observer, OnUpgradeRecommended());
   SetNotificationPeriodPref(base::TimeDelta());
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
-            UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 
-  // Fast forward an amount that is still in the "don't annoy me" period at the
-  // default period.
-  FastForwardBy(base::TimeDelta::FromHours(1));
+  // Fast forward an amount that is still in the "very low" level at the default
+  // period.
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended()).Times(AnyNumber());
+  FastForwardBy(base::TimeDelta::FromHours(12));
   ::testing::Mock::VerifyAndClear(&mock_observer);
+  EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 
   // Drop the period so that the current time is deep in the "high" level.
   EXPECT_CALL(mock_observer, OnUpgradeRecommended());
-  SetNotificationPeriodPref(base::TimeDelta::FromHours(3));
+  SetNotificationPeriodPref(base::TimeDelta::FromDays(1));
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
             UpgradeDetector::UPGRADE_ANNOYANCE_HIGH);
@@ -299,32 +362,9 @@
   SetNotificationPeriodPref(base::TimeDelta());
   ::testing::Mock::VerifyAndClear(&mock_observer);
   EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
-            UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
+            UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
 }
 
-#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
-// Tests that the low threshold for unstable channels is less than that for
-// stable channels.
-TEST_F(UpgradeDetectorImplTest, TestUnstableChannelLowThreshold) {
-  // Grab the low threshold for stable channel.
-  base::TimeDelta default_low_threshold;
-  {
-    TestUpgradeDetectorImpl upgrade_detector(GetMockTickClock());
-    default_low_threshold = upgrade_detector.GetThresholdForLevel(
-        UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
-  }
-
-  // Now make sure that the low threshold for canary is smaller.
-  install_static::ScopedInstallDetails install_details(
-      false, install_static::CANARY_INDEX);
-
-  TestUpgradeDetectorImpl upgrade_detector(GetMockTickClock());
-  EXPECT_LT(upgrade_detector.GetThresholdForLevel(
-                UpgradeDetector::UPGRADE_ANNOYANCE_LOW),
-            default_low_threshold);
-}
-#endif
-
 // Appends the time and stage from detector to |notifications|.
 ACTION_P2(AppendTicksAndStage, detector, notifications) {
   notifications->emplace_back(detector->tick_clock()->NowTicks(),
@@ -349,6 +389,7 @@
 INSTANTIATE_TEST_CASE_P(,
                         UpgradeDetectorImplTimerTest,
                         ::testing::Values(0,           // Default period of 7d.
+                                          86400000,    // 1d.
                                           11100000));  // 3:05:00.
 
 // Tests that the notification timer is handled as desired.
@@ -357,6 +398,8 @@
       std::pair<base::TimeTicks,
                 UpgradeDetector::UpgradeNotificationAnnoyanceLevel>;
   using Notifications = std::vector<TimeAndStage>;
+  static constexpr base::TimeDelta kTwentyMinues =
+      base::TimeDelta::FromMinutes(20);
 
   // Fast forward a little bit to get away from zero ticks, which has special
   // meaning in the detector.
@@ -366,7 +409,9 @@
   ::testing::StrictMock<MockUpgradeObserver> mock_observer(&detector);
 
   // Cache the thresholds for the detector's annoyance levels.
-  const base::TimeDelta thresholds[3] = {
+  const base::TimeDelta thresholds[4] = {
+      detector.GetThresholdForLevel(
+          UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW),
       detector.GetThresholdForLevel(UpgradeDetector::UPGRADE_ANNOYANCE_LOW),
       detector.GetThresholdForLevel(
           UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED),
@@ -377,8 +422,8 @@
   detector.UpgradeDetected(TestUpgradeDetectorImpl::UPGRADE_AVAILABLE_REGULAR);
   ::testing::Mock::VerifyAndClear(&mock_observer);
 
-  // Fast foward to the time that low annoyance should be reached. One
-  // notification should come in at exactly the low annoyance threshold.
+  // Fast forward to the time that very low annoyance should be reached. One
+  // notification should come in at exactly the very low annoyance threshold.
   Notifications notifications;
   EXPECT_CALL(mock_observer, OnUpgradeRecommended())
       .WillOnce(AppendTicksAndStage(&detector, &notifications));
@@ -387,7 +432,26 @@
   EXPECT_THAT(notifications,
               ::testing::ContainerEq(Notifications({TimeAndStage(
                   detector.upgrade_detected_time() + thresholds[0],
-                  UpgradeDetector::UPGRADE_ANNOYANCE_LOW)})));
+                  UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW)})));
+
+  // Move to the time that low annoyance should be reached. Notifications at
+  // very low annoyance should arrive every 20 minutes with one final
+  // notification at elevated annoyance.
+  notifications.clear();
+  EXPECT_CALL(mock_observer, OnUpgradeRecommended())
+      .WillRepeatedly(AppendTicksAndStage(&detector, &notifications));
+  FastForwardBy(thresholds[1] - thresholds[0]);
+  ::testing::Mock::VerifyAndClear(&mock_observer);
+  if (thresholds[1] - thresholds[0] >= kTwentyMinues) {
+    ASSERT_GT(notifications.size(), 1U);
+    EXPECT_EQ((notifications.end() - 2)->second,
+              UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW);
+  } else {
+    EXPECT_EQ(notifications.size(), 1U);
+  }
+  EXPECT_EQ(notifications.back(),
+            TimeAndStage(detector.upgrade_detected_time() + thresholds[1],
+                         UpgradeDetector::UPGRADE_ANNOYANCE_LOW));
 
   // Move to the time that elevated annoyance should be reached. Notifications
   // at low annoyance should arrive every 20 minutes with one final notification
@@ -395,15 +459,14 @@
   notifications.clear();
   EXPECT_CALL(mock_observer, OnUpgradeRecommended())
       .WillRepeatedly(AppendTicksAndStage(&detector, &notifications));
-  FastForwardBy(thresholds[1] - thresholds[0]);
+  FastForwardBy(thresholds[2] - thresholds[1]);
   ::testing::Mock::VerifyAndClear(&mock_observer);
-  EXPECT_THAT(notifications.size(), ::testing::Gt(1U));
-  EXPECT_THAT((notifications.end() - 2)->second,
-              ::testing::Eq(UpgradeDetector::UPGRADE_ANNOYANCE_LOW));
-  EXPECT_THAT(notifications.back(),
-              ::testing::Eq(
-                  TimeAndStage(detector.upgrade_detected_time() + thresholds[1],
-                               UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED)));
+  ASSERT_GT(notifications.size(), 1U);
+  EXPECT_EQ((notifications.end() - 2)->second,
+            UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
+  EXPECT_EQ(notifications.back(),
+            TimeAndStage(detector.upgrade_detected_time() + thresholds[2],
+                         UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED));
 
   // Move to the time that high annoyance should be reached. Notifications at
   // elevated annoyance should arrive every 20 minutes with one final
@@ -411,17 +474,16 @@
   notifications.clear();
   EXPECT_CALL(mock_observer, OnUpgradeRecommended())
       .WillRepeatedly(AppendTicksAndStage(&detector, &notifications));
-  FastForwardBy(thresholds[2] - thresholds[1]);
+  FastForwardBy(thresholds[3] - thresholds[2]);
   ::testing::Mock::VerifyAndClear(&mock_observer);
-  EXPECT_THAT(notifications.size(), ::testing::Gt(1U));
-  EXPECT_THAT((notifications.end() - 2)->second,
-              ::testing::Eq(UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED));
-  EXPECT_THAT(notifications.back(),
-              ::testing::Eq(
-                  TimeAndStage(detector.upgrade_detected_time() + thresholds[2],
-                               UpgradeDetector::UPGRADE_ANNOYANCE_HIGH)));
+  ASSERT_GT(notifications.size(), 1U);
+  EXPECT_EQ((notifications.end() - 2)->second,
+            UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
+  EXPECT_EQ(notifications.back(),
+            TimeAndStage(detector.upgrade_detected_time() + thresholds[3],
+                         UpgradeDetector::UPGRADE_ANNOYANCE_HIGH));
 
   // No new notifications after high annoyance has been reached.
-  FastForwardBy(thresholds[2]);
+  FastForwardBy(thresholds[3]);
   ::testing::Mock::VerifyAndClear(&mock_observer);
 }
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index f08e8dd..728d038 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -240,6 +240,7 @@
     "model/web_vr_model.h",
     "render_loop.cc",
     "render_loop.h",
+    "render_loop_browser_interface.h",
     "sample_queue.cc",
     "sample_queue.h",
     "service/browser_xr_runtime.cc",
diff --git a/chrome/browser/vr/render_loop.cc b/chrome/browser/vr/render_loop.cc
index 38d3ddde..f9d8204 100644
--- a/chrome/browser/vr/render_loop.cc
+++ b/chrome/browser/vr/render_loop.cc
@@ -7,26 +7,84 @@
 #include <utility>
 
 #include "base/time/time.h"
+#include "base/trace_event/common/trace_event_common.h"
 #include "chrome/browser/vr/controller_delegate.h"
+#include "chrome/browser/vr/graphics_delegate.h"
 #include "chrome/browser/vr/input_event.h"
 #include "chrome/browser/vr/model/controller_model.h"
+#include "chrome/browser/vr/render_loop_browser_interface.h"
 #include "chrome/browser/vr/ui_interface.h"
+#include "chrome/browser/vr/ui_renderer.h"
+#include "chrome/browser/vr/ui_test_input.h"
 
 namespace vr {
 
-RenderLoop::RenderLoop(std::unique_ptr<UiInterface> ui) : ui_(std::move(ui)) {}
+RenderLoop::RenderLoop(std::unique_ptr<UiInterface> ui,
+                       RenderLoopBrowserInterface* browser,
+                       size_t sliding_time_size)
+    : ui_(std::move(ui)),
+      browser_(browser),
+      ui_processing_time_(sliding_time_size),
+      ui_controller_update_time_(sliding_time_size) {}
 RenderLoop::~RenderLoop() = default;
 
-void RenderLoop::ProcessControllerInput(const RenderInfo& render_info,
-                                        base::TimeTicks current_time,
-                                        bool is_webxr_frame) {
+void RenderLoop::SetUiExpectingActivityForTesting(
+    UiTestActivityExpectation ui_expectation) {
+  DCHECK(ui_test_state_ == nullptr)
+      << "Attempted to set a UI activity expectation with one in progress";
+  ui_test_state_ = std::make_unique<UiTestState>();
+  ui_test_state_->quiescence_timeout_ms =
+      base::TimeDelta::FromMilliseconds(ui_expectation.quiescence_timeout_ms);
+}
+
+void RenderLoop::UpdateUi(const RenderInfo& render_info,
+                          base::TimeTicks current_time,
+                          FrameType frame_type) {
+  TRACE_EVENT0("gpu", __func__);
+  DCHECK(graphics_delegate_);
+
+  // Update the render position of all UI elements.
+  base::TimeTicks timing_start = base::TimeTicks::Now();
+  bool ui_updated = ui_->OnBeginFrame(current_time, render_info.head_pose);
+
+  // WebXR handles controller input in OnVsync.
+  base::TimeDelta controller_time;
+  if (frame_type == kUiFrame)
+    controller_time =
+        ProcessControllerInput(render_info, current_time, kUiFrame);
+
+  if (ui_->SceneHasDirtyTextures()) {
+    if (!graphics_delegate_->MakeSkiaContextCurrent()) {
+      ForceExitVr();
+      return;
+    }
+    ui_->UpdateSceneTextures();
+    if (!graphics_delegate_->MakeMainContextCurrent()) {
+      ForceExitVr();
+      return;
+    }
+    ui_updated = true;
+  }
+  ReportUiStatusForTesting(timing_start, ui_updated);
+
+  base::TimeDelta scene_time = base::TimeTicks::Now() - timing_start;
+  // Don't double-count the controller time that was part of the scene time.
+  ui_processing_time_.AddSample(scene_time - controller_time);
+  TRACE_EVENT_END0("gpu", "SceneUpdate");
+}
+
+base::TimeDelta RenderLoop::ProcessControllerInput(
+    const RenderInfo& render_info,
+    base::TimeTicks current_time,
+    FrameType frame_type) {
+  TRACE_EVENT0("gpu", __func__);
   DCHECK(controller_delegate_);
   DCHECK(ui_);
+  base::TimeTicks timing_start = base::TimeTicks::Now();
 
-  controller_delegate_->UpdateController(render_info, current_time,
-                                         is_webxr_frame);
+  controller_delegate_->UpdateController(render_info, current_time, frame_type);
   auto input_event_list = controller_delegate_->GetGestures(current_time);
-  if (is_webxr_frame) {
+  if (frame_type == kWebXrFrame) {
     ui_->HandleMenuButtonEvents(&input_event_list);
   } else {
     ReticleModel reticle_model;
@@ -36,6 +94,44 @@
                      &reticle_model, &input_event_list);
     ui_->OnControllerUpdated(controller_model, reticle_model);
   }
+
+  auto controller_time = base::TimeTicks::Now() - timing_start;
+  ui_controller_update_time_.AddSample(controller_time);
+  return controller_time;
+}
+
+void RenderLoop::ForceExitVr() {
+  browser_->ForceExitVr();
+}
+
+void RenderLoop::ReportUiStatusForTesting(const base::TimeTicks& current_time,
+                                          bool ui_updated) {
+  if (ui_test_state_ == nullptr)
+    return;
+  base::TimeDelta time_since_start = current_time - ui_test_state_->start_time;
+  if (ui_updated) {
+    ui_test_state_->activity_started = true;
+    if (time_since_start > ui_test_state_->quiescence_timeout_ms) {
+      // The UI is being updated, but hasn't reached a stable state in the
+      // given time -> report timeout.
+      ReportUiActivityResultForTesting(VrUiTestActivityResult::kTimeoutNoEnd);
+    }
+  } else {
+    if (ui_test_state_->activity_started) {
+      // The UI has been updated since the test requested notification of
+      // quiescence, but wasn't this frame -> report that the UI is quiescent.
+      ReportUiActivityResultForTesting(VrUiTestActivityResult::kQuiescent);
+    } else if (time_since_start > ui_test_state_->quiescence_timeout_ms) {
+      // The UI has never been updated and we've reached the timeout.
+      ReportUiActivityResultForTesting(VrUiTestActivityResult::kTimeoutNoStart);
+    }
+  }
+}
+
+void RenderLoop::ReportUiActivityResultForTesting(
+    VrUiTestActivityResult result) {
+  ui_test_state_ = nullptr;
+  browser_->ReportUiActivityResultForTesting(result);
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/render_loop.h b/chrome/browser/vr/render_loop.h
index 6b04d2e..f9ade7d 100644
--- a/chrome/browser/vr/render_loop.h
+++ b/chrome/browser/vr/render_loop.h
@@ -7,17 +7,25 @@
 
 #include <memory>
 
+#include "base/macros.h"
+#include "chrome/browser/vr/sliding_average.h"
 #include "chrome/browser/vr/vr_export.h"
 
 namespace base {
+class TimeDelta;
 class TimeTicks;
 }
 
 namespace vr {
 
+enum class VrUiTestActivityResult;
 class ControllerDelegate;
+class GraphicsDelegate;
+class RenderLoopBrowserInterface;
 class UiInterface;
 struct RenderInfo;
+struct UiTestActivityExpectation;
+struct UiTestState;
 
 // This abstract class handles all input/output activities during a frame.
 // This includes head movement, controller movement and input, audio output and
@@ -26,16 +34,49 @@
 // VrShellGl and make this class concrete (http://crbug.com/767282).
 class VR_EXPORT RenderLoop {
  public:
-  explicit RenderLoop(std::unique_ptr<UiInterface> ui);
+  enum FrameType { kUiFrame, kWebXrFrame };
+
+  explicit RenderLoop(std::unique_ptr<UiInterface> ui,
+                      RenderLoopBrowserInterface* browser,
+                      size_t sliding_time_size);
   virtual ~RenderLoop();
 
+  void SetUiExpectingActivityForTesting(
+      UiTestActivityExpectation ui_expectation);
+
  protected:
-  void ProcessControllerInput(const RenderInfo& render_info,
-                              base::TimeTicks current_time,
-                              bool is_webxr_frame);
+  // Position, hide and/or show UI elements, process input and update textures.
+  // Returns true if the scene changed.
+  void UpdateUi(const RenderInfo& render_info,
+                base::TimeTicks currrent_time,
+                FrameType frame_type);
+  base::TimeDelta ProcessControllerInput(const RenderInfo& render_info,
+                                         base::TimeTicks current_time,
+                                         FrameType frame_type);
+  void ForceExitVr();
+
+  const SlidingTimeDeltaAverage& ui_controller_update_time() const {
+    return ui_controller_update_time_;
+  }
+  const SlidingTimeDeltaAverage& ui_processing_time() const {
+    return ui_processing_time_;
+  }
 
   std::unique_ptr<UiInterface> ui_;
   std::unique_ptr<ControllerDelegate> controller_delegate_;
+  std::unique_ptr<GraphicsDelegate> graphics_delegate_;
+
+ private:
+  void ReportUiStatusForTesting(const base::TimeTicks& current_time,
+                                bool ui_updated);
+  void ReportUiActivityResultForTesting(VrUiTestActivityResult result);
+
+  RenderLoopBrowserInterface* browser_;
+  std::unique_ptr<UiTestState> ui_test_state_;
+  SlidingTimeDeltaAverage ui_processing_time_;
+  SlidingTimeDeltaAverage ui_controller_update_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderLoop);
 };
 
 }  // namespace vr
diff --git a/chrome/browser/vr/render_loop_browser_interface.h b/chrome/browser/vr/render_loop_browser_interface.h
new file mode 100644
index 0000000..6e7b2f7
--- /dev/null
+++ b/chrome/browser/vr/render_loop_browser_interface.h
@@ -0,0 +1,24 @@
+// 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_VR_RENDER_LOOP_BROWSER_INTERFACE_H_
+#define CHROME_BROWSER_VR_RENDER_LOOP_BROWSER_INTERFACE_H_
+
+#include "chrome/browser/vr/ui_test_input.h"
+
+namespace vr {
+
+// RenderLoop talks to the browser main thread through this interface.
+class RenderLoopBrowserInterface {
+ public:
+  virtual ~RenderLoopBrowserInterface() = default;
+
+  virtual void ForceExitVr() = 0;
+  virtual void ReportUiActivityResultForTesting(
+      const VrUiTestActivityResult& result) = 0;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_RENDER_LOOP_BROWSER_INTERFACE_H_
diff --git a/chrome/browser/web_applications/components/web_app_icon_downloader.h b/chrome/browser/web_applications/components/web_app_icon_downloader.h
index 80b58f5d..3759c7e 100644
--- a/chrome/browser/web_applications/components/web_app_icon_downloader.h
+++ b/chrome/browser/web_applications/components/web_app_icon_downloader.h
@@ -42,9 +42,6 @@
       WebAppIconDownloaderCallback;
   // |extra_favicon_urls| allows callers to provide icon urls that aren't
   // provided by the renderer (e.g touch icons on non-android environments).
-  // |skip_page_favicons| instructs the downloader to not query the page
-  // for favicons (e.g. when a favicon URL has already been provided in
-  // |extra_favicon_urls|).
   // |https_status_code_class_histogram_name| optionally specifies a histogram
   // to use for logging http status code class results from fetch attempts.
   WebAppIconDownloader(content::WebContents* web_contents,
@@ -53,6 +50,9 @@
                        WebAppIconDownloaderCallback callback);
   ~WebAppIconDownloader() override;
 
+  // Instructs the downloader to not query the page for favicons (e.g. when a
+  // favicon URL has already been provided in the constructor's
+  // |extra_favicon_urls| argument).
   void SkipPageFavicons();
 
   void Start();
diff --git a/chrome/browser/win/OWNERS b/chrome/browser/win/OWNERS
index 2621204..a62aa9c 100644
--- a/chrome/browser/win/OWNERS
+++ b/chrome/browser/win/OWNERS
@@ -4,9 +4,7 @@
 pmonette@chromium.org
 
 # per-file rules:
-per-file chrome_elf_init*=csharp@chromium.org
-per-file chrome_elf_init*=robertshield@chromium.org
-
+per-file chrome_elf_init*=file://chrome_elf/OWNERS
 per-file enumerate_modules_model*=finnur@chromium.org
 
 # COMPONENT: Internals>Core
diff --git a/chrome/chrome_cleaner/BUILD.gn b/chrome/chrome_cleaner/BUILD.gn
index c85bcc5..13fd3e8 100644
--- a/chrome/chrome_cleaner/BUILD.gn
+++ b/chrome/chrome_cleaner/BUILD.gn
@@ -11,29 +11,33 @@
   ]
 
   deps = [
+    # Dependencies of the test harness.
     ":other_executable_definitions",
+    "//base",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/crash:crashpad_lib",
     "//chrome/chrome_cleaner/engines:resources",
+    "//chrome/chrome_cleaner/ipc:sandbox",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/os:cleaner_os",
+    "//chrome/chrome_cleaner/os:common_os",
     "//chrome/chrome_cleaner/os:common_os",
     "//chrome/chrome_cleaner/pup_data:pup_data_base",
+    "//chrome/chrome_cleaner/settings:settings_types",
     "//chrome/chrome_cleaner/test:test_pup_data",
+    "//chrome/chrome_cleaner/test:test_util",
+    "//sandbox/win:sandbox",
+    "//testing/gtest",
 
     # Tests from sub-directories.
     "//chrome/chrome_cleaner/http:unittest_sources",
+    "//chrome/chrome_cleaner/ipc:unittest_sources",
     "//chrome/chrome_cleaner/logging:unittest_sources",
     "//chrome/chrome_cleaner/os:unittest_sources",
     "//chrome/chrome_cleaner/pup_data:unittest_sources",
     "//chrome/chrome_cleaner/settings:unittest_sources",
     "//chrome/chrome_cleaner/strings:unittest_sources",
     "//chrome/chrome_cleaner/test:unittest_sources",
-
-    # Dependencies of the test harness.
-    "//base",
-    "//base/test:test_support",
-    "//chrome/chrome_cleaner/os:cleaner_os",
-    "//chrome/chrome_cleaner/os:common_os",
-    "//chrome/chrome_cleaner/test:test_util",
-    "//sandbox/win:sandbox",
-    "//testing/gtest",
   ]
 }
 
diff --git a/chrome/chrome_cleaner/constants/chrome_cleaner_switches.cc b/chrome/chrome_cleaner/constants/chrome_cleaner_switches.cc
index b843f83..e563d52 100644
--- a/chrome/chrome_cleaner/constants/chrome_cleaner_switches.cc
+++ b/chrome/chrome_cleaner/constants/chrome_cleaner_switches.cc
@@ -29,7 +29,8 @@
 
 // Dump the raw logs to a file with the same base name as the executable. The
 // dumped file is a raw protobuf and has a "pb" extension.
-// WARNING: this switch is used internally. Be careful when making changes.
+// WARNING: this switch is used by internal test systems. Be careful when making
+// changes.
 const char kDumpRawLogsSwitch[] = "dump-raw-logs";
 
 // Identify that the process is already supposed to be elevated, so that we
@@ -48,7 +49,8 @@
 
 // Log all removable UwS that were not detected, but the scanner found some
 // UwS-related footprints.
-// WARNING: this switch is used internally. Be careful when making changes.
+// WARNING: this switch is used by internal test systems. Be careful when making
+// changes.
 const char kForceUwsDetectionSwitch[] = "force-uws-detection";
 
 // The handle of an event to signal when the initialization of the main process
@@ -82,7 +84,8 @@
 const char kNoRecoveryComponentSwitch[] = "no-recovery-component";
 
 // Prevent the logging service from uploading logs and reports.
-// WARNING: this switch is used internally, be careful when making changes.
+// WARNING: this switch is used by internal test systems, be careful when making
+// changes.
 const char kNoReportUploadSwitch[] = "no-report-upload";
 
 // Prevent the executable from deleting itself after running.
@@ -131,7 +134,8 @@
 
 // Flag set during testing and stored as a crash key, to differentiate from
 // crashes received from actual users.
-// WARNING: this switch is used internally, be careful when making changes.
+// WARNING: this switch is used by internal test systems, be careful when making
+// changes.
 const char kTestingSwitch[] = "testing";
 
 // Specifies the full path to a protocol buffer log file to be uploaded.
diff --git a/chrome/chrome_cleaner/crash/BUILD.gn b/chrome/chrome_cleaner/crash/BUILD.gn
new file mode 100644
index 0000000..9187ab82
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/BUILD.gn
@@ -0,0 +1,38 @@
+# 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.
+
+source_set("crash_keys") {
+  sources = [
+    "crash_keys.cc",
+    "crash_keys.h",
+  ]
+
+  deps = [
+    "//base:base",
+    "//third_party/crashpad/crashpad/client:client",
+  ]
+}
+
+source_set("crashpad_lib") {
+  sources = [
+    "crash_client.h",
+    "crash_reporter.h",
+    "crashpad_crash_client.cc",
+    "crashpad_crash_client.h",
+    "crashpad_crash_reporter.cc",
+  ]
+
+  deps = [
+    ":crash_keys",
+    "//base:base",
+    "//chrome/chrome_cleaner/chrome_utils:chrome_util_lib",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/settings:settings",
+    "//chrome/chrome_cleaner/settings:settings_types",
+    "//third_party/crashpad/crashpad/client",
+    "//third_party/crashpad/crashpad/handler",
+  ]
+}
diff --git a/chrome/chrome_cleaner/crash/DEPS b/chrome/chrome_cleaner/crash/DEPS
new file mode 100644
index 0000000..93ee7f1
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/crashpad",
+]
diff --git a/chrome/chrome_cleaner/crash/crash_client.h b/chrome/chrome_cleaner/crash/crash_client.h
new file mode 100644
index 0000000..c5e8d030
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crash_client.h
@@ -0,0 +1,56 @@
+// 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_CHROME_CLEANER_CRASH_CRASH_CLIENT_H_
+#define CHROME_CHROME_CLEANER_CRASH_CRASH_CLIENT_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/synchronization/lock.h"
+#include "chrome/chrome_cleaner/settings/settings_types.h"
+
+namespace chrome_cleaner {
+
+// This class manages interaction with the crash reporter.
+class CrashClient {
+ public:
+  enum class Mode { REPORTER, CLEANER, MODE_COUNT };
+
+  static CrashClient* GetInstance();
+
+  // Set |client_id| to the current guid associated with crashes. |client_id|
+  // may be empty if no guid is associated.
+  static void GetClientId(base::string16* client_id);
+
+  // Returns whether upload of crashes is enabled or not.
+  static bool IsUploadEnabled();
+
+  CrashClient() = default;
+  virtual ~CrashClient() = default;
+
+  // Initializes collection and upload of crash reports. This will only be done
+  // if the user has agreed to crash dump reporting.
+  //
+  // Crash reporting has to be initialized as early as possible (e.g., the first
+  // thing in main()) to catch crashes occurring during process startup. Crashes
+  // which occur during the global static construction phase will not be caught
+  // and reported. This should not be a problem as static non-POD objects are
+  // not allowed by the style guide and exceptions to this rule are rare.
+  //
+  // |mode| controls a custom info entry present in the generated dumps to allow
+  // distinguishing between cleaner and reporter crashes on the backend.
+  //
+  // |process_type| identifies the type of process that reported the crash.
+  virtual bool InitializeCrashReporting(Mode mode,
+                                        SandboxType process_type) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CrashClient);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_CRASH_CRASH_CLIENT_H_
diff --git a/chrome/chrome_cleaner/crash/crash_keys.cc b/chrome/chrome_cleaner/crash/crash_keys.cc
new file mode 100644
index 0000000..d7d96f34
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crash_keys.cc
@@ -0,0 +1,83 @@
+// 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/chrome_cleaner/crash/crash_keys.h"
+
+#include "base/command_line.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "third_party/crashpad/crashpad/client/crashpad_info.h"
+#include "third_party/crashpad/crashpad/client/simple_string_dictionary.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+base::Lock& GetCrashKeyLock() {
+  static base::Lock* crash_key_lock = new base::Lock();
+  return *crash_key_lock;
+}
+
+crashpad::SimpleStringDictionary* GetCrashKeys() {
+  // TODO(crbug.com/870715): Use the new crash key API from
+  // https://cs.chromium.org/chromium/src/components/crash/core/common/crash_key.h
+  static crashpad::SimpleStringDictionary* crash_keys =
+      new crashpad::SimpleStringDictionary();
+  return crash_keys;
+}
+
+void SetCrashKeyInDictionary(crashpad::SimpleStringDictionary* crash_keys,
+                             base::StringPiece key,
+                             base::StringPiece value) {
+  if (crash_keys->GetValueForKey(key))
+    LOG(WARNING) << "Crash key \"" << key << "\" being overwritten";
+  else
+    DCHECK_LT(crash_keys->GetCount(), crash_keys->num_entries);
+  crash_keys->SetKeyValue(key, value);
+}
+
+}  // namespace
+
+void SetCrashKey(base::StringPiece key, base::StringPiece value) {
+  base::AutoLock lock(GetCrashKeyLock());
+  SetCrashKeyInDictionary(GetCrashKeys(), key, value);
+}
+
+void SetCrashKeysFromCommandLine() {
+  // Based on Chrome's crash_keys::SetSwitchesFromCommandLine.
+  static constexpr size_t kMaxArgs = 16;
+  static constexpr char kKeyFormat[] = "CommandLineArg-%02" PRIuS;
+  static constexpr char kSizeKey[] = "CommandLineSize";
+
+  base::AutoLock lock(GetCrashKeyLock());
+  crashpad::SimpleStringDictionary* crash_keys = GetCrashKeys();
+
+  // Make sure this was only called once.
+  DCHECK(!crash_keys->GetValueForKey(kSizeKey));
+
+  const base::CommandLine::StringVector& argv =
+      base::CommandLine::ForCurrentProcess()->argv();
+
+  // Record the true number of arguments in case there are too many to store.
+  SetCrashKeyInDictionary(crash_keys, kSizeKey,
+                          base::NumberToString(argv.size()));
+
+  // Go through the argv, including the exec path in argv[0]. Stop if there are
+  // too many arguments to hold in crash keys.
+  for (size_t key_i = 0; key_i < argv.size() && key_i < kMaxArgs; ++key_i) {
+    SetCrashKeyInDictionary(crash_keys, base::StringPrintf(kKeyFormat, key_i),
+                            base::WideToUTF8(argv[key_i]));
+  }
+}
+
+void UseCrashKeysToAnnotate(crashpad::CrashpadInfo* crashpad_info) {
+  crashpad_info->set_simple_annotations(GetCrashKeys());
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/crash/crash_keys.h b/chrome/chrome_cleaner/crash/crash_keys.h
new file mode 100644
index 0000000..6a5757db
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crash_keys.h
@@ -0,0 +1,39 @@
+// 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_CHROME_CLEANER_CRASH_CRASH_KEYS_H_
+#define CHROME_CHROME_CLEANER_CRASH_CRASH_KEYS_H_
+
+#include <string>
+
+#include "base/strings/string_piece_forward.h"
+
+namespace crashpad {
+
+// Forward-declare CrashpadInfo instead of including crashpad_info.h because
+// the header pulls in extra dependencies that would need to be inherited by
+// every file using crash_keys.h.
+struct CrashpadInfo;
+
+}  // namespace crashpad
+
+namespace chrome_cleaner {
+
+// Sets the crash key |key| to the specified |value|. The key will be
+// overwritten if it was already present. This is thread-safe.
+void SetCrashKey(base::StringPiece key, base::StringPiece value);
+
+// Records the current process's command-line in a set of crash keys. This is
+// thread-safe.
+void SetCrashKeysFromCommandLine();
+
+// Sets |crashpad_info| to use this process's crash key dictionary for
+// annotations. Note the annotations are not used in a thread-safe way by
+// Crashpad, but that should be acceptable because they are only used while
+// dumping a crash.
+void UseCrashKeysToAnnotate(crashpad::CrashpadInfo* crashpad_info);
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_CRASH_CRASH_KEYS_H_
diff --git a/chrome/chrome_cleaner/crash/crash_reporter.h b/chrome/chrome_cleaner/crash/crash_reporter.h
new file mode 100644
index 0000000..7ef069f
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crash_reporter.h
@@ -0,0 +1,29 @@
+// 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_CHROME_CLEANER_CRASH_CRASH_REPORTER_H_
+#define CHROME_CHROME_CLEANER_CRASH_CRASH_REPORTER_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+
+// Starts a new instance of this executable running as the crash reporter
+// process.
+void StartCrashReporter(const std::string version);
+
+// Runs the crash reporter message loop within the current process. On return,
+// the current process should exit.
+int CrashReporterMain();
+
+// Returns the name of the IPC pipe that is used to communicate with the crash
+// reporter process, or an empty string if the current process is not connected
+// to a crash reporter process.
+base::string16 GetCrashReporterIPCPipeName();
+
+// Uses the crash reporter with the specified |ipc_pipe_name|, instead of
+// starting a new crash reporter process.
+void UseCrashReporter(const base::string16& ipc_pipe_name);
+
+#endif  // CHROME_CHROME_CLEANER_CRASH_CRASH_REPORTER_H_
diff --git a/chrome/chrome_cleaner/crash/crashpad_crash_client.cc b/chrome/chrome_cleaner/crash/crashpad_crash_client.cc
new file mode 100644
index 0000000..dff783df
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crashpad_crash_client.cc
@@ -0,0 +1,358 @@
+// 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/chrome_cleaner/crash/crashpad_crash_client.h"
+
+#include <process.h>
+#include <psapi.h>
+#include <stdio.h>
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/win/wrapped_window_proc.h"
+#include "chrome/chrome_cleaner/chrome_utils/chrome_util.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/crash/crash_keys.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
+#include "chrome/chrome_cleaner/settings/settings.h"
+#include "chrome/chrome_cleaner/settings/settings_types.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
+#include "third_party/crashpad/crashpad/client/crashpad_client.h"
+#include "third_party/crashpad/crashpad/client/crashpad_info.h"
+#include "third_party/crashpad/crashpad/client/settings.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+base::LazyInstance<base::Lock>::Leaky record_memory_usage_and_crash_lock =
+    LAZY_INSTANCE_INITIALIZER;
+
+// NOTE: the following functions will be executed when the application is likely
+// in the process of crashing. That could be because there is no memory left, so
+// we must avoid allocating memory when they are run.
+
+// Helper function to format a DWORD value to a string. Does not allocate
+// memory. The returned value is valid until the next call to this function.
+// This function is not thread-safe.
+const char* ConvertDwordToString(DWORD value) {
+  static_assert(sizeof(value) == 4, "DWORD is not 32 bits?");
+
+  // The maximum value represented by a DWORD value is 4294967295, which is 10
+  // characters long. Leave space for a NULL terminator character.
+  static char buffer[11] = {};
+
+  _snprintf(buffer, base::size(buffer), "%u", value);
+  buffer[base::size(buffer) - 1] = '\0';
+  return buffer;
+}
+
+// Helper function to format a SIZE_T value to a string. Does not allocate
+// memory. The returned value is valid until the next call to this function.
+// This function is not thread-safe.
+const char* ConvertSizeTToString(SIZE_T value) {
+  static_assert(sizeof(value) <= 8, "SIZE_T is more than 64 bits?");
+
+  // The maximum value represented by a 64-bit SIZE_T value is
+  // 18446744073709551616, which is 20 characters long. Leave space for a NULL
+  // terminator character.
+  static char buffer[21] = {};
+
+  _snprintf(buffer, base::size(buffer), "%Iu", value);
+  buffer[base::size(buffer) - 1] = '\0';
+  return buffer;
+}
+
+// Exception handler. Adds crash keys with memory usage information, then
+// hands control over to the Crashpad crash handler.
+LONG WINAPI RecordMemoryUsageAndCrash(EXCEPTION_POINTERS* exception_pointers) {
+  static PROCESS_MEMORY_COUNTERS counters = {};
+
+  {
+    base::AutoLock auto_lock(record_memory_usage_and_crash_lock.Get());
+
+    // Call GetProcessMemoryInfo directly instead of using base::ProcessMetrics,
+    // to keep stack allocations to a minimum.
+    if (GetProcessMemoryInfo(GetCurrentProcess(), &counters,
+                             sizeof(counters))) {
+      // Crashpad pre-allocates space for 64 crash keys, so setting these here
+      // does not allocate memory. Both key and value can be up to 256
+      // characters long.
+      SetCrashKey("PageFaultCount",
+                  ConvertDwordToString(counters.PageFaultCount));
+      SetCrashKey("PeakWorkingSetSize",
+                  ConvertSizeTToString(counters.PeakWorkingSetSize));
+      SetCrashKey("WorkingSetSize",
+                  ConvertSizeTToString(counters.WorkingSetSize));
+      SetCrashKey("QuotaPeakPagedPoolUsage",
+                  ConvertSizeTToString(counters.QuotaPeakPagedPoolUsage));
+      SetCrashKey("QuotaPagedPoolUsage",
+                  ConvertSizeTToString(counters.QuotaPagedPoolUsage));
+      SetCrashKey("QuotaPeakNonPagedPoolUsage",
+                  ConvertSizeTToString(counters.QuotaPeakNonPagedPoolUsage));
+      SetCrashKey("QuotaNonPagedPoolUsage",
+                  ConvertSizeTToString(counters.QuotaNonPagedPoolUsage));
+      SetCrashKey("PagefileUsage",
+                  ConvertSizeTToString(counters.PagefileUsage));
+      SetCrashKey("PeakPagefileUsage",
+                  ConvertSizeTToString(counters.PeakPagefileUsage));
+    }
+  }
+
+  crashpad::CrashpadClient::DumpAndCrash(exception_pointers);
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// Wraps the DumpAndCrash function info a function that has the right return
+// type to be passed to base::win::SetWinProcExceptionFilter.
+int __cdecl HandleWinProcException(EXCEPTION_POINTERS* info) {
+  return RecordMemoryUsageAndCrash(info);
+}
+
+}  // namespace
+
+// static
+CrashClient* CrashClient::GetInstance() {
+  return CrashpadCrashClient::GetInstance();
+}
+
+// static
+void CrashClient::GetClientId(base::string16* client_id) {
+  CrashpadCrashClient::GetClientId(client_id);
+}
+
+// static
+bool CrashClient::IsUploadEnabled() {
+  return CrashpadCrashClient::IsUploadEnabled();
+}
+
+CrashpadCrashClient::~CrashpadCrashClient() = default;
+
+bool CrashpadCrashClient::InitializeDatabaseOnly() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  base::FilePath database_path;
+  if (!chrome_cleaner::GetAppDataProductDirectory(&database_path)) {
+    LOG(ERROR) << "Failed to get AppData product directory";
+    return false;
+  }
+
+  database_.reset(
+      crashpad::CrashReportDatabase::Initialize(database_path).release());
+  if (!database_) {
+    LOG(ERROR) << "Failed to initialize Crashpad database.";
+    return false;
+  }
+
+  return true;
+}
+
+bool CrashpadCrashClient::InitializeCrashReporting(Mode mode,
+                                                   SandboxType process_type) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  static bool initialized = false;
+  DCHECK(!initialized);
+  initialized = true;
+
+  UseCrashKeysToAnnotate(crashpad::CrashpadInfo::GetCrashpadInfo());
+
+  SetCrashKey("pid", base::NumberToString(_getpid()));
+
+  static_assert(static_cast<int>(Mode::MODE_COUNT) == 2,
+                "Update the annotation below if a new Mode is added");
+  constexpr char kModeString[] = "mode";
+  switch (mode) {
+    case Mode::REPORTER:
+      SetCrashKey(kModeString, "reporter");
+      break;
+    case Mode::CLEANER:
+      SetCrashKey(kModeString, "cleaner");
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  constexpr char kProcessType[] = "process_type";
+  switch (process_type) {
+    case SandboxType::kNonSandboxed:
+      SetCrashKey(kProcessType, "broker");
+      break;
+    case SandboxType::kEset:
+      SetCrashKey(kProcessType, "eset");
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  SetCrashKey("uma", Settings::GetInstance()->metrics_enabled() ? "1" : "0");
+
+  SetCrashKey("testing",
+              base::CommandLine::ForCurrentProcess()->HasSwitch(kTestingSwitch)
+                  ? "1"
+                  : "0");
+
+  base::string16 chrome_version;
+  bool chrome_system_install;
+  RetrieveChromeVersionAndInstalledDomain(&chrome_version,
+                                          &chrome_system_install);
+  SetCrashKey("ChromeVersion", base::UTF16ToUTF8(chrome_version));
+  SetCrashKey("ChromeSystemInstall", chrome_system_install ? "1" : "0");
+
+  SetCrashKeysFromCommandLine();
+
+  static_assert(static_cast<int>(Mode::MODE_COUNT) == 2,
+                "Update the condition below if a new Mode is added");
+  if (mode == Mode::CLEANER)
+    SetCrashKey("CleanupId", Settings::GetInstance()->cleanup_id());
+
+  const std::string engine_version = Settings::GetInstance()->engine_version();
+  if (!engine_version.empty())
+    SetCrashKey("EngineVersion", engine_version);
+
+  if (!InitializeDatabaseOnly())
+    return false;
+
+  // Replace Crashpad's exception filter with our own filter, which records
+  // memory usage at the time of the crash, then tells Crashpad to dump and
+  // crash.
+  SetUnhandledExceptionFilter(&RecordMemoryUsageAndCrash);
+
+  // Catch exceptions thrown from a window procedure.
+  base::win::WinProcExceptionFilter exception_filter =
+      base::win::SetWinProcExceptionFilter(&HandleWinProcException);
+  LOG_IF(DFATAL, exception_filter) << "Exception filter already present";
+
+  // Log completed crash reports in the logs that will be uploaded to Safe
+  // Browsing.
+  std::vector<crashpad::CrashReportDatabase::Report> completed_reports;
+  const crashpad::CrashReportDatabase::OperationStatus status_completed =
+      database_->GetCompletedReports(&completed_reports);
+  if (status_completed == crashpad::CrashReportDatabase::kNoError) {
+    LOG(INFO) << "Found " << completed_reports.size()
+              << " completed crash reports";
+    for (const auto& report : completed_reports) {
+      LOG(INFO) << "Crash since last run: ID \"" << report.id
+                << "\", created at " << report.creation_time << ", "
+                << report.upload_attempts << " upload attempts, file path \""
+                << SanitizePath(report.file_path) << "\", unique ID \""
+                << report.uuid.ToString()
+                << "\"; uploaded: " << (report.uploaded ? "yes" : "no");
+    }
+  } else {
+    LOG(ERROR) << "Failed to fetch completed crash reports: "
+               << status_completed;
+  }
+
+  std::vector<crashpad::CrashReportDatabase::Report> pending_reports;
+  const crashpad::CrashReportDatabase::OperationStatus status_pending =
+      database_->GetPendingReports(&pending_reports);
+  if (status_pending == crashpad::CrashReportDatabase::kNoError) {
+    LOG(INFO) << "Found " << pending_reports.size() << " pending crash reports";
+    for (const auto& report : pending_reports) {
+      LOG(INFO) << "Crash since last run: (pending), created at "
+                << report.creation_time << ", " << report.upload_attempts
+                << " upload attempts, file path \""
+                << SanitizePath(report.file_path) << "\", unique ID \""
+                << report.uuid.ToString() << "\"";
+    }
+  } else {
+    LOG(ERROR) << "Failed to fetch pending crash reports: " << status_pending;
+  }
+
+  DeleteStaleReports();
+
+  // Enable or disable crash reporting based on settings.
+  crashpad::Settings* crashpad_settings = database_->GetSettings();
+  DCHECK(crashpad_settings);
+  crashpad_settings->SetUploadsEnabled(
+      Settings::GetInstance()->allow_crash_report_upload());
+
+  return true;
+}
+
+void CrashpadCrashClient::DeleteStaleReports() {
+  const int kMaxReportCount = 3;
+
+  std::vector<crashpad::CrashReportDatabase::Report> completed_reports;
+  if (database_->GetCompletedReports(&completed_reports) !=
+      crashpad::CrashReportDatabase::kNoError) {
+    return;
+  }
+
+  std::vector<crashpad::CrashReportDatabase::Report> not_uploaded_reports;
+  for (const auto& report : completed_reports) {
+    if (report.uploaded)
+      database_->DeleteReport(report.uuid);
+    else
+      not_uploaded_reports.push_back(report);
+  }
+
+  // Sort reports from newest to oldest, then delete all but the newest
+  // kMaxReportCount reports.
+  std::sort(not_uploaded_reports.begin(), not_uploaded_reports.end(),
+            [](const auto& report1, const auto& report2) {
+              return report1.creation_time > report2.creation_time;
+            });
+  for (size_t i = kMaxReportCount; i < not_uploaded_reports.size(); ++i)
+    database_->DeleteReport(not_uploaded_reports[i].uuid);
+}
+
+// static
+CrashpadCrashClient* CrashpadCrashClient::GetInstance() {
+  return base::Singleton<CrashpadCrashClient, base::LeakySingletonTraits<
+                                                  CrashpadCrashClient>>::get();
+}
+
+// static
+void CrashpadCrashClient::GetClientId(base::string16* client_id) {
+  DCHECK(client_id);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(GetInstance()->sequence_checker_);
+  DCHECK(GetInstance()->database_) << "Crash reporting not initialized";
+  crashpad::Settings* settings = GetInstance()->database_->GetSettings();
+  DCHECK(settings);
+
+  crashpad::UUID uuid;
+  if (!settings->GetClientID(&uuid)) {
+    LOG(ERROR) << "Unable to retrieve client ID from Crashpad database";
+    *client_id = base::string16();
+    return;
+  }
+
+  std::string uuid_string = uuid.ToString();
+  base::ReplaceSubstringsAfterOffset(&uuid_string, 0, "-", "");
+  *client_id = base::UTF8ToWide(uuid_string);
+}
+
+// static
+bool CrashpadCrashClient::IsUploadEnabled() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(GetInstance()->sequence_checker_);
+  DCHECK(GetInstance()->database_) << "Crash reporting not initialized";
+  crashpad::Settings* settings = GetInstance()->database_->GetSettings();
+  DCHECK(settings);
+  bool upload_enabled = false;
+  if (settings->GetUploadsEnabled(&upload_enabled)) {
+    return upload_enabled;
+  } else {
+    LOG(ERROR) << "Unable to verify if crash uploads are enabled or not";
+    return false;
+  }
+}
+
+CrashpadCrashClient::CrashpadCrashClient() = default;
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/crash/crashpad_crash_client.h b/chrome/chrome_cleaner/crash/crashpad_crash_client.h
new file mode 100644
index 0000000..435ab12
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crashpad_crash_client.h
@@ -0,0 +1,67 @@
+// 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_CHROME_CLEANER_CRASH_CRASHPAD_CRASH_CLIENT_H_
+#define CHROME_CHROME_CLEANER_CRASH_CRASHPAD_CRASH_CLIENT_H_
+
+#include <map>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string16.h"
+#include "chrome/chrome_cleaner/crash/crash_client.h"
+#include "chrome/chrome_cleaner/settings/settings_types.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace chrome_cleaner {
+
+// This class manages interaction with the Crashpad reporter.
+class CrashpadCrashClient : public CrashClient {
+ public:
+  ~CrashpadCrashClient() override;
+
+  // Initializes the crash database only. Used in the crash reporter, which
+  // cannot connect to itself to upload its own crashes.
+  bool InitializeDatabaseOnly();
+
+  crashpad::CrashReportDatabase* database() { return database_.get(); }
+
+  // CrashClient:
+  bool InitializeCrashReporting(Mode mode, SandboxType process_type) override;
+
+  static CrashpadCrashClient* GetInstance();
+
+  // Sets |client_id| to the current guid associated with crashes. |client_id|
+  // may be empty if no guid is associated.
+  static void GetClientId(base::string16* client_id);
+
+  // Returns whether upload of crashes is enabled or not.
+  static bool IsUploadEnabled();
+
+ private:
+  friend class base::Singleton<CrashpadCrashClient>;
+  friend struct base::DefaultSingletonTraits<CrashpadCrashClient>;
+
+  CrashpadCrashClient();
+
+  // Removes already uploaded reports and limits the number of reports that
+  // stay on disk.
+  void DeleteStaleReports();
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  std::unique_ptr<crashpad::CrashReportDatabase> database_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrashpadCrashClient);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_CRASH_CRASHPAD_CRASH_CLIENT_H_
diff --git a/chrome/chrome_cleaner/crash/crashpad_crash_reporter.cc b/chrome/chrome_cleaner/crash/crashpad_crash_reporter.cc
new file mode 100644
index 0000000..9080cd5
--- /dev/null
+++ b/chrome/chrome_cleaner/crash/crashpad_crash_reporter.cc
@@ -0,0 +1,161 @@
+// 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 <algorithm>
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/crash/crashpad_crash_client.h"
+#include "chrome/chrome_cleaner/logging/scoped_logging.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
+#include "chrome/chrome_cleaner/os/system_util.h"
+#include "third_party/crashpad/crashpad/client/crashpad_client.h"
+#include "third_party/crashpad/crashpad/handler/handler_main.h"
+
+namespace {
+
+// The URL where crash reports are uploaded.
+const char kReportUploadURL[] = "https://clients2.google.com/cr/report";
+
+// Whether the current process is connected to a crash handler process.
+bool g_is_connected_to_crash_handler = false;
+
+}  // namespace
+
+crashpad::CrashpadClient* GetCrashpadClient() {
+  static auto* crashpad_client = new crashpad::CrashpadClient();
+  return crashpad_client;
+}
+
+void AppendSwitchIfExisting(const base::CommandLine& command_line,
+                            const std::string& switch_name,
+                            std::vector<std::string>* arguments) {
+  if (command_line.HasSwitch(switch_name)) {
+    // String format: --%s=%s
+    arguments->push_back(
+        base::StrCat({"--", switch_name, "=",
+                      command_line.GetSwitchValueASCII(switch_name)}));
+  }
+}
+
+void StartCrashReporter(const std::string version) {
+  static bool started = false;
+  DCHECK(!started);
+  started = true;
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+  base::FilePath handler_path =
+      chrome_cleaner::PreFetchedPaths::GetInstance()->GetExecutablePath();
+
+  base::FilePath database_path;
+  if (!chrome_cleaner::GetAppDataProductDirectory(&database_path)) {
+    LOG(DFATAL) << "Failed to get AppData product directory";
+    return;
+  }
+
+  std::map<std::string, std::string> annotations;  // Crash keys.
+  annotations["ver"] = version;
+  annotations["prod"] = "ChromeFoil";
+  annotations["plat"] = "Win32";
+
+  std::vector<std::string> arguments;
+  arguments.push_back(
+      base::StrCat({"--", chrome_cleaner::kCrashHandlerSwitch}));
+
+  AppendSwitchIfExisting(*command_line, chrome_cleaner::kTestLoggingURLSwitch,
+                         &arguments);
+  AppendSwitchIfExisting(*command_line, chrome_cleaner::kCleanupIdSwitch,
+                         &arguments);
+
+  crashpad::CrashpadClient* client = GetCrashpadClient();
+  if (!client->StartHandler(handler_path, database_path,
+                            /*metrics_dir=*/base::FilePath(), kReportUploadURL,
+                            annotations, arguments, /*restartable=*/true,
+                            /*asynchronous_start=*/false)) {
+    LOG(DFATAL) << "Failed to start handler.";
+  } else {
+    g_is_connected_to_crash_handler = true;
+    LOG(INFO) << "Crash handler launched and ready.";
+  }
+}
+
+void RemoveSwitchIfExisting(const char* const switch_to_remove,
+                            std::vector<base::string16>* argv) {
+  const base::string16 pattern =
+      base::StrCat({L"--", base::UTF8ToWide(switch_to_remove)});
+  auto matches_switch = [&pattern](const base::string16& argument) -> bool {
+    return base::StartsWith(argument, pattern, base::CompareCase::SENSITIVE);
+  };
+  argv->erase(std::remove_if(argv->begin(), argv->end(), matches_switch),
+              argv->end());
+}
+
+int CrashReporterMain() {
+  chrome_cleaner::ScopedLogging scoped_logging(L"-crashpad");
+
+  // Make sure not to take too much of the machines's resources.
+  chrome_cleaner::SetBackgroundMode();
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  // This function should only run if --crash-handler switch is present.
+  DCHECK(command_line->HasSwitch(chrome_cleaner::kCrashHandlerSwitch));
+
+  std::vector<base::string16> argv = command_line->argv();
+
+  // Because of https://bugs.chromium.org/p/crashpad/issues/detail?id=82,
+  // Crashpad fails on the presence of flags it doesn't handle. Until that bug
+  // is fixed, we need to remove any custom flag passed by the cleaner to the
+  // Crashpad process.
+  RemoveSwitchIfExisting(chrome_cleaner::kCrashHandlerSwitch, &argv);
+  RemoveSwitchIfExisting(chrome_cleaner::kTestLoggingURLSwitch, &argv);
+  RemoveSwitchIfExisting(chrome_cleaner::kCleanupIdSwitch, &argv);
+
+  // Disable rate-limiting until this is fixed:
+  //   https://bugs.chromium.org/p/crashpad/issues/detail?id=23
+  argv.push_back(L"--no-rate-limit");
+
+  // |storage| must be declared before |argv_as_utf8|, to ensure it outlives
+  // |argv_as_utf8|, which will hold pointers into |storage|.
+  std::vector<std::string> storage;
+  std::unique_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
+  storage.reserve(argv.size());
+  for (size_t i = 0; i < argv.size(); ++i) {
+    storage.push_back(base::UTF16ToUTF8(argv[i]));
+    argv_as_utf8[i] = &storage[i][0];
+  }
+  argv_as_utf8[argv.size()] = nullptr;
+
+  return crashpad::HandlerMain(static_cast<int>(argv.size()),
+                               argv_as_utf8.get(),
+                               /* user_stream_sources */ nullptr);
+}
+
+base::string16 GetCrashReporterIPCPipeName() {
+  return g_is_connected_to_crash_handler
+             ? GetCrashpadClient()->GetHandlerIPCPipe()
+             : base::string16();
+}
+
+void UseCrashReporter(const base::string16& ipc_pipe_name) {
+  DCHECK(!ipc_pipe_name.empty());
+  crashpad::CrashpadClient* crashpad_client = GetCrashpadClient();
+  if (!crashpad_client->SetHandlerIPCPipe(ipc_pipe_name)) {
+    LOG(DFATAL) << "Failed to set handler IPC pipe name: " << ipc_pipe_name;
+  } else {
+    g_is_connected_to_crash_handler = true;
+    LOG(INFO) << "Crash handler launched and ready.";
+  }
+}
diff --git a/chrome/chrome_cleaner/ipc/BUILD.gn b/chrome/chrome_cleaner/ipc/BUILD.gn
new file mode 100644
index 0000000..f607956
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/BUILD.gn
@@ -0,0 +1,113 @@
+# 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.
+
+source_set("mojo_task_runner") {
+  sources = [
+    "mojo_task_runner.cc",
+    "mojo_task_runner.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/core/embedder",
+    "//mojo/public/cpp/system",
+  ]
+}
+
+source_set("chrome_prompt_ipc") {
+  sources = [
+    "chrome_prompt_ipc.cc",
+    "chrome_prompt_ipc.h",
+  ]
+
+  deps = [
+    ":mojo_task_runner",
+    "//base",
+    "//components/chrome_cleaner/public/interfaces",
+    "//mojo/public/cpp/platform",
+    "//mojo/public/cpp/system",
+  ]
+}
+
+source_set("sandbox") {
+  sources = [
+    "sandbox.cc",
+    "sandbox.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/crash:crashpad_lib",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/settings:settings",
+    "//chrome/chrome_cleaner/settings:settings_types",
+    "//components/chrome_cleaner/public/constants:constants",
+    "//mojo/public/cpp/system",
+    "//sandbox:sandbox",
+  ]
+}
+
+source_set("ipc_test_util") {
+  testonly = true
+
+  sources = [
+    "ipc_test_util.cc",
+    "ipc_test_util.h",
+  ]
+
+  deps = [
+    ":mojo_task_runner",
+    "//base",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/ipc:sandbox",
+    "//chrome/chrome_cleaner/logging:common",
+    "//mojo/public/cpp/system",
+    "//sandbox/win:sandbox",
+    "//testing/gtest",
+  ]
+}
+
+source_set("unittest_sources") {
+  testonly = true
+
+  sources = [
+    "chrome_prompt_ipc_unittest.cc",
+    "mojo_task_runner_unittest.cc",
+    "sandbox_unittest.cc",
+  ]
+
+  deps = [
+    ":chrome_prompt_ipc",
+    ":ipc_test_util",
+    ":mojo_task_runner",
+    ":sandbox",
+    "//base",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/logging:common",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/test:test_util",
+    "//components/chrome_cleaner/public/interfaces:interfaces",
+    "//mojo/core/embedder",
+    "//sandbox/win:sandbox",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+source_set("mock_chrome_prompt_ipc") {
+  testonly = true
+
+  sources = [
+    "mock_chrome_prompt_ipc.cc",
+    "mock_chrome_prompt_ipc.h",
+  ]
+
+  deps = [
+    ":chrome_prompt_ipc",
+    "//components/chrome_cleaner/public/interfaces:interfaces",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/chrome_cleaner/ipc/DEPS b/chrome/chrome_cleaner/ipc/DEPS
new file mode 100644
index 0000000..9243dcd6
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/core/embedder",
+]
diff --git a/chrome/chrome_cleaner/ipc/chrome_prompt_ipc.cc b/chrome/chrome_cleaner/ipc/chrome_prompt_ipc.cc
new file mode 100644
index 0000000..d0cd0636
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/chrome_prompt_ipc.cc
@@ -0,0 +1,138 @@
+// 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/chrome_cleaner/ipc/chrome_prompt_ipc.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "mojo/public/cpp/platform/platform_channel.h"
+#include "mojo/public/cpp/system/invitation.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace chrome_cleaner {
+
+ChromePromptIPC::ChromePromptIPC(const std::string& chrome_mojo_pipe_token,
+                                 scoped_refptr<MojoTaskRunner> task_runner)
+    : task_runner_(std::move(task_runner)),
+      chrome_mojo_pipe_token_(chrome_mojo_pipe_token) {
+  // Accesses to |state_| must happen on |task_runner_|'s sequence, which is
+  // not the construction sequence.
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+void ChromePromptIPC::Initialize(ErrorHandler* error_handler) {
+  DCHECK(!chrome_mojo_pipe_token_.empty());
+  DCHECK(task_runner_);
+
+  error_handler_ = error_handler;
+
+  // No need to retain this object, since it will live until the process
+  // finishes.
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&ChromePromptIPC::InitializeChromePromptPtr,
+                                base::Unretained(this)));
+}
+
+ChromePromptIPC::~ChromePromptIPC() {
+  // This object is only destroyed when the cleaner process ends. At this point
+  // we don't need to close the IPC, since the broken connection message will
+  // be received by Chrome anyway, and we can simply leak the pointer.
+  chrome_prompt_service_.release();  // Leaked.
+}
+
+void ChromePromptIPC::PostPromptUserTask(
+    const std::vector<base::FilePath>& files_to_delete,
+    const std::vector<base::string16>& registry_keys,
+    mojom::ChromePrompt::PromptUserCallback callback) {
+  DCHECK(task_runner_);
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &ChromePromptIPC::RunPromptUserTask, base::Unretained(this),
+          files_to_delete, registry_keys,
+          base::BindOnce(&ChromePromptIPC::OnChromeResponseReceived,
+                         base::Unretained(this), std::move(callback))));
+}
+
+void ChromePromptIPC::OnChromeResponseReceived(
+    mojom::ChromePrompt::PromptUserCallback callback,
+    mojom::PromptAcceptance prompt_acceptance) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_EQ(State::kWaitingForResponseFromChrome, state_);
+
+  state_ = State::kDone;
+  std::move(callback).Run(prompt_acceptance);
+}
+
+void ChromePromptIPC::OnConnectionError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_NE(State::kUninitialized, state_);
+
+  if (!error_handler_)
+    return;
+
+  if (state_ == State::kDone) {
+    error_handler_->OnConnectionClosedAfterDone();
+  } else {
+    state_ = State::kDone;
+    error_handler_->OnConnectionClosed();
+  }
+}
+
+void ChromePromptIPC::InitializeChromePromptPtr() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_EQ(State::kUninitialized, state_);
+
+  auto channel_endpoint =
+      mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
+          *base::CommandLine::ForCurrentProcess());
+  auto incoming_invitation =
+      mojo::IncomingInvitation::Accept(std::move(channel_endpoint));
+
+  mojo::ScopedMessagePipeHandle message_pipe_handle =
+      incoming_invitation.ExtractMessagePipe(chrome_mojo_pipe_token_);
+
+  chrome_prompt_service_.reset(new chrome_cleaner::mojom::ChromePromptPtr);
+  chrome_prompt_service_->Bind(chrome_cleaner::mojom::ChromePromptPtrInfo(
+      std::move(message_pipe_handle), 0));
+  // No need to retain this object, since it will live until the process
+  // finishes.
+  chrome_prompt_service_->set_connection_error_handler(base::BindOnce(
+      &ChromePromptIPC::OnConnectionError, base::Unretained(this)));
+  state_ = State::kWaitingForScanResults;
+}
+
+void ChromePromptIPC::RunPromptUserTask(
+    const std::vector<base::FilePath>& files_to_delete,
+    const std::vector<base::string16>& registry_keys,
+    mojom::ChromePrompt::PromptUserCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(chrome_prompt_service_);
+  DCHECK(state_ != State::kUninitialized);
+  DCHECK(state_ != State::kWaitingForResponseFromChrome);
+
+  // This is a corner case, in which we receive the disconnect message on the
+  // IPC thread right before this task is posted. In that case, this function
+  // will be a no-op.
+  if (state_ == State::kDone)
+    return;
+
+  state_ = State::kWaitingForResponseFromChrome;
+
+  (*chrome_prompt_service_)
+      ->PromptUser(std::move(files_to_delete), std::move(registry_keys),
+                   base::nullopt, std::move(callback));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h b/chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h
new file mode 100644
index 0000000..7b1e3bf
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h
@@ -0,0 +1,138 @@
+// 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_CHROME_CLEANER_IPC_CHROME_PROMPT_IPC_H_
+#define CHROME_CHROME_CLEANER_IPC_CHROME_PROMPT_IPC_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string16.h"
+#include "base/threading/thread.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
+
+namespace chrome_cleaner {
+
+// Simple wrapper to control lifetime of the ChromePromptPtr object and post
+// tasks in the IPC thread kept by the MojoTaskRunner. Once created, this
+// object lives until the cleaner process ends.
+//
+// Simple usage:
+//   scoped_refptr<MojoTaskRunner> task_runner = MojoTaskRunner::Create();
+//   const std::string chrome_mojo_pipe_token =
+//       Settings::GetInstance()->chrome_mojo_pipe_token();
+//   ChromePromptIPC* chrome_prompt_ipc =
+//       new ChromePromptIPC(chrome_mojo_pipe_token, task_runner);
+//   ChromePromptIPC::ErrorHandler error_handler = ...;
+//   chrome_prompt_ipc->Initialize(&error_handler);
+//   ...
+//   std::vector<base::FilePath> files_to_delete = ...;
+//   std::vector<base::string16> registry_keys = ...;
+//   chrome_prompt_ipc->PostPromptUserTask(
+//       files_to_delete, registry_keys,
+//       base::BindOnce(&ReceivePromptResult));
+//
+//   void ReceivePromptResult(mojom::PromptAcceptance prompt_acceptance) {
+//     ...
+//   }
+class ChromePromptIPC {
+ public:
+  // Interface for connection error handling, which can change depending on the
+  // context objects of this class are used, such as in the main cleaner or in
+  // tests. Methods of this class will be called on the IPC controller's
+  // thread. Clients of this class must ensure operations are posted to the
+  // right thread if needed.
+  class ErrorHandler {
+   public:
+    virtual ~ErrorHandler() = default;
+
+    // Invoked if the pipe connection is closed while the communication channel
+    // is still required (before receiving response from the parent process).
+    virtual void OnConnectionClosed() = 0;
+
+    // Invoked if the pipe connection is closed once the communication channel
+    // is no longer required.
+    virtual void OnConnectionClosedAfterDone() = 0;
+  };
+
+  ChromePromptIPC(const std::string& chrome_mojo_pipe_token,
+                  scoped_refptr<MojoTaskRunner> task_runner);
+
+  // Initializes |chrome_prompt_service_| in the IPC controller's thread and
+  // sets |error_handler| as the connection error handler. This object doesn't
+  // own the error handler pointer.
+  virtual void Initialize(ErrorHandler* error_handler);
+
+  // Posts a PromptUser() task to the IPC controller's thread. Internal state
+  // must be State:kWaitingForScanResults when the posted task runs. Once the
+  // response from Chrome is received, |callback| will run on the IPC
+  // controller's thread; clients of this class are responsible for posting
+  // response on the right thread.
+  virtual void PostPromptUserTask(
+      const std::vector<base::FilePath>& files_to_delete,
+      const std::vector<base::string16>& registry_keys,
+      mojom::ChromePrompt::PromptUserCallback callback);
+
+ protected:
+  // The destructor is only called by tests for doubles of this class. In the
+  // cleaner, this object leaks, so we don't bother closing the connection
+  // (Chrome will receive the signal anyway once the cleaner process ends).
+  virtual ~ChromePromptIPC();
+
+ private:
+  enum class State {
+    // The IPC has not been initialized.
+    kUninitialized,
+    // Scan results are not available yet.
+    kWaitingForScanResults,
+    // Scan results sent to Chrome, waiting for the user's response.
+    kWaitingForResponseFromChrome,
+    // Response from Chrome received. In this state, the IPC will no longer be
+    // used.
+    kDone,
+  };
+
+  // Initializes |chrome_prompt_service_| and sets the connection error
+  // handler. This must be executed in the IPC controller's thread.
+  void InitializeChromePromptPtr();
+
+  // Runs |chrome_prompt_service_->PromptUser()|. Must be called on the IPC
+  // thread.
+  virtual void RunPromptUserTask(
+      const std::vector<base::FilePath>& files_to_delete,
+      const std::vector<base::string16>& registry_keys,
+      mojom::ChromePrompt::PromptUserCallback callback);
+
+  // Callback for ChromePrompt::PromptUser, internal state must be
+  // State::kWaitingForResponseFromChrome. Invokes callback(prompt_acceptance)
+  // and transitions to state State::kDone.
+  void OnChromeResponseReceived(
+      mojom::ChromePrompt::PromptUserCallback callback,
+      mojom::PromptAcceptance prompt_acceptance);
+
+  // Connection error handler. Invokes either
+  // error_handler_->OnConnectionClosed() or
+  // error_handler_->OnConnectionClosedAfterDone(), depending on the internal
+  // state.
+  void OnConnectionError();
+
+  State state_ = State::kUninitialized;
+  scoped_refptr<MojoTaskRunner> task_runner_;
+  std::string chrome_mojo_pipe_token_;
+  std::unique_ptr<mojom::ChromePromptPtr> chrome_prompt_service_;
+  ErrorHandler* error_handler_ = nullptr;
+
+  // Ensures that all accesses to state_ after initialization are done on the
+  // same sequence.
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_IPC_CHROME_PROMPT_IPC_H_
diff --git a/chrome/chrome_cleaner/ipc/chrome_prompt_ipc_unittest.cc b/chrome/chrome_cleaner/ipc/chrome_prompt_ipc_unittest.cc
new file mode 100644
index 0000000..a5387c2
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/chrome_prompt_ipc_unittest.cc
@@ -0,0 +1,353 @@
+// 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/chrome_cleaner/ipc/chrome_prompt_ipc.h"
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/chrome_cleaner/ipc/ipc_test_util.h"
+#include "chrome/chrome_cleaner/logging/scoped_logging.h"
+#include "chrome/chrome_cleaner/test/test_name_helper.h"
+#include "chrome/chrome_cleaner/test/test_util.h"
+#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace chrome_cleaner {
+namespace {
+
+using testing::Bool;
+using testing::Values;
+
+constexpr char kIncludeUwSSwitch[] = "include-uws";
+constexpr char kIncludeRegistryKeysSwitch[] = "include-registry-keys";
+constexpr char kExpectedPromptResultSwitch[] = "expected-prompt-result";
+constexpr char kExpectedParentDisconnectedSwitch[] =
+    "expected-parent-disconnected";
+
+const base::FilePath kBadFilePath(L"/path/to/bad.dll");
+const base::string16 kBadRegistryKey(L"HKCU:32\\Software\\ugly-uws\\nasty");
+
+// Possible moments when the parent process can disconnect from the IPC to
+// check connection error handling in the child process.
+enum class ParentDisconnected {
+  // The parent process will not try to disconnect while the child process
+  // is running.
+  kNone,
+  // The parent process will disconnect before the child process sends a
+  // message through the pipe.
+  kOnStartup,
+  // The parent process will disconnect after receiving a message from the
+  // child process and before sending out a response.
+  kWhileProcessingChildRequest,
+  // The parent process will disconnect once no further communication is
+  // required in the child process.
+  kOnDone,
+};
+
+std::ostream& operator<<(std::ostream& stream,
+                         ParentDisconnected parent_disconnected) {
+  switch (parent_disconnected) {
+    case ParentDisconnected::kNone:
+      stream << "NotDisconnected";
+      break;
+    case ParentDisconnected::kOnStartup:
+      stream << "DisconnectedOnStartup";
+      break;
+    case ParentDisconnected::kWhileProcessingChildRequest:
+      stream << "DisconnectedWhileProcessingChildRequest";
+      break;
+    case ParentDisconnected::kOnDone:
+      stream << "DisconnectedOnDone";
+      break;
+  }
+  return stream;
+}
+
+struct TestConfig {
+  bool uws_expected;
+  bool with_registry_keys;
+  mojom::PromptAcceptance expected_prompt_acceptance;
+  ParentDisconnected expected_parent_disconnected;
+};
+
+// Parent process.
+class MockChromePrompt : public mojom::ChromePrompt {
+ public:
+  MockChromePrompt(TestConfig test_config, mojom::ChromePromptRequest request)
+      : test_config_(test_config), binding_(this, std::move(request)) {}
+
+  ~MockChromePrompt() override = default;
+
+  void PromptUser(
+      const std::vector<base::FilePath>& files_to_delete,
+      const base::Optional<std::vector<base::string16>>& registry_keys,
+      const base::Optional<std::vector<base::string16>>& extension_ids,
+      mojom::ChromePrompt::PromptUserCallback callback) override {
+    EXPECT_NE(test_config_.uws_expected, files_to_delete.empty());
+    if (test_config_.uws_expected) {
+      EXPECT_EQ(1UL, files_to_delete.size());
+      EXPECT_EQ(kBadFilePath, files_to_delete.front());
+    }
+    if (test_config_.with_registry_keys) {
+      EXPECT_EQ(1UL, registry_keys->size());
+      EXPECT_EQ(kBadRegistryKey, registry_keys->front());
+    }
+    CloseConnectionIf(ParentDisconnected::kWhileProcessingChildRequest);
+    std::move(callback).Run(test_config_.expected_prompt_acceptance);
+    CloseConnectionIf(ParentDisconnected::kOnDone);
+  }
+
+  // Close the IPC connection on the parent process depending on the value of
+  // |parent_disconnected|.
+  void CloseConnectionIf(ParentDisconnected parent_disconnected) {
+    if (test_config_.expected_parent_disconnected == parent_disconnected)
+      binding_.Close();
+  }
+
+  TestConfig test_config_;
+  mojo::Binding<chrome_cleaner::mojom::ChromePrompt> binding_;
+};
+
+class ChromePromptIPCParentProcess : public ParentProcess {
+ public:
+  ChromePromptIPCParentProcess(TestConfig test_config,
+                               scoped_refptr<MojoTaskRunner> mojo_task_runner)
+      : ParentProcess(std::move(mojo_task_runner)), test_config_(test_config) {
+    if (test_config.uws_expected)
+      AppendSwitch(kIncludeUwSSwitch);
+    if (test_config.with_registry_keys)
+      AppendSwitch(kIncludeRegistryKeysSwitch);
+    AppendSwitch(kExpectedPromptResultSwitch,
+                 base::IntToString(
+                     static_cast<int>(test_config.expected_prompt_acceptance)));
+    AppendSwitch(kExpectedParentDisconnectedSwitch,
+                 base::IntToString(static_cast<int>(
+                     test_config.expected_parent_disconnected)));
+  }
+
+ protected:
+  void CreateImpl(mojo::ScopedMessagePipeHandle mojo_pipe) override {
+    chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request(
+        std::move(mojo_pipe));
+    mock_chrome_prompt_ = std::make_unique<MockChromePrompt>(
+        test_config_, std::move(chrome_prompt_request));
+    // At this point, the child process should be connected.
+    mock_chrome_prompt_->CloseConnectionIf(ParentDisconnected::kOnStartup);
+  }
+
+  void DestroyImpl() override { mock_chrome_prompt_.reset(); }
+
+ private:
+  ~ChromePromptIPCParentProcess() override = default;
+
+  TestConfig test_config_;
+  std::unique_ptr<MockChromePrompt> mock_chrome_prompt_;
+};
+
+class ChromePromptIPCTestErrorHandler : public ChromePromptIPC::ErrorHandler {
+ public:
+  ChromePromptIPCTestErrorHandler(base::OnceClosure on_closed,
+                                  base::OnceClosure on_closed_after_done)
+      : on_closed_(std::move(on_closed)),
+        on_closed_after_done_(std::move(on_closed_after_done)) {}
+
+  ~ChromePromptIPCTestErrorHandler() override = default;
+
+  void OnConnectionClosed() override { std::move(on_closed_).Run(); }
+
+  void OnConnectionClosedAfterDone() override {
+    std::move(on_closed_after_done_).Run();
+  }
+
+  base::OnceClosure on_closed_;
+  base::OnceClosure on_closed_after_done_;
+};
+
+// Child process.
+class ChromePromptIPCChildProcess : public ChildProcess {
+ public:
+  explicit ChromePromptIPCChildProcess(
+      scoped_refptr<MojoTaskRunner> mojo_task_runner)
+      : ChildProcess(std::move(mojo_task_runner)) {}
+
+  void SendUwSDataToParentProcess(ChromePromptIPC* chrome_prompt_ipc,
+                                  base::OnceClosure done) {
+    CHECK(chrome_prompt_ipc);
+
+    std::vector<base::FilePath> files_to_delete;
+    std::vector<base::string16> registry_keys;
+    if (uws_expected()) {
+      files_to_delete.push_back(kBadFilePath);
+      if (with_registry_keys())
+        registry_keys.push_back(kBadRegistryKey);
+    }
+
+    chrome_prompt_ipc->PostPromptUserTask(
+        std::move(files_to_delete), std::move(registry_keys),
+        base::BindOnce(&ChromePromptIPCChildProcess::ReceivePromptResult,
+                       base::Unretained(this), base::Passed(&done)));
+  }
+
+  ParentDisconnected expected_parent_disconnected() const {
+    int val = -1;
+    CHECK(base::StringToInt(
+        command_line().GetSwitchValueASCII(kExpectedParentDisconnectedSwitch),
+        &val));
+    return static_cast<ParentDisconnected>(val);
+  }
+
+ private:
+  ~ChromePromptIPCChildProcess() override = default;
+
+  void ReceivePromptResult(base::OnceClosure done,
+                           mojom::PromptAcceptance prompt_acceptance) {
+    CHECK_EQ(expected_prompt_acceptance(), prompt_acceptance);
+    // Unblocks the main thread.
+    std::move(done).Run();
+  }
+
+  bool uws_expected() const {
+    return command_line().HasSwitch(kIncludeUwSSwitch);
+  }
+
+  bool with_registry_keys() const {
+    return uws_expected() &&
+           command_line().HasSwitch(kIncludeRegistryKeysSwitch);
+  }
+
+  mojom::PromptAcceptance expected_prompt_acceptance() const {
+    int val = -1;
+    CHECK(base::StringToInt(
+        command_line().GetSwitchValueASCII(kExpectedPromptResultSwitch), &val));
+    return static_cast<mojom::PromptAcceptance>(val);
+  }
+};
+
+constexpr int kEarlyDisconnectionExitCode = 100;
+constexpr int kSuccessExitCode = 0;
+
+MULTIPROCESS_TEST_MAIN(ChromePromptIPCClientMain) {
+  static constexpr int kInternalTestFailureExitCode = -1;
+
+  base::MessageLoop message_loop;
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
+  auto child_process =
+      base::MakeRefCounted<ChromePromptIPCChildProcess>(mojo_task_runner);
+  base::RunLoop on_done_run_loop;
+  // The parent process can disconnect while the pipe is required or after it's
+  // no longer needed. In the former case, the child process will immediately
+  // exit; in the latter, it will break |on_done_run_loop|, which will be
+  // blocking its main thread.
+  ChromePromptIPCTestErrorHandler error_handler(
+      base::BindOnce([] {
+        exit(::testing::Test::HasFailure() ? kInternalTestFailureExitCode
+                                           : kEarlyDisconnectionExitCode);
+      }),
+      on_done_run_loop.QuitClosure());
+
+  ChromePromptIPC* chrome_prompt_ipc =
+      new ChromePromptIPC(child_process->mojo_pipe_token(), mojo_task_runner);
+  chrome_prompt_ipc->Initialize(&error_handler);
+
+  if (child_process->expected_parent_disconnected() ==
+      ParentDisconnected::kOnStartup) {
+    // If a failure on startup is expected, the child process will wait until
+    // the pipe gets disconnected (which will terminate the process), or
+    // eventually timeout if the disconnection is never received.
+    base::RunLoop().Run();
+  }
+
+  // After the response from the parent process is received, this will post a
+  // task to unblock the child process's main thread. Not blocking the main
+  // thread can lead to race condition on exit.
+  base::RunLoop run_loop;
+  child_process->SendUwSDataToParentProcess(chrome_prompt_ipc,
+                                            run_loop.QuitClosure());
+  run_loop.Run();
+
+  if (child_process->expected_parent_disconnected() ==
+      ParentDisconnected::kOnDone) {
+    // Only block the main thread at this point if the parent process is
+    // expected to disconnect once communication is over.
+    on_done_run_loop.Run();
+  }
+
+  return ::testing::Test::HasFailure() ? kInternalTestFailureExitCode
+                                       : kSuccessExitCode;
+}
+
+class ChromePromptIPCTest
+    : public ::testing::TestWithParam<
+          std::tuple<bool, bool, mojom::PromptAcceptance, ParentDisconnected>> {
+ public:
+  void SetUp() override { mojo_task_runner_ = MojoTaskRunner::Create(); }
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+  scoped_refptr<ChromePromptIPCParentProcess> parent_process_;
+};
+
+TEST_P(ChromePromptIPCTest, Communication) {
+  TestConfig test_config;
+  std::tie(test_config.uws_expected, test_config.with_registry_keys,
+           test_config.expected_prompt_acceptance,
+           test_config.expected_parent_disconnected) = GetParam();
+  if (test_config.with_registry_keys)
+    ASSERT_TRUE(test_config.uws_expected);
+
+  parent_process_ = base::MakeRefCounted<ChromePromptIPCParentProcess>(
+      test_config, mojo_task_runner_);
+
+  int32_t exit_code = -1;
+  EXPECT_TRUE(parent_process_->LaunchConnectedChildProcess(
+      "ChromePromptIPCClientMain", &exit_code));
+
+  int32_t expected_exit_code =
+      test_config.expected_parent_disconnected == ParentDisconnected::kNone ||
+              test_config.expected_parent_disconnected ==
+                  ParentDisconnected::kOnDone
+          ? kSuccessExitCode
+          : kEarlyDisconnectionExitCode;
+  EXPECT_EQ(expected_exit_code, exit_code);
+}
+
+INSTANTIATE_TEST_CASE_P(NoUwSPresent,
+                        ChromePromptIPCTest,
+                        testing::Combine(
+                            /*uws_expected=*/Values(false),
+                            /*with_registry_keys=*/Values(false),
+                            Values(mojom::PromptAcceptance::DENIED),
+                            Values(ParentDisconnected::kNone,
+                                   ParentDisconnected::kOnStartup)),
+                        GetParamNameForTest());
+
+INSTANTIATE_TEST_CASE_P(
+    UwSPresent,
+    ChromePromptIPCTest,
+    testing::Combine(
+        /*uws_expected=*/Values(true),
+        /*with_registry_keys=*/Bool(),
+        Values(mojom::PromptAcceptance::ACCEPTED_WITH_LOGS,
+               mojom::PromptAcceptance::ACCEPTED_WITHOUT_LOGS,
+               mojom::PromptAcceptance::DENIED),
+        Values(ParentDisconnected::kNone,
+               ParentDisconnected::kOnStartup,
+               ParentDisconnected::kWhileProcessingChildRequest,
+               ParentDisconnected::kOnDone)),
+    GetParamNameForTest());
+
+}  // namespace
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/ipc_test_util.cc b/chrome/chrome_cleaner/ipc/ipc_test_util.cc
new file mode 100644
index 0000000..690058e1
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/ipc_test_util.cc
@@ -0,0 +1,278 @@
+// 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/chrome_cleaner/ipc/ipc_test_util.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/launch.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "chrome/chrome_cleaner/ipc/sandbox.h"
+#include "chrome/chrome_cleaner/logging/scoped_logging.h"
+#include "sandbox/win/src/sandbox_factory.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+constexpr char kMojoPipeTokenSwitch[] = "mojo-pipe-token";
+
+constexpr wchar_t kIPCTestUtilLogSuffix[] = L"ipc-test-util";
+
+class MojoSandboxSetupHooks : public SandboxSetupHooks {
+ public:
+  explicit MojoSandboxSetupHooks(SandboxedParentProcess* parent_process)
+      : parent_process_(parent_process) {}
+  ~MojoSandboxSetupHooks() override = default;
+
+  // SandboxSetupHooks
+
+  ResultCode UpdateSandboxPolicy(sandbox::TargetPolicy* policy,
+                                 base::CommandLine* command_line) override {
+    base::HandlesToInheritVector handles_to_inherit;
+    parent_process_->CreateMojoPipe(command_line, &handles_to_inherit);
+    for (HANDLE handle : handles_to_inherit)
+      policy->AddHandleToShare(handle);
+    return RESULT_CODE_SUCCESS;
+  }
+
+  ResultCode TargetSpawned(
+      const base::Process& target_process,
+      const base::win::ScopedHandle& target_thread) override {
+    parent_process_->ConnectMojoPipe(target_process.Duplicate());
+    return RESULT_CODE_SUCCESS;
+  }
+
+ private:
+  SandboxedParentProcess* parent_process_;
+};
+
+base::FilePath GetLogPath() {
+  return ScopedLogging::GetLogFilePath(kIPCTestUtilLogSuffix);
+}
+
+bool DeleteChildProcessLogs() {
+  // Delete the child process log file if existing.
+  const base::FilePath log_path = GetLogPath();
+  if (!base::DeleteFile(log_path, false)) {
+    LOG(ERROR) << "Can't delete log file from previous run: "
+               << log_path.value();
+    return false;
+  }
+  return true;
+}
+
+void PrintChildProcessLogs() {
+  const base::FilePath log_path = GetLogPath();
+  if (log_path.empty()) {
+    LOG(ERROR) << "Child process log path is empty";
+    return;
+  }
+
+  if (!base::PathExists(log_path)) {
+    LOG(ERROR) << "Child process log file doesn't exist";
+    return;
+  }
+
+  // Collect the child process log file, and dump the contents, to help
+  // debugging failures.
+  std::string log_file_contents;
+  if (!base::ReadFileToString(log_path, &log_file_contents)) {
+    LOG(ERROR) << "Failed to read child process log file";
+    return;
+  }
+
+  std::vector<base::StringPiece> lines =
+      base::SplitStringPiece(log_file_contents, "\n", base::TRIM_WHITESPACE,
+                             base::SPLIT_WANT_NONEMPTY);
+  LOG(ERROR) << "Dumping child process logs";
+  for (const auto& line : lines) {
+    LOG(ERROR) << "Child process: " << line;
+  }
+}
+
+}  // namespace
+
+ParentProcess::ParentProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner)
+    : command_line_(base::GetMultiProcessTestChildBaseCommandLine()),
+      mojo_task_runner_(mojo_task_runner) {}
+
+ParentProcess::~ParentProcess() {}
+
+void ParentProcess::CreateImplOnIPCThread(
+    mojo::ScopedMessagePipeHandle mojo_pipe) {
+  mojo_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ParentProcess::CreateImpl, base::RetainedRef(this),
+                     base::Passed(&mojo_pipe)));
+}
+
+void ParentProcess::DestroyImplOnIPCThread() {
+  mojo_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ParentProcess::DestroyImpl, base::RetainedRef(this)));
+}
+
+void ParentProcess::AppendSwitch(const std::string& switch_string) {
+  command_line_.AppendSwitch(switch_string);
+}
+
+void ParentProcess::AppendSwitch(const std::string& switch_string,
+                                 const std::string& value) {
+  command_line_.AppendSwitchASCII(switch_string, value);
+}
+
+void ParentProcess::AppendSwitchNative(const std::string& switch_string,
+                                       const base::string16& value) {
+  command_line_.AppendSwitchNative(switch_string, value);
+}
+
+void ParentProcess::AppendSwitchPath(const std::string& switch_string,
+                                     const base::FilePath& value) {
+  command_line_.AppendSwitchPath(switch_string, value);
+}
+
+bool ParentProcess::LaunchConnectedChildProcess(
+    const std::string& child_main_function,
+    int32_t* exit_code) {
+  return LaunchConnectedChildProcess(child_main_function,
+                                     TestTimeouts::action_timeout(), exit_code);
+}
+
+bool ParentProcess::LaunchConnectedChildProcess(
+    const std::string& child_main_function,
+    base::TimeDelta timeout,
+    int32_t* exit_code) {
+  if (!DeleteChildProcessLogs())
+    return false;
+
+  if (!PrepareAndLaunchTestChildProcess(child_main_function))
+    return false;
+
+  CreateImplOnIPCThread(std::move(mojo_pipe_));
+  const bool success = base::WaitForMultiprocessTestChildExit(
+      child_process_, timeout, exit_code);
+  if (!success) {
+    LOG(ERROR) << "Child process failed to terminate within " << timeout;
+    child_process_.Terminate(/*exit_code=*/-1, /*wait=*/false);
+  }
+  DestroyImplOnIPCThread();
+
+  if (!success || *exit_code != 0)
+    PrintChildProcessLogs();
+
+  return success;
+}
+
+bool ParentProcess::PrepareAndLaunchTestChildProcess(
+    const std::string& child_main_function) {
+  base::LaunchOptions launch_options;
+  CreateMojoPipe(&command_line_, &launch_options.handles_to_inherit);
+
+  base::Process child_process = base::SpawnMultiProcessTestChild(
+      child_main_function, command_line_, launch_options);
+
+  ConnectMojoPipe(std::move(child_process));
+  return true;
+}
+
+void ParentProcess::CreateMojoPipe(
+    base::CommandLine* command_line,
+    base::HandlesToInheritVector* handles_to_inherit) {
+  std::string mojo_pipe_token = base::NumberToString(base::RandUint64());
+  mojo_pipe_ = outgoing_invitation_.AttachMessagePipe(mojo_pipe_token);
+  command_line->AppendSwitchASCII(kMojoPipeTokenSwitch, mojo_pipe_token);
+  mojo_channel_.PrepareToPassRemoteEndpoint(handles_to_inherit, command_line);
+}
+
+void ParentProcess::ConnectMojoPipe(base::Process process) {
+  child_process_ = std::move(process);
+  mojo::OutgoingInvitation::Send(std::move(outgoing_invitation_),
+                                 child_process_.Handle(),
+                                 mojo_channel_.TakeLocalEndpoint());
+}
+
+SandboxedParentProcess::SandboxedParentProcess(
+    scoped_refptr<MojoTaskRunner> mojo_task_runner)
+    : ParentProcess(mojo_task_runner) {}
+
+SandboxedParentProcess::~SandboxedParentProcess() {}
+
+bool SandboxedParentProcess::PrepareAndLaunchTestChildProcess(
+    const std::string& child_main_function) {
+  MojoSandboxSetupHooks hooks(this);
+
+  // This switch usage is copied from SpawnMultiProcessTestChild.
+  //
+  // We can't use SpawnMultiProcessTestChild here, because it uses
+  // LaunchProcess internally and we need to start the test child using
+  // StartSandboxTarget, which uses BrokerServices::SpawnTarget.
+  if (!command_line_.HasSwitch(switches::kTestChildProcess))
+    command_line_.AppendSwitchASCII(switches::kTestChildProcess,
+                                    child_main_function);
+
+  chrome_cleaner::ResultCode result_code =
+      StartSandboxTarget(command_line_, &hooks, SandboxType::kTest);
+  if (result_code != RESULT_CODE_SUCCESS) {
+    LOG(ERROR) << "Failed to launch sandbox: " << result_code;
+    return false;
+  }
+  return true;
+}
+
+ChildProcess::ChildProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner)
+    : mojo_task_runner_(mojo_task_runner),
+      command_line_(base::CommandLine::ForCurrentProcess()),
+      scopped_logging_(new ScopedLogging(kIPCTestUtilLogSuffix)) {
+  sandbox::TargetServices* target_services =
+      sandbox::SandboxFactory::GetTargetServices();
+  if (!target_services)
+    return;
+
+  sandbox::ResultCode result = target_services->Init();
+  if (result != sandbox::SBOX_ALL_OK) {
+    LOG(ERROR) << "Failed to initialize sandbox TargetServices: " << result;
+    return;
+  }
+  target_services_initialized_ = true;
+}
+
+ChildProcess::~ChildProcess() {}
+
+void ChildProcess::LowerToken() const {
+  if (!target_services_initialized_)
+    return;
+  sandbox::TargetServices* target_services =
+      sandbox::SandboxFactory::GetTargetServices();
+  DCHECK(target_services);
+  target_services->LowerToken();
+}
+
+mojo::ScopedMessagePipeHandle ChildProcess::CreateMessagePipeFromCommandLine() {
+  auto channel_endpoint =
+      mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
+          *base::CommandLine::ForCurrentProcess());
+  auto incoming_invitation =
+      mojo::IncomingInvitation::Accept(std::move(channel_endpoint));
+  return incoming_invitation.ExtractMessagePipe(mojo_pipe_token());
+}
+
+std::string ChildProcess::mojo_pipe_token() const {
+  return command_line_->GetSwitchValueASCII(kMojoPipeTokenSwitch);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/ipc_test_util.h b/chrome/chrome_cleaner/ipc/ipc_test_util.h
new file mode 100644
index 0000000..cfd0fca
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/ipc_test_util.h
@@ -0,0 +1,121 @@
+// 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_CHROME_CLEANER_IPC_IPC_TEST_UTIL_H_
+#define CHROME_CHROME_CLEANER_IPC_IPC_TEST_UTIL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/command_line.h"
+#include "base/memory/ref_counted.h"
+#include "base/process/process.h"
+#include "base/time/time.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/logging/scoped_logging.h"
+#include "mojo/public/cpp/platform/platform_channel.h"
+#include "mojo/public/cpp/system/invitation.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace chrome_cleaner {
+
+typedef base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle mojo_pipe)>
+    CreateImplCallback;
+
+class ParentProcess : public base::RefCountedThreadSafe<ParentProcess> {
+ public:
+  explicit ParentProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner);
+
+  bool LaunchConnectedChildProcess(const std::string& child_main_function,
+                                   int32_t* exit_code);
+
+  bool LaunchConnectedChildProcess(const std::string& child_main_function,
+                                   base::TimeDelta timeout,
+                                   int32_t* exit_code);
+
+  void AppendSwitch(const std::string& switch_string);
+  void AppendSwitch(const std::string& switch_string, const std::string& value);
+  void AppendSwitchNative(const std::string& switch_string,
+                          const base::string16& value);
+  void AppendSwitchPath(const std::string& switch_string,
+                        const base::FilePath& value);
+
+  // The following methods are called during the launch sequence. They are
+  // public so they can be called from helper classes.
+  void CreateImplOnIPCThread(mojo::ScopedMessagePipeHandle mojo_pipe);
+  void DestroyImplOnIPCThread();
+  void CreateMojoPipe(base::CommandLine* command_line,
+                      base::HandlesToInheritVector* handles_to_inherit);
+  void ConnectMojoPipe(base::Process child_process);
+
+ protected:
+  friend base::RefCountedThreadSafe<ParentProcess>;
+  virtual ~ParentProcess();
+
+  // This is called on the IPC thread.
+  virtual void CreateImpl(mojo::ScopedMessagePipeHandle mojo_pipe) = 0;
+  virtual void DestroyImpl() = 0;
+
+  // Subclasses can override this to launch the child in different ways, such
+  // as in the sandbox. Subclasses should call CreateMojoPipe before the
+  // subprocess is spawned and ConnectMojoPipe afterward.
+  virtual bool PrepareAndLaunchTestChildProcess(
+      const std::string& child_main_function);
+
+  base::CommandLine command_line_;
+
+ private:
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+  mojo::OutgoingInvitation outgoing_invitation_;
+  mojo::ScopedMessagePipeHandle mojo_pipe_;
+  mojo::PlatformChannel mojo_channel_;
+  base::Process child_process_;
+};
+
+class SandboxedParentProcess : public ParentProcess {
+ public:
+  explicit SandboxedParentProcess(
+      scoped_refptr<MojoTaskRunner> mojo_task_runner);
+
+ protected:
+  friend base::RefCountedThreadSafe<SandboxedParentProcess>;
+  ~SandboxedParentProcess() override;
+
+  bool PrepareAndLaunchTestChildProcess(
+      const std::string& child_main_function) override;
+};
+
+class ChildProcess : public base::RefCountedThreadSafe<ChildProcess> {
+ public:
+  explicit ChildProcess(scoped_refptr<MojoTaskRunner> mojo_task_runner);
+
+  mojo::ScopedMessagePipeHandle CreateMessagePipeFromCommandLine();
+
+  std::string mojo_pipe_token() const;
+
+  const base::CommandLine& command_line() const { return *command_line_; }
+
+  // This will drop all privileges if the child process is running in a
+  // sandbox. If not, it will do nothing.
+  void LowerToken() const;
+
+ protected:
+  friend base::RefCountedThreadSafe<ChildProcess>;
+  virtual ~ChildProcess();
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+
+ private:
+  base::CommandLine* command_line_;
+  std::unique_ptr<ScopedLogging> scopped_logging_;
+
+  // This will be true iff the process is running in a sandbox and
+  // TargetServices was initialized successfully.
+  bool target_services_initialized_ = false;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_IPC_IPC_TEST_UTIL_H_
diff --git a/chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.cc b/chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.cc
new file mode 100644
index 0000000..dd82d73
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.cc
@@ -0,0 +1,23 @@
+// 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/chrome_cleaner/ipc/mock_chrome_prompt_ipc.h"
+
+#include <string>
+
+namespace chrome_cleaner {
+
+MockChromePromptIPC::MockChromePromptIPC()
+    : ChromePromptIPC(std::string(), nullptr) {}
+
+MockChromePromptIPC::~MockChromePromptIPC() = default;
+
+void MockChromePromptIPC::PostPromptUserTask(
+    const std::vector<base::FilePath>& files_to_delete,
+    const std::vector<base::string16>& registry_keys,
+    mojom::ChromePrompt::PromptUserCallback callback) {
+  MockPostPromptUserTask(files_to_delete, registry_keys, &callback);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.h b/chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.h
new file mode 100644
index 0000000..9ae54a4
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.h
@@ -0,0 +1,39 @@
+// 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_CHROME_CLEANER_IPC_MOCK_CHROME_PROMPT_IPC_H_
+#define CHROME_CHROME_CLEANER_IPC_MOCK_CHROME_PROMPT_IPC_H_
+
+#include <memory>
+#include <vector>
+
+#include "chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h"
+#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chrome_cleaner {
+
+class MockChromePromptIPC : public ChromePromptIPC {
+ public:
+  MockChromePromptIPC();
+  ~MockChromePromptIPC() override;
+
+  MOCK_METHOD1(Initialize, void(ErrorHandler* error_handler));
+
+  // Workaround for GMock's limitation, in which MOCK_METHOD* doesn't accept
+  // base::OnceCallback parameters. Will forward any calls to
+  // MockPostPromptUserTask() and pass along a raw pointer for |callback|.
+  void PostPromptUserTask(
+      const std::vector<base::FilePath>& files_to_delete,
+      const std::vector<base::string16>& registry_keys,
+      mojom::ChromePrompt::PromptUserCallback callback) override;
+  MOCK_METHOD3(MockPostPromptUserTask,
+               void(const std::vector<base::FilePath>& files_to_delete,
+                    const std::vector<base::string16>& registry_keys,
+                    mojom::ChromePrompt::PromptUserCallback* callback));
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_IPC_MOCK_CHROME_PROMPT_IPC_H_
diff --git a/chrome/chrome_cleaner/ipc/mojo_task_runner.cc b/chrome/chrome_cleaner/ipc/mojo_task_runner.cc
new file mode 100644
index 0000000..fd1c9f0
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/mojo_task_runner.cc
@@ -0,0 +1,73 @@
+// 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/chrome_cleaner/ipc/mojo_task_runner.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/core/embedder/embedder.h"
+
+namespace chrome_cleaner {
+
+// static
+scoped_refptr<MojoTaskRunner> MojoTaskRunner::Create() {
+  // Ensures thread-safe and unique initialization of the mojo lib.
+  static bool mojo_initialization = []() {  // Leaked.
+    mojo::core::Init();
+    return true;
+  }();
+  ANALYZER_ALLOW_UNUSED(mojo_initialization);
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner(new MojoTaskRunner());
+  return mojo_task_runner->Initialize() ? mojo_task_runner : nullptr;
+}
+
+bool MojoTaskRunner::PostDelayedTask(const base::Location& from_here,
+                                     base::OnceClosure task,
+                                     base::TimeDelta delay) {
+  DCHECK(io_thread_);
+  return io_thread_->task_runner()->PostDelayedTask(from_here, std::move(task),
+                                                    delay);
+}
+
+bool MojoTaskRunner::RunsTasksInCurrentSequence() const {
+  DCHECK(io_thread_);
+  return io_thread_->task_runner()->RunsTasksInCurrentSequence();
+}
+
+bool MojoTaskRunner::PostNonNestableDelayedTask(const base::Location& from_here,
+                                                base::OnceClosure task,
+                                                base::TimeDelta delay) {
+  return io_thread_->task_runner()->PostNonNestableDelayedTask(
+      from_here, std::move(task), delay);
+}
+
+MojoTaskRunner::MojoTaskRunner() = default;
+
+MojoTaskRunner::~MojoTaskRunner() {
+  ipc_support_.reset();
+  // Resets the IO thread after resetting the ipc_support_, because its
+  // finalization uses the thread's task runner.
+  io_thread_.reset();
+}
+
+bool MojoTaskRunner::Initialize() {
+  io_thread_ = std::make_unique<base::Thread>("MojoThread");
+  if (!io_thread_->StartWithOptions(
+          base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
+    io_thread_.reset();
+    return false;
+  }
+
+  ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
+      io_thread_->task_runner(),
+      mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+
+  return true;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/mojo_task_runner.h b/chrome/chrome_cleaner/ipc/mojo_task_runner.h
new file mode 100644
index 0000000..c99c29f
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/mojo_task_runner.h
@@ -0,0 +1,53 @@
+// 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_CHROME_CLEANER_IPC_MOJO_TASK_RUNNER_H_
+#define CHROME_CHROME_CLEANER_IPC_MOJO_TASK_RUNNER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "mojo/core/embedder/scoped_ipc_support.h"
+
+namespace chrome_cleaner {
+
+// Task runner for Mojo IPC tasks that ensures Mojo lib initialization
+// and execution on an IO thread.
+class MojoTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  // Creates a new instance of MojoTaskRunner with a new IO thread to run IPC
+  // tasks.
+  static scoped_refptr<MojoTaskRunner> Create();
+
+  // Abstract methods from base::TaskRunner.
+  bool PostDelayedTask(const base::Location& from_here,
+                       base::OnceClosure task,
+                       base::TimeDelta delay) override;
+  bool RunsTasksInCurrentSequence() const override;
+
+  // Abstract methods from base::SequencedTaskRunner.
+  bool PostNonNestableDelayedTask(const base::Location& from_here,
+                                  base::OnceClosure task,
+                                  base::TimeDelta delay) override;
+
+ protected:
+  MojoTaskRunner();
+  ~MojoTaskRunner() override;
+
+  // Starts a new IO thread to run IPC tasks.
+  virtual bool Initialize();
+
+ private:
+  std::unique_ptr<base::Thread> io_thread_;
+  std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support_;
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_IPC_MOJO_TASK_RUNNER_H_
diff --git a/chrome/chrome_cleaner/ipc/mojo_task_runner_unittest.cc b/chrome/chrome_cleaner/ipc/mojo_task_runner_unittest.cc
new file mode 100644
index 0000000..46c3f6f
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/mojo_task_runner_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "chrome/chrome_cleaner/ipc/ipc_test_util.h"
+#include "mojo/core/embedder/embedder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace chrome_cleaner {
+namespace {
+
+MULTIPROCESS_TEST_MAIN(MojoTaskRunnerTestClientMain) {
+  scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
+  scoped_refptr<ChildProcess> child_process =
+      base::MakeRefCounted<ChildProcess>(mojo_task_runner);
+
+  CHECK_NE(nullptr, mojo_task_runner);
+  CHECK_NE(nullptr, mojo::core::GetIOTaskRunner());
+  return 0;
+}
+
+class MojoTaskRunnerTestParentProcess : public ParentProcess {
+ public:
+  explicit MojoTaskRunnerTestParentProcess(
+      scoped_refptr<MojoTaskRunner> mojo_task_runner)
+      : ParentProcess(mojo_task_runner) {}
+
+ protected:
+  ~MojoTaskRunnerTestParentProcess() override = default;
+
+  void CreateImpl(mojo::ScopedMessagePipeHandle mojo_pipe) override {}
+  void DestroyImpl() override {}
+};
+
+TEST(MojoTaskRunnerTest, Setup) {
+  // Start the MojoTaskRunner on the parent process and checks if it's valid.
+  scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
+  CHECK_NE(nullptr, mojo_task_runner);
+  CHECK_NE(nullptr, mojo::core::GetIOTaskRunner());
+
+  scoped_refptr<MojoTaskRunnerTestParentProcess> parent_process =
+      base::MakeRefCounted<MojoTaskRunnerTestParentProcess>(
+          std::move(mojo_task_runner));
+
+  int32_t exit_code = -1;
+  EXPECT_TRUE(parent_process->LaunchConnectedChildProcess(
+      "MojoTaskRunnerTestClientMain", &exit_code));
+  EXPECT_EQ(0, exit_code);
+}
+
+}  // namespace
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/sandbox.cc b/chrome/chrome_cleaner/ipc/sandbox.cc
new file mode 100644
index 0000000..7c61918
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/sandbox.cc
@@ -0,0 +1,380 @@
+// 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/chrome_cleaner/ipc/sandbox.h"
+
+#include <windows.h>
+
+#include <iterator>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "base/win/win_util.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/crash/crash_reporter.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/inheritable_event.h"
+#include "chrome/chrome_cleaner/os/initializer.h"
+#include "chrome/chrome_cleaner/os/pre_fetched_paths.h"
+#include "chrome/chrome_cleaner/settings/settings.h"
+#include "components/chrome_cleaner/public/constants/constants.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace chrome_cleaner {
+
+const wchar_t kSandboxLogFileSuffix[] = L"-sandbox";
+
+namespace {
+
+// Switches to propagate to the sandbox target process.
+const char* kSwitchesToPropagate[] = {
+    kEnableCrashReportingSwitch, kExecutionModeSwitch,
+    kExtendedSafeBrowsingEnabledSwitch, switches::kTestChildProcess,
+};
+
+std::map<SandboxType, base::Process>* g_target_processes = nullptr;  // Leaked.
+
+scoped_refptr<sandbox::TargetPolicy> GetSandboxPolicy(
+    sandbox::BrokerServices* sandbox_broker_services) {
+  scoped_refptr<sandbox::TargetPolicy> policy(
+      sandbox_broker_services->CreatePolicy());
+
+  sandbox::ResultCode sandbox_result = policy->SetTokenLevel(
+      sandbox::USER_RESTRICTED_SAME_ACCESS, sandbox::USER_LOCKDOWN);
+  CHECK_EQ(sandbox::SBOX_ALL_OK, sandbox_result);
+
+  sandbox_result = policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
+  CHECK_EQ(sandbox::SBOX_ALL_OK, sandbox_result);
+
+  // Chromium ignores failures on this function but logs a warning. Do the same
+  // here.
+  // https://chromium.googlesource.com/chromium/src/+/b6a4ff86c730756a73d63cc882ef818fb7818a53/content/common/sandbox_win.cc#420
+  sandbox::ResultCode result = policy->SetAlternateDesktop(true);
+  LOG_IF(WARNING, result != sandbox::SBOX_ALL_OK)
+      << "Failed to apply desktop security";
+
+  sandbox_result =
+      policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
+  CHECK_EQ(sandbox::SBOX_ALL_OK, sandbox_result);
+
+  // This is all the mitigations from security_level.h, except those that need
+  // to be enabled later (set in SetDelayedProcessMitigations below).
+  sandbox_result = policy->SetProcessMitigations(
+      sandbox::MITIGATION_DEP | sandbox::MITIGATION_DEP_NO_ATL_THUNK |
+      sandbox::MITIGATION_SEHOP | sandbox::MITIGATION_HEAP_TERMINATE |
+      sandbox::MITIGATION_BOTTOM_UP_ASLR |
+      sandbox::MITIGATION_HIGH_ENTROPY_ASLR |
+      sandbox::MITIGATION_WIN32K_DISABLE |
+      sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
+      sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
+      sandbox::MITIGATION_HARDEN_TOKEN_IL_POLICY |
+      sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
+      sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL);
+  CHECK_EQ(sandbox::SBOX_ALL_OK, sandbox_result);
+
+  // RELOCATE_IMAGE and RELOCATE_IMAGE_REQUIRED could be in
+  // SetProcessMitigations above, but they need to be delayed in Debug builds.
+  // It's easier to just set them up as delayed for both Debug and Release
+  // builds.
+  sandbox_result = policy->SetDelayedProcessMitigations(
+      sandbox::MITIGATION_RELOCATE_IMAGE |
+      sandbox::MITIGATION_RELOCATE_IMAGE_REQUIRED |
+      sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
+      sandbox::MITIGATION_DLL_SEARCH_ORDER);
+  CHECK_EQ(sandbox::SBOX_ALL_OK, sandbox_result);
+
+  // This rule is needed to allow user32.dll and gdi32.dll to initialize during
+  // load, while still blocking other WIN32K calls.
+  sandbox_result =
+      policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
+                      sandbox::TargetPolicy::FAKE_USER_GDI_INIT, nullptr);
+  CHECK_EQ(sandbox::SBOX_ALL_OK, sandbox_result);
+
+#if !defined(CHROME_CLEANER_OFFICIAL_BUILD)
+  base::FilePath product_path;
+  GetAppDataProductDirectory(&product_path);
+  if (!product_path.value().empty()) {
+    // In developer builds, let the sandbox target process write logs to the
+    // product directory.
+    sandbox_result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                                     sandbox::TargetPolicy::FILES_ALLOW_ANY,
+                                     product_path.Append(L"*").value().c_str());
+    LOG_IF(ERROR, sandbox_result != sandbox::SBOX_ALL_OK)
+        << "Failed to give the target process access to the product directory";
+  }
+#endif
+
+  policy->SetLockdownDefaultDacl();
+
+  // Do not include SetDisconnectCsrss because the signature validator uses
+  // wincrypt, which uses a garbage-collected connection to csrss.exe that may
+  // not be cleaned up yet when we call LowerToken.
+
+  return policy;
+}
+
+}  // namespace
+
+SandboxSetupHooks::SandboxSetupHooks() = default;
+
+SandboxSetupHooks::~SandboxSetupHooks() = default;
+
+ResultCode SandboxSetupHooks::UpdateSandboxPolicy(
+    sandbox::TargetPolicy* policy,
+    base::CommandLine* command_line) {
+  return RESULT_CODE_SUCCESS;
+}
+
+ResultCode SandboxSetupHooks::TargetSpawned(
+    const base::Process& target_process,
+    const base::win::ScopedHandle& target_thread) {
+  return RESULT_CODE_SUCCESS;
+}
+
+ResultCode SandboxSetupHooks::TargetResumed() {
+  return RESULT_CODE_SUCCESS;
+}
+
+void SandboxSetupHooks::SetupFailed() {}
+
+SandboxTargetHooks::SandboxTargetHooks() = default;
+
+SandboxTargetHooks::~SandboxTargetHooks() = default;
+
+ResultCode SandboxTargetHooks::TargetStartedWithHighPrivileges() {
+  return RESULT_CODE_SUCCESS;
+}
+
+SandboxType SandboxProcessType() {
+  // This should only be called by children processes.
+  DCHECK(sandbox::SandboxFactory::GetTargetServices() != nullptr);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  int val = -1;
+  const bool success = base::StringToInt(
+      command_line->GetSwitchValueASCII(kSandboxedProcessIdSwitch), &val);
+
+  SandboxType sandbox_type = SandboxType::kNonSandboxed;
+
+  if (success) {
+    sandbox_type = static_cast<SandboxType>(val);
+    DCHECK_GT(sandbox_type, SandboxType::kNonSandboxed);
+    DCHECK_LT(sandbox_type, SandboxType::kNumValues);
+  }
+
+  return sandbox_type;
+}
+
+ResultCode SpawnSandbox(SandboxSetupHooks* setup_hooks, SandboxType type) {
+  base::CommandLine sandbox_command_line(
+      PreFetchedPaths::GetInstance()->GetExecutablePath());
+
+  // Propagate the relevant switches from the current process to
+  // |sandbox_command_line|.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  for (const char* switch_name : kSwitchesToPropagate) {
+    if (command_line->HasSwitch(switch_name)) {
+      sandbox_command_line.AppendSwitchNative(
+          switch_name, command_line->GetSwitchValueNative(switch_name));
+    }
+  }
+  sandbox_command_line.AppendSwitchNative(kUseCrashHandlerWithIdSwitch,
+                                          GetCrashReporterIPCPipeName());
+
+  sandbox_command_line.AppendSwitchASCII(
+      kSandboxedProcessIdSwitch, base::IntToString(static_cast<int>(type)));
+
+  return StartSandboxTarget(sandbox_command_line, setup_hooks, type);
+}
+
+ResultCode StartSandboxTarget(const base::CommandLine& sandbox_command_line,
+                              SandboxSetupHooks* hooks,
+                              SandboxType type) {
+  if (!g_target_processes)
+    g_target_processes = new std::map<SandboxType, base::Process>();
+  // |StartSandboxTarget| gets called multiple times in tests.
+  if (g_target_processes->erase(type))
+    DCHECK_EQ(SandboxType::kTest, type);
+
+  base::ScopedClosureRunner notify_hooks_on_failure(base::DoNothing::Once());
+
+  if (hooks) {
+    // Unretained is safe because |hooks| lives for the entire enclosing scope.
+    notify_hooks_on_failure.ReplaceClosure(base::BindOnce(
+        &SandboxSetupHooks::SetupFailed, base::Unretained(hooks)));
+  }
+
+  sandbox::BrokerServices* sandbox_broker_services =
+      sandbox::SandboxFactory::GetBrokerServices();
+  CHECK(sandbox_broker_services);
+
+  // Make init_result static so broker services will only be initialized once.
+  // Otherwise, it could be initialized multiple times during tests.
+  static const sandbox::ResultCode init_result =
+      sandbox_broker_services->Init();
+  if (init_result != sandbox::SBOX_ALL_OK) {
+    LOG(FATAL) << "Failed to initialize sandbox BrokerServices: "
+               << init_result;
+    return RESULT_CODE_FAILED_TO_START_SANDBOX_PROCESS;
+  }
+
+  scoped_refptr<sandbox::TargetPolicy> policy =
+      GetSandboxPolicy(sandbox_broker_services);
+  base::CommandLine command_line = sandbox_command_line;
+
+  // Create an event so the sandboxed process can notify the broker when it
+  // has finished it's setup. This is useful because if the sandboxed process
+  // fails its setup, we can return the exit code to help debug the issue.
+  std::unique_ptr<base::WaitableEvent> init_done_event =
+      chrome_cleaner::CreateInheritableEvent(
+          base::WaitableEvent::ResetPolicy::MANUAL,
+          base::WaitableEvent::InitialState::NOT_SIGNALED);
+  command_line.AppendSwitchNative(
+      chrome_cleaner::kInitDoneNotifierSwitch,
+      base::UintToString16(
+          base::win::HandleToUint32(init_done_event->handle())));
+  policy->AddHandleToShare(init_done_event->handle());
+
+  if (hooks) {
+    ResultCode result_code =
+        hooks->UpdateSandboxPolicy(policy.get(), &command_line);
+    if (result_code != RESULT_CODE_SUCCESS)
+      return result_code;
+  }
+
+  // Spawn the sandbox target process.
+  PROCESS_INFORMATION temp_process_info = {0};
+  DWORD last_win_error = 0;
+  sandbox::ResultCode last_result_code = sandbox::SBOX_ALL_OK;
+  LOG(INFO) << "Starting sandbox process with command line arguments: "
+            << command_line.GetArgumentsString();
+  sandbox::ResultCode sandbox_result = sandbox_broker_services->SpawnTarget(
+      command_line.GetProgram().value().c_str(),
+      command_line.GetCommandLineString().c_str(), policy.get(),
+      &last_result_code, &last_win_error, &temp_process_info);
+  if (sandbox_result != sandbox::SBOX_ALL_OK) {
+    LOG(DFATAL) << "Failed to spawn sandbox target: " << sandbox_result
+                << " , last sandbox result : " << last_result_code
+                << " , last windows error: " << last_win_error;
+    return RESULT_CODE_FAILED_TO_START_SANDBOX_PROCESS;
+  }
+
+  base::Process process_handle = base::Process(temp_process_info.hProcess);
+  base::win::ScopedHandle thread_handle =
+      base::win::ScopedHandle(temp_process_info.hThread);
+
+  // Because objects on the stack on destroyed in reverse order of allocation,
+  // an early return from |StartSandboxTarget| will first call
+  // process_handle.Terminate() and then close process_handle.
+  base::ScopedClosureRunner terminate_process_on_failure(
+      base::BindOnce(base::IgnoreResult(&base::Process::Terminate),
+                     base::Unretained(&process_handle), -1, true));
+
+  if (hooks) {
+    ResultCode result_code =
+        hooks->TargetSpawned(process_handle, thread_handle);
+    if (result_code != RESULT_CODE_SUCCESS)
+      return result_code;
+  }
+
+  // The target is spawned paused, so resume it.
+  if (::ResumeThread(thread_handle.Get()) == static_cast<DWORD>(-1)) {
+    PLOG(ERROR) << "Failed to resume thread";
+    return RESULT_CODE_FAILED_TO_START_SANDBOX_PROCESS;
+  }
+
+  // Wait for the sandboxed process to signal it is ready, checking every now
+  // and then to see if the process crashed before it could complete it's setup.
+  int exit_code = -1;
+  while (!init_done_event->TimedWait(base::TimeDelta::FromSeconds(1))) {
+    if (process_handle.WaitForExitWithTimeout(base::TimeDelta(), &exit_code)) {
+      LOG(ERROR)
+          << "Sandboxed process exited before signaling it was initialized, "
+             "exit code: "
+          << exit_code;
+      return RESULT_CODE_FAILED_TO_START_SANDBOX_PROCESS;
+    }
+  }
+
+  if (hooks) {
+    ResultCode result_code = hooks->TargetResumed();
+    if (result_code != RESULT_CODE_SUCCESS)
+      return result_code;
+  }
+
+  // Now that the target process has been started successfully, don't call the
+  // failure closures. Instead transfer ownership of |process_handle| to a
+  // global that will be cleaned up by the OS on exit, so that it can be polled
+  // in |IsSandboxTargetRunning|.
+  g_target_processes->emplace(type, base::Process(std::move(process_handle)));
+  terminate_process_on_failure.ReplaceClosure(base::DoNothing::Once());
+  notify_hooks_on_failure.ReplaceClosure(base::DoNothing::Once());
+
+  return RESULT_CODE_SUCCESS;
+}
+
+bool IsSandboxTargetRunning(SandboxType type) {
+  if (!g_target_processes)
+    return false;
+  auto type_process_iter = g_target_processes->find(type);
+  if (type_process_iter == g_target_processes->end())
+    return false;
+
+  int exit_code = 0;
+  if (!type_process_iter->second.WaitForExitWithTimeout(base::TimeDelta(),
+                                                        &exit_code)) {
+    LOG(ERROR) << "WaitForExitWithTimeout failed";
+    return false;
+  }
+
+  return (exit_code == STILL_ACTIVE);
+}
+
+std::map<SandboxType, SystemResourceUsage> GetSandboxSystemResourceUsage() {
+  std::map<SandboxType, SystemResourceUsage> result;
+  if (g_target_processes) {
+    for (const auto& type_process : *g_target_processes) {
+      SystemResourceUsage stats;
+      if (GetSystemResourceUsage(type_process.second.Handle(), &stats))
+        result[type_process.first] = stats;
+    }
+  }
+  return result;
+}
+
+ResultCode RunSandboxTarget(const base::CommandLine& command_line,
+                            sandbox::TargetServices* sandbox_target_services,
+                            SandboxTargetHooks* hooks) {
+  CHECK(sandbox_target_services);
+  sandbox::ResultCode sandbox_result = sandbox_target_services->Init();
+  if (sandbox_result != sandbox::SBOX_ALL_OK) {
+    LOG(ERROR) << "Failed to initialize sandbox TargetServices: "
+               << sandbox_result;
+    return RESULT_CODE_FAILED;
+  }
+
+  DCHECK(hooks);
+  ResultCode result_code = hooks->TargetStartedWithHighPrivileges();
+  if (result_code != RESULT_CODE_SUCCESS)
+    return result_code;
+
+  sandbox_target_services->LowerToken();
+
+  NotifyInitializationDone();
+
+  return hooks->TargetDroppedPrivileges(command_line);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/ipc/sandbox.h b/chrome/chrome_cleaner/ipc/sandbox.h
new file mode 100644
index 0000000..f8982a8
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/sandbox.h
@@ -0,0 +1,130 @@
+// 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_CHROME_CLEANER_IPC_SANDBOX_H_
+#define CHROME_CHROME_CLEANER_IPC_SANDBOX_H_
+
+#include <stdlib.h>
+
+#include <map>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/chrome_cleaner/os/process.h"
+#include "chrome/chrome_cleaner/settings/settings_types.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace chrome_cleaner {
+
+// The suffix to append to log files for sandboxed processes.
+extern const wchar_t kSandboxLogFileSuffix[];
+
+// Functions that will be called while setting up the sandbox. Users of the
+// sandbox can implement these to add their own features, such as IPC pipes.
+class SandboxSetupHooks {
+ public:
+  SandboxSetupHooks();
+  virtual ~SandboxSetupHooks();
+
+  // Called before spawning the sandbox target process. |policy| is the set of
+  // policies that will be applied to the target process. |command_line| is the
+  // command-line it will be launched with. The callee can alter either of
+  // these objects.
+  //
+  // If the return value is anything except RESULT_CODE_SUCCESS, the target
+  // process will not be spawned and the return value will also be returned by
+  // |StartSandboxTarget|.
+  virtual ResultCode UpdateSandboxPolicy(sandbox::TargetPolicy* policy,
+                                         base::CommandLine* command_line);
+
+  // Called just after the target process is spawned, while it is still
+  // suspended. |target_process| wraps a handle to the sandboxed process, and
+  // |target_thread| wraps its main thread. The callee must duplicate these
+  // handles if it wishes to save them.
+  //
+  // If the return value is anything except RESULT_CODE_SUCCESS, the target
+  // process will be terminated and the return value will also be returned by
+  // |StartSandboxTarget|.
+  virtual ResultCode TargetSpawned(
+      const base::Process& target_process,
+      const base::win::ScopedHandle& target_thread);
+
+  // Called when the target process is no longer suspended. When this returns
+  // the sandbox setup is complete.
+  //
+  // If the return value is anything except RESULT_CODE_SUCCESS, the target
+  // process will be terminated and the return value will also be returned by
+  // |StartSandboxTarget|.
+  virtual ResultCode TargetResumed();
+
+  // Called as the last step of the sandbox setup if the process failed,
+  // including if it failed because a method of SandboxSetupHooks returned an
+  // error code.
+  virtual void SetupFailed();
+};
+
+// Functions that will be called in the sandbox target process. Users of the
+// sandbox must implement at least TargetDroppedPrivileges to provide the code
+// that will run in the sandbox after lowering privileges.
+class SandboxTargetHooks {
+ public:
+  SandboxTargetHooks();
+  virtual ~SandboxTargetHooks();
+
+  // Called after the process starts, before it has dropped all privileges. The
+  // callee can do any setup which requires higher privileges here. It is
+  // unsafe to call untrusted code or process untrusted data from this method.
+  //
+  // If the return value is anything except RESULT_CODE_SUCCESS, the target
+  // process will exit using the return value as the exit code.
+  virtual ResultCode TargetStartedWithHighPrivileges();
+
+  // Called after TargetProcess::LowerToken. The callee should do all
+  // processing that must be done in the sandbox here.
+  //
+  // The target process will exit using the return value as the exit code.
+  virtual ResultCode TargetDroppedPrivileges(
+      const base::CommandLine& command_line) = 0;
+};
+
+// Returns the type of process this sandbox is. This should only be called by
+// sandboxed processes.
+SandboxType SandboxProcessType();
+
+// Spawns a new sandbox target with the given |setup_hooks| passed by
+// parameters. The parameter |type| indicates the type of sandbox that is being
+// created and therefore the switch kSandboxedProcessIdSwitch should be expected
+// on the target's command line with the value specified on this parameter.
+ResultCode SpawnSandbox(SandboxSetupHooks* setup_hooks, SandboxType type);
+
+// Starts a sandbox target process with the command line
+// |sandbox_command_line|.  If |hooks| is non-null its methods will be called
+// during setup.
+ResultCode StartSandboxTarget(const base::CommandLine& sandbox_command_line,
+                              SandboxSetupHooks* hooks,
+                              SandboxType type);
+
+// Returns whether a sandbox target process is currently running or not.
+bool IsSandboxTargetRunning(SandboxType type);
+
+// Calls the methods of |hooks| and returns the result code of the last one to
+// execute.  This will be called in the sandbox target process. |command_line|
+// is the command line the process was launched with. |sandbox_target_services|
+// should be the object returned by SandboxFactory::GetTargetServices() except
+// when it is overridden in unit tests.
+ResultCode RunSandboxTarget(const base::CommandLine& command_line,
+                            sandbox::TargetServices* sandbox_target_services,
+                            SandboxTargetHooks* hooks);
+
+// Retrieves system resource usage stats for all sandbox target processes, even
+// if the target processes have already exited.
+std::map<SandboxType, SystemResourceUsage> GetSandboxSystemResourceUsage();
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_IPC_SANDBOX_H_
diff --git a/chrome/chrome_cleaner/ipc/sandbox_unittest.cc b/chrome/chrome_cleaner/ipc/sandbox_unittest.cc
new file mode 100644
index 0000000..0a7dd58
--- /dev/null
+++ b/chrome/chrome_cleaner/ipc/sandbox_unittest.cc
@@ -0,0 +1,186 @@
+// 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/chrome_cleaner/ipc/sandbox.h"
+
+#include <windows.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/logging/scoped_logging.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/os/initializer.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+constexpr int kChildExitCode = 420042;
+
+class MockSandboxTargetServices : public sandbox::TargetServices {
+ public:
+  MockSandboxTargetServices() = default;
+  ~MockSandboxTargetServices() = default;
+
+  MOCK_METHOD0(Init, sandbox::ResultCode());
+  MOCK_METHOD0(LowerToken, void());
+  MOCK_METHOD0(GetState, sandbox::ProcessState*());
+};
+
+class TestSandboxSetupHooks : public SandboxSetupHooks {
+ public:
+  explicit TestSandboxSetupHooks(base::Process* process_holder)
+      : process_holder_(process_holder) {}
+  ~TestSandboxSetupHooks() override = default;
+
+  ResultCode TargetSpawned(
+      const base::Process& target_process,
+      const base::win::ScopedHandle& target_thread) override {
+    DCHECK(process_holder_);
+    *process_holder_ = target_process.Duplicate();
+    return SandboxSetupHooks::TargetSpawned(target_process, target_thread);
+  }
+
+ private:
+  base::Process* process_holder_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSandboxSetupHooks);
+};
+
+class TestSandboxTargetHooks : public SandboxTargetHooks {
+ public:
+  TestSandboxTargetHooks() = default;
+  ~TestSandboxTargetHooks() override = default;
+
+  ResultCode TargetDroppedPrivileges(
+      const base::CommandLine& command_line) override {
+    return RESULT_CODE_SUCCESS;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestSandboxTargetHooks);
+};
+
+class SandboxTest : public base::MultiProcessTest {
+ protected:
+  SandboxTest() = default;
+
+  void SetUp() override {
+    // Delete the sandbox process log file. If we decide to log its content,
+    // it will only contain output relevant to this test case. DeleteFile
+    // returns true on success or if attempting to delete a file that does not
+    // exist.
+    sandbox_process_log_file_path_ =
+        ScopedLogging::GetLogFilePath(kSandboxLogFileSuffix);
+    EXPECT_TRUE(base::DeleteFile(sandbox_process_log_file_path_, false));
+  }
+
+  void TearDown() override {
+    if (HasFailure() && base::PathExists(sandbox_process_log_file_path_)) {
+      // Collect the sandbox process log file, and dump the contents, to help
+      // debugging failures.
+      std::string log_file_contents;
+      if (base::ReadFileToString(sandbox_process_log_file_path_,
+                                 &log_file_contents)) {
+        std::vector<base::StringPiece> lines = base::SplitStringPiece(
+            log_file_contents, "\n", base::TRIM_WHITESPACE,
+            base::SPLIT_WANT_NONEMPTY);
+        LOG(ERROR) << "Dumping sandbox process log";
+        for (const auto& line : lines) {
+          LOG(ERROR) << "Sandbox process log line: " << line;
+        }
+      } else {
+        LOG(ERROR) << "Failed to read sandbox process log file";
+      }
+    }
+  }
+
+  // Starts a child process using the StartSandboxTarget API.
+  bool SpawnMockSandboxProcess(base::Process* process) {
+    TestSandboxSetupHooks setup_hooks(process);
+    return chrome_cleaner::StartSandboxTarget(
+               MakeCmdLine("MockSandboxProcessMain"), &setup_hooks,
+               SandboxType::kTest) == RESULT_CODE_SUCCESS;
+  }
+
+  ResultCode TestRunSandboxTarget(const base::CommandLine& command_line) {
+    TestSandboxTargetHooks hooks;
+    return RunSandboxTarget(command_line, &mock_sandbox_target_services_,
+                            &hooks);
+  }
+
+ private:
+  MockSandboxTargetServices mock_sandbox_target_services_;
+  base::FilePath sandbox_process_log_file_path_;
+};
+
+MULTIPROCESS_TEST_MAIN(MockSandboxProcessMain) {
+  base::FilePath product_path;
+  bool success = chrome_cleaner::GetAppDataProductDirectory(&product_path);
+  CHECK(success);
+  auto* target_services = sandbox::SandboxFactory::GetTargetServices();
+  CHECK(target_services);
+  NotifyInitializationDone();
+  target_services->LowerToken();
+
+  bool have_write_access = false;
+  base::FilePath temp_file;
+  if (base::CreateTemporaryFileInDir(product_path, &temp_file)) {
+    have_write_access = true;
+    base::DeleteFile(temp_file, /*recursive=*/false);
+  }
+
+#if defined(CHROME_CLEANER_OFFICIAL_BUILD)
+  CHECK(!have_write_access);
+#else
+  CHECK(have_write_access);
+#endif
+
+  // Lower token, test access.
+  return kChildExitCode;
+}
+
+}  // namespace
+
+TEST_F(SandboxTest, SpawnSandboxTarget) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8) {
+    // TODO(b/871924): This test is currently failing on win7. Fix and enable.
+    return;
+  }
+
+  base::Process target_process;
+  EXPECT_TRUE(SpawnMockSandboxProcess(&target_process));
+  EXPECT_TRUE(target_process.IsValid());
+
+  int exit_code = -1;
+  EXPECT_TRUE(target_process.WaitForExitWithTimeout(
+      base::TimeDelta::FromSeconds(10), &exit_code));
+  EXPECT_EQ(kChildExitCode, exit_code);
+}
+
+TEST_F(SandboxTest, RunSandboxTarget) {
+  EXPECT_EQ(RESULT_CODE_SUCCESS,
+            TestRunSandboxTarget(*base::CommandLine::ForCurrentProcess()));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/os/BUILD.gn b/chrome/chrome_cleaner/os/BUILD.gn
index df91f9d..98a5567 100644
--- a/chrome/chrome_cleaner/os/BUILD.gn
+++ b/chrome/chrome_cleaner/os/BUILD.gn
@@ -16,6 +16,8 @@
     "file_path_sanitization.h",
     "file_path_set.cc",
     "file_path_set.h",
+    "inheritable_event.cc",
+    "inheritable_event.h",
     "initializer.cc",
     "initializer.h",
     "layered_service_provider_api.h",
diff --git a/chrome/chrome_cleaner/os/inheritable_event.cc b/chrome/chrome_cleaner/os/inheritable_event.cc
new file mode 100644
index 0000000..65d8a2556
--- /dev/null
+++ b/chrome/chrome_cleaner/os/inheritable_event.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/os/inheritable_event.h"
+
+#include <windows.h>
+
+namespace chrome_cleaner {
+
+std::unique_ptr<base::WaitableEvent> CreateInheritableEvent(
+    base::WaitableEvent::ResetPolicy reset_policy,
+    base::WaitableEvent::InitialState initial_state) {
+  SECURITY_ATTRIBUTES attributes = {sizeof(SECURITY_ATTRIBUTES)};
+  attributes.bInheritHandle = true;
+
+  HANDLE handle = ::CreateEvent(
+      &attributes, reset_policy == base::WaitableEvent::ResetPolicy::MANUAL,
+      initial_state == base::WaitableEvent::InitialState::SIGNALED, nullptr);
+  if (handle == nullptr || handle == INVALID_HANDLE_VALUE) {
+    PLOG(ERROR) << "Could not create inheritable event";
+    return nullptr;
+  }
+  base::win::ScopedHandle event_handle(handle);
+  return std::make_unique<base::WaitableEvent>(std::move(event_handle));
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/os/inheritable_event.h b/chrome/chrome_cleaner/os/inheritable_event.h
new file mode 100644
index 0000000..40086a5
--- /dev/null
+++ b/chrome/chrome_cleaner/os/inheritable_event.h
@@ -0,0 +1,20 @@
+// 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_CHROME_CLEANER_OS_INHERITABLE_EVENT_H_
+#define CHROME_CHROME_CLEANER_OS_INHERITABLE_EVENT_H_
+
+#include <memory>
+
+#include "base/synchronization/waitable_event.h"
+
+namespace chrome_cleaner {
+
+std::unique_ptr<base::WaitableEvent> CreateInheritableEvent(
+    base::WaitableEvent::ResetPolicy reset_policy,
+    base::WaitableEvent::InitialState initial_state);
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_OS_INHERITABLE_EVENT_H_
diff --git a/chrome/chrome_cleaner/os/initializer.cc b/chrome/chrome_cleaner/os/initializer.cc
index b694ce4..be2d4fd 100644
--- a/chrome/chrome_cleaner/os/initializer.cc
+++ b/chrome/chrome_cleaner/os/initializer.cc
@@ -20,6 +20,33 @@
 
 namespace chrome_cleaner {
 
+namespace {
+
+std::unique_ptr<base::WaitableEvent> SignalInitializationDone() {
+  base::win::ScopedHandle init_done_notifier;
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  uint32_t handle = 0;
+  if (command_line->HasSwitch(kInitDoneNotifierSwitch) &&
+      base::StringToUint(
+          command_line->GetSwitchValueNative(kInitDoneNotifierSwitch),
+          &handle)) {
+    init_done_notifier.Set(base::win::Uint32ToHandle(handle));
+  }
+
+  std::unique_ptr<base::WaitableEvent> notifier_event;
+  if (init_done_notifier.IsValid()) {
+    notifier_event.reset(
+        new base::WaitableEvent(std::move(init_done_notifier)));
+
+    // Wake up the test that is waiting on this event.
+    notifier_event->Signal();
+  }
+  return notifier_event;
+}
+
+}  // namespace
+
 bool InitializeOSUtils() {
   chrome_cleaner::InitializeFilePathSanitization();
   chrome_cleaner::InitializeDiskUtil();
@@ -36,29 +63,20 @@
   return true;
 }
 
+void NotifyInitializationDone() {
+  SignalInitializationDone();
+}
+
 void NotifyInitializationDoneForTesting() {
-  base::win::ScopedHandle init_done_notifier;
+  std::unique_ptr<base::WaitableEvent> notifier_event =
+      SignalInitializationDone();
 
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  uint32_t handle = 0;
-  if (command_line->HasSwitch(kInitDoneNotifierSwitch) &&
-      base::StringToUint(
-          command_line->GetSwitchValueNative(kInitDoneNotifierSwitch),
-          &handle)) {
-    init_done_notifier.Set(base::win::Uint32ToHandle(handle));
-  }
-
-  if (init_done_notifier.IsValid()) {
-    base::WaitableEvent notifier_event(std::move(init_done_notifier));
-
-    // Wake up the test that is waiting on this event.
-    notifier_event.Signal();
-
+  if (notifier_event) {
     // The event has ResetPolicy AUTOMATIC, so after the test is woken up it is
     // immediately reset. Wait at most 5 seconds for the test to signal that
     // it's ready using the same event before continuing. If the test takes
     // longer than that stop waiting to prevent hangs.
-    notifier_event.TimedWait(base::TimeDelta::FromSeconds(5));
+    notifier_event->TimedWait(base::TimeDelta::FromSeconds(5));
   }
 }
 
diff --git a/chrome/chrome_cleaner/os/initializer.h b/chrome/chrome_cleaner/os/initializer.h
index aa584da..80bd93b1 100644
--- a/chrome/chrome_cleaner/os/initializer.h
+++ b/chrome/chrome_cleaner/os/initializer.h
@@ -11,12 +11,15 @@
 // work.
 bool InitializeOSUtils();
 
-// Signals the event handle was passed on the commandline with
+// Signals the event handle that was passed on the commandline with
+// --init-done-notifier, if it exists.
+void NotifyInitializationDone();
+
+// Signals the event handle that was passed on the commandline with
 // --init-done-notifier, if it exists. Then waits for the event to be signalled
 // again before continuing. This allows a test harness to pause the binary's
 // execution, do some extra setup, and resume it.
-//
-// Does nothing in official builds.
+// Note, this means the event must be AUTOMATIC.
 void NotifyInitializationDoneForTesting();
 
 }  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc b/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc
index 2305931..c9ad6c3 100644
--- a/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc
+++ b/chrome/chrome_cleaner/os/system_util_cleaner_unittest.cc
@@ -84,7 +84,8 @@
   EXPECT_FALSE(DoesServiceExist(service_handle.service_name()));
 }
 
-TEST_F(ServiceUtilCleanerTest, StopAndDeleteRunningService) {
+// Flaky. https://crbug.com/871784
+TEST_F(ServiceUtilCleanerTest, DISABLED_StopAndDeleteRunningService) {
   // Install and launch the service.
   TestScopedServiceHandle service_handle;
   ASSERT_TRUE(service_handle.InstallService());
@@ -107,7 +108,8 @@
   EXPECT_FALSE(IsProcessRunning(kTestServiceExecutableName));
 }
 
-TEST_F(ServiceUtilCleanerTest, DeleteRunningService) {
+// Flaky. https://crbug.com/871784
+TEST_F(ServiceUtilCleanerTest, DISABLED_DeleteRunningService) {
   // Install and launch the service.
   TestScopedServiceHandle service_handle;
   ASSERT_TRUE(service_handle.InstallService());
diff --git a/chrome/chrome_cleaner/settings/settings.cc b/chrome/chrome_cleaner/settings/settings.cc
index cb895b4..114b224 100644
--- a/chrome/chrome_cleaner/settings/settings.cc
+++ b/chrome/chrome_cleaner/settings/settings.cc
@@ -43,7 +43,8 @@
 
 ExecutionMode GetExecutionMode(const base::CommandLine& command_line) {
   int val = -1;
-  // WARNING: this switch is used in Bineval, be careful when making changes.
+  // WARNING: this switch is used by internal test systems, be careful when
+  // making changes.
   if (base::StringToInt(command_line.GetSwitchValueASCII(kExecutionModeSwitch),
                         &val) &&
       val > static_cast<int>(ExecutionMode::kNone) &&
@@ -60,8 +61,8 @@
     case TargetBinary::kReporter:
       // For the reporter, if logging collection is enabled, then we will save
       // UwS matching to a proto that can be saved to disk or sent to Google if
-      // logs upload is allowed. WARNING: this switch is used in Bineval, be
-      // careful when making changes.
+      // logs upload is allowed. WARNING: this switch is used by internal test
+      // systems, be careful when making changes.
       return command_line.HasSwitch(kExtendedSafeBrowsingEnabledSwitch);
     case TargetBinary::kCleaner:
       // Logs collection is only enabled if the user did not opt out, which
@@ -79,7 +80,8 @@
 bool GetLogsUploadAllowed(const base::CommandLine& command_line,
                           TargetBinary target_binary,
                           ExecutionMode execution_mode) {
-  // WARNING: this switch is used in Bineval, be careful when making changes.
+  // WARNING: this switch is used by internal test systems, be careful when
+  // making changes.
   if (command_line.HasSwitch(kNoReportUploadSwitch))
     return false;
 
@@ -90,7 +92,8 @@
   if (command_line.HasSwitch(kNoCrashUploadSwitch))
     return false;
 
-  // WARNING: this switch is used in Bineval, be careful when making changes.
+  // WARNING: this switch is used by internal test systems, be careful when
+  // making changes.
   return command_line.HasSwitch(kEnableCrashReportingSwitch);
 }
 
@@ -308,7 +311,8 @@
   engine_ = GetEngine(command_line);
 
   metrics_enabled_ = command_line.HasSwitch(kUmaUserSwitch);
-  // WARNING: this switch is used in Bineval, be careful when making changes.
+  // WARNING: this switch is used by internal test systems, be careful when
+  // making changes.
   sber_enabled_ = command_line.HasSwitch(kExtendedSafeBrowsingEnabledSwitch);
   execution_mode_ = GetExecutionMode(command_line);
   logs_upload_allowed_ =
diff --git a/chrome/chrome_cleaner/test/BUILD.gn b/chrome/chrome_cleaner/test/BUILD.gn
index 8672245..f811aea 100644
--- a/chrome/chrome_cleaner/test/BUILD.gn
+++ b/chrome/chrome_cleaner/test/BUILD.gn
@@ -48,6 +48,7 @@
     ":test_util",
     "//base:base",
     "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/os:common_os",
   ]
 }
 
diff --git a/chrome/chrome_cleaner/test/test_executables.cc b/chrome/chrome_cleaner/test/test_executables.cc
index f92500559..4524356 100644
--- a/chrome/chrome_cleaner/test/test_executables.cc
+++ b/chrome/chrome_cleaner/test/test_executables.cc
@@ -12,6 +12,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/win/win_util.h"
 #include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/os/inheritable_event.h"
 #include "chrome/chrome_cleaner/test/test_strings.h"
 #include "chrome/chrome_cleaner/test/test_util.h"
 
diff --git a/chrome/chrome_cleaner/test/test_main.cc b/chrome/chrome_cleaner/test/test_main.cc
index f551a25..4286710 100644
--- a/chrome/chrome_cleaner/test/test_main.cc
+++ b/chrome/chrome_cleaner/test/test_main.cc
@@ -9,10 +9,14 @@
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "base/win/scoped_com_initializer.h"
+#include "chrome/chrome_cleaner/crash/crash_client.h"
+#include "chrome/chrome_cleaner/ipc/sandbox.h"
+#include "chrome/chrome_cleaner/logging/scoped_logging.h"
 #include "chrome/chrome_cleaner/os/rebooter.h"
 #include "chrome/chrome_cleaner/os/secure_dll_loading.h"
 #include "chrome/chrome_cleaner/os/system_util_cleaner.h"
 #include "chrome/chrome_cleaner/os/task_scheduler.h"
+#include "chrome/chrome_cleaner/settings/settings_types.h"
 #include "chrome/chrome_cleaner/test/test_util.h"
 #include "sandbox/win/src/sandbox_factory.h"
 
@@ -24,6 +28,26 @@
   return is_sandboxed_process;
 }
 
+// base::TestSuite's Initialize method initializes logging differently than we
+// do. This subclass ensures logging is properly initialized using ScopedLogging
+// after base::TestSuite::Initialize has run.
+class ChromeCleanerTestSuite : public base::TestSuite {
+ public:
+  // Inherit constructors.
+  using base::TestSuite::TestSuite;
+
+ protected:
+  void Initialize() override {
+    base::TestSuite::Initialize();
+    scoped_logging.reset(new chrome_cleaner::ScopedLogging(
+        IsSandboxedProcess() ? chrome_cleaner::kSandboxLogFileSuffix
+                             : nullptr));
+  }
+
+ private:
+  std::unique_ptr<chrome_cleaner::ScopedLogging> scoped_logging;
+};
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -34,7 +58,7 @@
   // affect the behaviour of functionality that's tested.
   chrome_cleaner::EnableSecureDllLoading();
 
-  base::TestSuite test_suite(argc, argv);
+  ChromeCleanerTestSuite test_suite(argc, argv);
 
   if (!chrome_cleaner::SetupTestConfigs())
     return 1;
@@ -60,6 +84,15 @@
 
     success = chrome_cleaner::TaskScheduler::Initialize();
     DCHECK(success) << "TaskScheduler::Initialize() failed.";
+
+    // Crash reporting must be initialized only once, so it cannot be
+    // initialized by individual tests or fixtures. Also, since crashpad does
+    // not actually enable uploading of crash reports in non-official builds
+    // (unless forced to by the --enable-crash-reporting flag) we don't need to
+    // disable crash reporting.
+    chrome_cleaner::CrashClient::GetInstance()->InitializeCrashReporting(
+        chrome_cleaner::CrashClient::Mode::CLEANER,
+        chrome_cleaner::SandboxType::kNonSandboxed);
   }
 
   // Some tests will fail if two tests try to launch test_process.exe
diff --git a/chrome/chrome_cleaner/test/test_util.cc b/chrome/chrome_cleaner/test/test_util.cc
index ac643fd..10a854b 100644
--- a/chrome/chrome_cleaner/test/test_util.cc
+++ b/chrome/chrome_cleaner/test/test_util.cc
@@ -273,23 +273,6 @@
   return CreateEmptyFile(GetPath().Append(file_name));
 }
 
-std::unique_ptr<base::WaitableEvent> CreateInheritableEvent(
-    base::WaitableEvent::ResetPolicy reset_policy,
-    base::WaitableEvent::InitialState initial_state) {
-  SECURITY_ATTRIBUTES attributes = {sizeof(SECURITY_ATTRIBUTES)};
-  attributes.bInheritHandle = true;
-
-  HANDLE handle = ::CreateEvent(
-      &attributes, reset_policy == base::WaitableEvent::ResetPolicy::MANUAL,
-      initial_state == base::WaitableEvent::InitialState::SIGNALED, nullptr);
-  if (handle == nullptr || handle == INVALID_HANDLE_VALUE) {
-    PLOG(ERROR) << "Could not create inheritable event";
-    return std::unique_ptr<base::WaitableEvent>();
-  }
-  base::win::ScopedHandle event_handle(handle);
-  return std::make_unique<base::WaitableEvent>(std::move(event_handle));
-}
-
 bool CheckTestPrivileges() {
   // Check for administrator privileges, unless running in the sandbox.
   const bool is_sandboxed_process =
diff --git a/chrome/chrome_cleaner/test/test_util.h b/chrome/chrome_cleaner/test/test_util.h
index c0cd0139..4172780 100644
--- a/chrome/chrome_cleaner/test/test_util.h
+++ b/chrome/chrome_cleaner/test/test_util.h
@@ -163,9 +163,6 @@
   // directory.
 };
 
-std::unique_ptr<base::WaitableEvent> CreateInheritableEvent(
-    base::WaitableEvent::ResetPolicy reset_policy,
-    base::WaitableEvent::InitialState initial_state);
 
 // Check that the test has administrator privileges, but not debug privileges.
 // This function drops unneeded privileges if possible, but won't try to raise
diff --git a/chrome/common/extensions/api/arc_apps_private.idl b/chrome/common/extensions/api/arc_apps_private.idl
index c6ac109..7f32cdff 100644
--- a/chrome/common/extensions/api/arc_apps_private.idl
+++ b/chrome/common/extensions/api/arc_apps_private.idl
@@ -9,22 +9,27 @@
 namespace arcAppsPrivate {
 
   dictionary AppInfo {
-    // The app id.
-    DOMString id;
+    // The app package name.
+    DOMString packageName;
   };
 
   callback VoidCallback = void ();
-  callback GetLaunchableAppsCallback = void (AppInfo[] apps_info);
+  callback GetLaunchableAppsCallback = void (AppInfo[] appsInfo);
 
   interface Functions {
     // Returns info of the installed ARC apps that are launchable, including
     // ready and non-ready apps.
     static void getLaunchableApps(GetLaunchableAppsCallback callback);
 
-    // Launches the ARC app with |app_id|, which must be returned by
-    // |getLaunchableApps|. The app is launched immediately if it's ready,
-    // otherwise it will be launched when it becomes ready. The callback is
-    // called as soon as the launch is scheduled.
-    static void launchApp(DOMString app_id, optional VoidCallback callback);
+    // Launches the ARC app with its package name. The app is launched
+    // immediately if it's ready, otherwise it will be launched when it becomes
+    // ready. The callback is called as soon as the launch is scheduled.
+    static void launchApp(DOMString packageName,
+                          optional VoidCallback callback);
+  };
+
+  interface Events {
+    // Fires when a new app can be launched via $(ref:launchApp).
+    static void onInstalled(AppInfo app_info);
   };
 };
\ No newline at end of file
diff --git a/chrome/common/extensions/api/privacy.json b/chrome/common/extensions/api/privacy.json
index c6843e6..9c22611 100644
--- a/chrome/common/extensions/api/privacy.json
+++ b/chrome/common/extensions/api/privacy.json
@@ -59,6 +59,16 @@
             "value": ["autofillEnabled", {"type":"boolean"}],
             "description": "If enabled, Chrome offers to automatically fill in forms. This preference's value is a boolean, defaulting to <code>true</code>."
           },
+          "autofillAddressEnabled": {
+            "$ref": "types.ChromeSetting",
+            "value": ["autofillAddressEnabled", {"type":"boolean"}],
+            "description": "If enabled, Chrome offers to automatically fill in address forms. This preference's value is a boolean, defaulting to <code>true</code>."
+          },
+          "autofillCreditCardEnabled": {
+            "$ref": "types.ChromeSetting",
+            "value": ["autofillCreditCardEnabled", {"type":"boolean"}],
+            "description": "If enabled, Chrome offers to automatically fill in credit card forms. This preference's value is a boolean, defaulting to <code>true</code>."
+          },
           "passwordSavingEnabled": {
             "$ref": "types.ChromeSetting",
             "value": ["passwordSavingEnabled", {"type":"boolean"}],
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 4efe9184..a9e69e7 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2603,6 +2603,9 @@
 
 // Holds URL patterns that specify URLs that will be allowed to autoplay.
 const char kAutoplayWhitelist[] = "media.autoplay_whitelist";
+
+// Boolean that specifies whether autoplay blocking is enabled.
+const char kBlockAutoplayEnabled[] = "media.block_autoplay";
 #endif  // !defined(OS_ANDROID)
 
 // Integer that holds the value of the next persistent notification ID to be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index f84cb51..052a5b58 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -915,6 +915,7 @@
 #if !defined(OS_ANDROID)
 extern const char kAutoplayAllowed[];
 extern const char kAutoplayWhitelist[];
+extern const char kBlockAutoplayEnabled[];
 #endif
 
 extern const char kNotificationNextPersistentId[];
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index c9d8961..829f237 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -1226,7 +1226,8 @@
                                    const char* placeholder_lastname,
                                    const char* placeholder_phone,
                                    const char* placeholder_creditcard,
-                                   const char* placeholder_city) {
+                                   const char* placeholder_city,
+                                   const char* placeholder_state) {
     LoadHTML(html);
     WebLocalFrame* web_frame = GetMainFrame();
     ASSERT_NE(nullptr, web_frame);
@@ -1241,7 +1242,7 @@
     std::vector<WebFormControlElement> control_elements =
         ExtractAutofillableElementsInForm(form_element);
 
-    ASSERT_EQ(5U, control_elements.size());
+    ASSERT_EQ(6U, control_elements.size());
     // We now modify the values.
     // This will be ignored, the string will be sanitized into an empty string.
     control_elements[0].SetValue(WebString::FromUTF16(
@@ -1264,6 +1265,9 @@
     control_elements[4].SetValue(
         WebString::FromUTF16(ASCIIToUTF16("Enter your city..")));
 
+    control_elements[5].SetValue(WebString::FromUTF16(ASCIIToUTF16("AK")));
+    control_elements[5].SetUserHasEditedTheFieldForTest();
+
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
@@ -1275,7 +1279,7 @@
     EXPECT_EQ(GURL("http://abc.com"), form.action);
 
     const std::vector<FormFieldData>& fields = form.fields;
-    ASSERT_EQ(5U, fields.size());
+    ASSERT_EQ(6U, fields.size());
 
     // Preview the form and verify that the cursor position has been updated.
     form.fields[0].value = ASCIIToUTF16("Wyatt");
@@ -1283,11 +1287,13 @@
     form.fields[2].value = ASCIIToUTF16("888-123-4567");
     form.fields[3].value = ASCIIToUTF16("1111-2222-3333-4444");
     form.fields[4].value = ASCIIToUTF16("Montreal");
+    form.fields[5].value = ASCIIToUTF16("AA");
     form.fields[0].is_autofilled = true;
     form.fields[1].is_autofilled = true;
     form.fields[2].is_autofilled = true;
     form.fields[3].is_autofilled = true;
     form.fields[4].is_autofilled = true;
+    form.fields[5].is_autofilled = true;
     PreviewForm(form, input_element);
     // The selection should be set after the fifth character.
     EXPECT_EQ(5, input_element.SelectionStart());
@@ -1307,7 +1313,7 @@
     EXPECT_EQ(GURL("http://abc.com"), form2.action);
 
     const std::vector<FormFieldData>& fields2 = form2.fields;
-    ASSERT_EQ(5U, fields2.size());
+    ASSERT_EQ(6U, fields2.size());
 
     FormFieldData expected;
     expected.form_control_type = "text";
@@ -1378,6 +1384,24 @@
         base::FeatureList::IsEnabled(features::kAutofillPrefilledFields);
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[4]);
 
+    expected.form_control_type = "select-one";
+    expected.name = ASCIIToUTF16("state");
+    expected.value =
+        base::FeatureList::IsEnabled(features::kAutofillPrefilledFields)
+            ? ASCIIToUTF16("AA")
+            : control_elements[5].Value().Utf16();
+    if (placeholder_state) {
+      expected.label = ASCIIToUTF16(placeholder_state);
+      expected.placeholder = ASCIIToUTF16(placeholder_state);
+    } else {
+      expected.label.clear();
+      expected.placeholder.clear();
+    }
+    expected.is_autofilled =
+        base::FeatureList::IsEnabled(features::kAutofillPrefilledFields);
+    expected.max_length = 0;
+    EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[5]);
+
     // Verify that the cursor position has been updated.
     EXPECT_EQ(5, input_element.SelectionStart());
     EXPECT_EQ(5, input_element.SelectionEnd());
@@ -4796,9 +4820,16 @@
       "  <INPUT type='text' id='cc' placeholder='Credit Card Number' "
       "value='Credit Card'/>"
       "  <INPUT type='text' id='city' placeholder='City' value='City'/>"
+      "  <SELECT id='state' name='state' placeholder='State'>"
+      "    <OPTION selected>?</OPTION>"
+      "    <OPTION>AA</OPTION>"
+      "    <OPTION>AE</OPTION>"
+      "    <OPTION>AK</OPTION>"
+      "  </SELECT>"
       "  <INPUT type='submit' value='Send'/>"
       "</FORM>",
-      "First Name", "Last Name", "Phone", "Credit Card Number", "City");
+      "First Name", "Last Name", "Phone", "Credit Card Number", "City",
+      "State");
 }
 
 TEST_F(FormAutofillTest, FillFormModifyInitiatingValue) {
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index fbf143fd..5ca3cf84 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -94,6 +94,7 @@
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/mime_handler_view_mode.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/renderer/plugin_instance_throttler.h"
@@ -630,6 +631,38 @@
                                    .ToSkBitmap());
 }
 
+bool ChromeContentRendererClient::IsPluginHandledByMimeHandlerView(
+    content::RenderFrame* render_frame,
+    const blink::WebElement& plugin_element,
+    const GURL& original_url,
+    const std::string& mime_type,
+    int32_t instance_id_to_use) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  DCHECK(plugin_element.HasHTMLTagName("object") ||
+         plugin_element.HasHTMLTagName("embed"));
+  if (!content::MimeHandlerViewMode::UsesCrossProcessFrame())
+    return false;
+  // Blink will next try to load a WebPlugin which would end up in
+  // OverrideCreatePlugin, sending another IPC only to find out the plugin is
+  // not supported. Here it suffices to return false but there should perhaps be
+  // a more unified approach to avoid sending the IPC twice.
+  chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New();
+  GetPluginInfoHost()->GetPluginInfo(
+      render_frame->GetRoutingID(), original_url,
+      render_frame->GetWebFrame()->Top()->GetSecurityOrigin(), mime_type,
+      &plugin_info);
+  if (plugin_info->status == chrome::mojom::PluginStatus::kNotFound ||
+      !ChromeExtensionsRendererClient::IsPluginHandledByMimeHandlerView(
+          plugin_element, original_url, plugin_info->actual_mime_type,
+          plugin_info->plugin, instance_id_to_use)) {
+    return false;
+  }
+  return true;
+#else
+  return false;
+#endif
+}
+
 bool ChromeContentRendererClient::OverrideCreatePlugin(
     content::RenderFrame* render_frame,
     const WebPluginParams& params,
@@ -1232,8 +1265,7 @@
                                              const GURL& url,
                                              const std::string& http_method,
                                              bool is_initial_navigation,
-                                             bool is_server_redirect,
-                                             bool* send_referrer) {
+                                             bool is_server_redirect) {
   DCHECK(!frame->Parent());
 
 #if !defined(OS_ANDROID)
@@ -1245,7 +1277,6 @@
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kInstantProcess) ||
       SearchBouncer::GetInstance()->ShouldFork(url)) {
-    *send_referrer = true;
     return true;
   }
 #endif
@@ -1266,13 +1297,12 @@
   // navigation is attempted.
   if (prerender_dispatcher_.get() &&
       prerender_dispatcher_->IsPrerenderURL(url)) {
-    *send_referrer = true;
     return true;
   }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   bool should_fork = ChromeExtensionsRendererClient::ShouldFork(
-      frame, url, is_initial_navigation, is_server_redirect, send_referrer);
+      frame, url, is_initial_navigation, is_server_redirect);
   if (should_fork)
     return true;
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index 811b2f2..ad6046f 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -113,6 +113,11 @@
   void RenderViewCreated(content::RenderView* render_view) override;
   SkBitmap* GetSadPluginBitmap() override;
   SkBitmap* GetSadWebViewBitmap() override;
+  bool IsPluginHandledByMimeHandlerView(content::RenderFrame* render_frame,
+                                        const blink::WebElement& plugin_element,
+                                        const GURL& original_url,
+                                        const std::string& mime_type,
+                                        int32_t instance_id_to_use) override;
   bool OverrideCreatePlugin(content::RenderFrame* render_frame,
                             const blink::WebPluginParams& params,
                             blink::WebPlugin** plugin) override;
@@ -153,8 +158,7 @@
                   const GURL& url,
                   const std::string& http_method,
                   bool is_initial_navigation,
-                  bool is_server_redirect,
-                  bool* send_referrer) override;
+                  bool is_server_redirect) override;
   void WillSendRequest(blink::WebLocalFrame* frame,
                        ui::PageTransition transition_type,
                        const blink::WebURL& url,
diff --git a/chrome/renderer/chrome_content_renderer_client_browsertest.cc b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
index 4fb64e33..61ff236 100644
--- a/chrome/renderer/chrome_content_renderer_client_browsertest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
@@ -51,11 +51,10 @@
 TEST_F(InstantProcessNavigationTest, ForkForNavigationsFromInstantProcess) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kInstantProcess);
-  bool unused;
   ChromeContentRendererClient* client =
       static_cast<ChromeContentRendererClient*>(content_renderer_client_.get());
-  EXPECT_TRUE(client->ShouldFork(
-      GetMainFrame(), GURL("http://foo"), "GET", false, false, &unused));
+  EXPECT_TRUE(client->ShouldFork(GetMainFrame(), GURL("http://foo"), "GET",
+                                 false, false));
 }
 
 // Tests that renderer-initiated navigations from a non-Instant render process
@@ -69,16 +68,13 @@
   client->RenderThreadStarted();
   SearchBouncer::GetInstance()->SetNewTabPageURL(
       GURL("http://example.com/newtab"));
-  bool unused;
   EXPECT_TRUE(client->ShouldFork(
-      GetMainFrame(), GURL("http://example.com/newtab"), "GET", false, false,
-      &unused));
+      GetMainFrame(), GURL("http://example.com/newtab"), "GET", false, false));
   EXPECT_FALSE(client->ShouldFork(GetMainFrame(),
                                   GURL("http://example.com/search?q=foo"),
-                                  "GET", false, false, &unused));
-  EXPECT_FALSE(client->ShouldFork(
-      GetMainFrame(), GURL("http://example.com/"), "GET", false, false,
-      &unused));
+                                  "GET", false, false));
+  EXPECT_FALSE(client->ShouldFork(GetMainFrame(), GURL("http://example.com/"),
+                                  "GET", false, false));
 }
 
 TEST_F(ChromeContentRendererClientSearchBoxTest, RewriteThumbnailURL) {
diff --git a/chrome/renderer/extensions/chrome_extensions_renderer_client.cc b/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
index 4c7e07b..319255e 100644
--- a/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
+++ b/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
@@ -22,6 +22,7 @@
 #include "chrome/renderer/media/cast_ipc_dispatcher.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/mime_handler_view_mode.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
 #include "extensions/common/constants.h"
@@ -272,8 +273,7 @@
 bool ChromeExtensionsRendererClient::ShouldFork(blink::WebLocalFrame* frame,
                                                 const GURL& url,
                                                 bool is_initial_navigation,
-                                                bool is_server_redirect,
-                                                bool* send_referrer) {
+                                                bool is_server_redirect) {
   const extensions::RendererExtensionRegistry* extension_registry =
       extensions::RendererExtensionRegistry::Get();
 
@@ -290,11 +290,6 @@
   if (!is_server_redirect &&
       CrossesExtensionExtents(frame, url, is_extension_url,
                               is_initial_navigation)) {
-    // Include the referrer in this case since we're going from a hosted web
-    // page. (the packaged case is handled previously by the extension
-    // navigation test)
-    *send_referrer = true;
-
     const Extension* extension =
         extension_registry->GetExtensionOrAppByURL(url);
     if (extension && extension->is_app()) {
@@ -332,6 +327,19 @@
 }
 
 // static
+bool ChromeExtensionsRendererClient::IsPluginHandledByMimeHandlerView(
+    const blink::WebElement& plugin_element,
+    const GURL& resource_url,
+    const std::string& mime_type,
+    const content::WebPluginInfo& plugin_info,
+    int32_t element_instance_id) {
+  CHECK(content::MimeHandlerViewMode::UsesCrossProcessFrame());
+  // TODO(ekaramad): Implement the renderer side logic here
+  // (https://crbug.com/659750).
+  return false;
+}
+
+// static
 blink::WebFrame* ChromeExtensionsRendererClient::FindFrame(
     blink::WebLocalFrame* relative_to_frame,
     const std::string& name) {
diff --git a/chrome/renderer/extensions/chrome_extensions_renderer_client.h b/chrome/renderer/extensions/chrome_extensions_renderer_client.h
index 019b6e2..8278bad 100644
--- a/chrome/renderer/extensions/chrome_extensions_renderer_client.h
+++ b/chrome/renderer/extensions/chrome_extensions_renderer_client.h
@@ -16,6 +16,7 @@
 class GURL;
 
 namespace blink {
+class WebElement;
 class WebFrame;
 class WebLocalFrame;
 struct WebPluginParams;
@@ -76,13 +77,18 @@
   static bool ShouldFork(blink::WebLocalFrame* frame,
                          const GURL& url,
                          bool is_initial_navigation,
-                         bool is_server_redirect,
-                         bool* send_referrer);
+                         bool is_server_redirect);
   static content::BrowserPluginDelegate* CreateBrowserPluginDelegate(
       content::RenderFrame* render_frame,
       const content::WebPluginInfo& info,
       const std::string& mime_type,
       const GURL& original_url);
+  static bool IsPluginHandledByMimeHandlerView(
+      const blink::WebElement& plugin_element,
+      const GURL& resource_url,
+      const std::string& mime_type,
+      const content::WebPluginInfo& plugin_info,
+      int32_t element_instance_id);
   static blink::WebFrame* FindFrame(blink::WebLocalFrame* relative_to_frame,
                                     const std::string& name);
 
diff --git a/chrome/service/service_process_prefs.cc b/chrome/service/service_process_prefs.cc
index 3bea199..fac44f5 100644
--- a/chrome/service/service_process_prefs.cc
+++ b/chrome/service/service_process_prefs.cc
@@ -13,8 +13,8 @@
 ServiceProcessPrefs::ServiceProcessPrefs(const base::FilePath& pref_filename,
                                          base::SequencedTaskRunner* task_runner)
     : prefs_(new JsonPrefStore(pref_filename,
-                               task_runner,
-                               std::unique_ptr<PrefFilter>())) {}
+                               std::unique_ptr<PrefFilter>(),
+                               task_runner)) {}
 
 ServiceProcessPrefs::~ServiceProcessPrefs() {}
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 546c406f..9daa8a93 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1622,6 +1622,8 @@
         "../browser/chromeos/input_method/textinput_test_helper.cc",
         "../browser/chromeos/input_method/textinput_test_helper.h",
         "../browser/chromeos/lock_screen_apps/note_taking_browsertest.cc",
+        "../browser/chromeos/login/active_directory_test_helper.cc",
+        "../browser/chromeos/login/active_directory_test_helper.h",
         "../browser/chromeos/login/auto_launched_kiosk_browsertest.cc",
         "../browser/chromeos/login/bluetooth_host_pairing_browsertest.cc",
         "../browser/chromeos/login/crash_restore_browsertest.cc",
@@ -2797,7 +2799,6 @@
     "//third_party/tlslite/",
     "//third_party/zlib/google/test/data/",
     "//tools/metrics/histograms/enums.xml",
-    "$root_out_dir/pyproto/google/",
   ]
   if (is_android || is_linux || is_win) {
     data += [
@@ -2990,6 +2991,7 @@
       "../browser/media/router/discovery/discovery_network_list_unittest.cc",
       "../browser/media/router/discovery/discovery_network_monitor_metric_observer_unittest.cc",
       "../browser/media/router/discovery/discovery_network_monitor_unittest.cc",
+      "../browser/media/unified_autoplay_config_unittest.cc",
       "../browser/media/webrtc/tab_desktop_media_list_unittest.cc",
       "../browser/media/webrtc/webrtc_event_log_manager_common_unittest.cc",
       "../browser/media/webrtc/webrtc_event_log_manager_unittest.cc",
@@ -4817,7 +4819,6 @@
       "//third_party/zlib/google/test/data/",
       "//tools/metrics/histograms/enums.xml",
       "//ui/webui/resources/js/",
-      "$root_out_dir/pyproto/google/",
       "$root_out_dir/test_case.html",
       "$root_out_dir/test_case.html.mock-http-headers",
       "$root_out_dir/test_page.css",
@@ -4987,6 +4988,8 @@
         "../browser/chromeos/input_method/textinput_test_helper.cc",
         "../browser/chromeos/input_method/textinput_test_helper.h",
         "../browser/chromeos/login/active_directory_login_browsertest.cc",
+        "../browser/chromeos/login/active_directory_test_helper.cc",
+        "../browser/chromeos/login/active_directory_test_helper.h",
         "../browser/chromeos/login/lock/screen_locker_browsertest.cc",
         "../browser/chromeos/login/lock/screen_locker_tester.cc",
         "../browser/chromeos/login/lock/screen_locker_tester.h",
@@ -5024,6 +5027,12 @@
         "//ash/wm/native_cursor_manager_ash_interactive_uitest.cc",
         "data/chromeos/service_login.html",
       ]
+      if (is_chrome_branded) {
+        sources += [
+          # The screen this test is checking exists in official build only.
+          "../browser/chromeos/login/sync_consent_interactive_ui_test.cc",
+        ]
+      }
       sources -= [
         # Use only the _chromeos version on Ash / Chrome OS.
         "base/view_event_test_platform_part_default.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/offlinepages/FakeOfflinePageBridge.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/offlinepages/FakeOfflinePageBridge.java
index 3b68f160..f130e70 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/offlinepages/FakeOfflinePageBridge.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/offlinepages/FakeOfflinePageBridge.java
@@ -17,6 +17,8 @@
 public class FakeOfflinePageBridge extends OfflinePageBridge {
     private boolean mIsOfflinePageModelLoaded;
     private final List<OfflinePageItem> mItems = new ArrayList<>();
+    private final List<SelectPageRequest> mRequests = new ArrayList<>();
+    private boolean mAnswersRequestsImmediately = true;
 
     public FakeOfflinePageBridge() {
         super(0);
@@ -35,6 +37,10 @@
         return mIsOfflinePageModelLoaded;
     }
 
+    public void setAnswersRequestsImmediately(boolean answersRequestsImmediately) {
+        mAnswersRequestsImmediately = answersRequestsImmediately;
+    }
+
     public void setItems(List<OfflinePageItem> items) {
         mItems.clear();
         mItems.addAll(items);
@@ -43,6 +49,16 @@
     @Override
     public void selectPageForOnlineUrl(
             String onlineUrl, int tabId, Callback<OfflinePageItem> callback) {
+        assert tabId == 0;
+        if (mAnswersRequestsImmediately) {
+            answerRequest(onlineUrl, callback);
+            return;
+        }
+
+        mRequests.add(new SelectPageRequest(onlineUrl, callback));
+    }
+
+    private void answerRequest(String onlineUrl, Callback<OfflinePageItem> callback) {
         OfflinePageItem result = null;
         for (OfflinePageItem item : mItems) {
             if (!item.getUrl().equals(onlineUrl)) continue;
@@ -53,7 +69,24 @@
         callback.onResult(result);
     }
 
+    public void answerAllRequests() {
+        for (SelectPageRequest request : mRequests) {
+            answerRequest(request.onlineUrl, request.callback);
+        }
+        mRequests.clear();
+    }
+
     public void fireOfflinePageModelLoaded() {
         super.offlinePageModelLoaded();
     }
+
+    private static class SelectPageRequest {
+        public final String onlineUrl;
+        public final Callback<OfflinePageItem> callback;
+
+        public SelectPageRequest(String onlineUrl, Callback<OfflinePageItem> callback) {
+            this.onlineUrl = onlineUrl;
+            this.callback = callback;
+        }
+    }
 }
diff --git a/chrome/test/chromedriver/test/run_java_tests.py b/chrome/test/chromedriver/test/run_java_tests.py
index e2285b76..778a8d9 100755
--- a/chrome/test/chromedriver/test/run_java_tests.py
+++ b/chrome/test/chromedriver/test/run_java_tests.py
@@ -210,8 +210,6 @@
 
   ant_file = open(os.path.join(java_tests_src_dir, 'build.xml'), 'w')
   file_contents = _CreateBuildConfig(java_tests_src_dir, jvm_args, sys_props)
-  if util.IsMac():
-    print file_contents
   ant_file.write(file_contents)
   ant_file.close()
 
@@ -351,8 +349,10 @@
     return PrintTestResults(results)
   finally:
     environment.GlobalTearDown()
-    os.remove(os.path.join(java_tests_src_dir, "build.xml"))
-    os.remove(os.path.join(java_tests_src_dir, "results.xml"))
+    if(os.path.exists(os.path.join(java_tests_src_dir, "build.xml"))):
+      os.remove(os.path.join(java_tests_src_dir, "build.xml"))
+    if(os.path.exists(os.path.join(java_tests_src_dir, "results.xml"))):
+      os.remove(os.path.join(java_tests_src_dir, "results.xml"))
     if(os.path.exists(os.path.join(java_tests_src_dir, "chrome-wrapper-no-sandbox"))):
       os.remove(os.path.join(java_tests_src_dir, "chrome-wrapper-no-sandbox"))
     if(os.path.exists(os.path.join(java_tests_src_dir, "chrome-wrapper"))):
diff --git a/chrome/test/data/extensions/api_test/arc_app_launcher/install_event/manifest.json b/chrome/test/data/extensions/api_test/arc_app_launcher/install_event/manifest.json
new file mode 100644
index 0000000..c27bfdb
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/arc_app_launcher/install_event/manifest.json
@@ -0,0 +1,12 @@
+{
+  "key": "MIGqAgEAAiEAuTqZKXReYjq0LqmxcPXj5BhO4l43YRxiPm1A+Y6IqG8CAwEAAQIhAIwbSucUYqAij1AMg29STwFbL08USDm7SxcNgsW7aJzhAhEA6cjXcL5MFxl2geM2ZowcTQIRAMrUkXe2RyL2wuBDnV0VRasCEAkABWM+wDknbsuDTsXV4QUCEA5o66zFlmg1f8LPCu8CA+ECEC2UbOIhswH8ZhEictgqd5k=",
+  "name": "Install event test app",
+  "version": "1",
+  "manifest_version": 2,
+  "permissions": ["arcAppsPrivate"],
+  "app": {
+    "background": {
+      "scripts": ["test.js"]
+    }
+  }
+}
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/arc_app_launcher/install_event/test.js b/chrome/test/data/extensions/api_test/arc_app_launcher/install_event/test.js
new file mode 100644
index 0000000..31c8d6c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/arc_app_launcher/install_event/test.js
@@ -0,0 +1,23 @@
+// 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.
+
+var expectedPackageName = null;
+
+chrome.test.runTests([
+  function getConfig() {
+    chrome.test.getConfig(chrome.test.callbackPass(config => {
+      expectedPackageName = config.customArg;
+    }));
+  },
+
+  function onInstalled() {
+    chrome.test.assertTrue(!!expectedPackageName);
+    chrome.test.listenOnce(chrome.arcAppsPrivate.onInstalled, appInfo => {
+      chrome.test.assertEq({packageName: expectedPackageName}, appInfo);
+      chrome.arcAppsPrivate.launchApp(
+          appInfo.packageName, chrome.test.callbackPass());
+    });
+    chrome.test.sendMessage('ready');
+  }
+]);
diff --git a/chrome/test/data/extensions/api_test/arc_app_launcher/manifest.json b/chrome/test/data/extensions/api_test/arc_app_launcher/launch_app/manifest.json
similarity index 100%
rename from chrome/test/data/extensions/api_test/arc_app_launcher/manifest.json
rename to chrome/test/data/extensions/api_test/arc_app_launcher/launch_app/manifest.json
diff --git a/chrome/test/data/extensions/api_test/arc_app_launcher/launch_app/test.js b/chrome/test/data/extensions/api_test/arc_app_launcher/launch_app/test.js
new file mode 100644
index 0000000..02f413d4
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/arc_app_launcher/launch_app/test.js
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  var expectedPackageName = null;
+
+  chrome.test.runTests([
+    function getConfig() {
+      chrome.test.getConfig(chrome.test.callbackPass(config => {
+        expectedPackageName = config.customArg;
+      }));
+    },
+
+    function getPackageNameAndLaunchApp() {
+      chrome.arcAppsPrivate.launchApp(
+          'invalid package name', chrome.test.callbackFail('App not found'));
+      chrome.test.assertTrue(!!expectedPackageName);
+      chrome.arcAppsPrivate.getLaunchableApps(
+          chrome.test.callbackPass(appsInfo => {
+            chrome.test.assertEq(
+                [{packageName: expectedPackageName}], appsInfo);
+            chrome.arcAppsPrivate.launchApp(
+                appsInfo[0].packageName, chrome.test.callbackPass());
+          }));
+    }
+  ]);
+});
diff --git a/chrome/test/data/extensions/api_test/arc_app_launcher/test.js b/chrome/test/data/extensions/api_test/arc_app_launcher/test.js
deleted file mode 100644
index 6a21a73f..0000000
--- a/chrome/test/data/extensions/api_test/arc_app_launcher/test.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-chrome.app.runtime.onLaunched.addListener(function() {
-  var EXPECTED_APP_ID = null;
-
-  chrome.test.runTests([
-    function getConfig() {
-      chrome.test.getConfig(chrome.test.callbackPass(config => {
-        EXPECTED_APP_ID = config.customArg;
-      }));
-    },
-
-    function getAppIdAndLaunchApp() {
-      chrome.arcAppsPrivate.launchApp(
-          'invalid app id', chrome.test.callbackFail('Launch failed'));
-      chrome.test.assertTrue(!!EXPECTED_APP_ID);
-      chrome.arcAppsPrivate.getLaunchableApps(
-          chrome.test.callbackPass(appsInfo => {
-            chrome.test.assertEq([{id: EXPECTED_APP_ID}], appsInfo);
-            chrome.arcAppsPrivate.launchApp(
-                appsInfo[0].id, chrome.test.callbackPass());
-          }));
-    }
-  ]);
-});
\ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/preference/standard/test.js b/chrome/test/data/extensions/api_test/preference/standard/test.js
index b7678651..dc1a114 100644
--- a/chrome/test/data/extensions/api_test/preference/standard/test.js
+++ b/chrome/test/data/extensions/api_test/preference/standard/test.js
@@ -33,6 +33,8 @@
     preferences: {
       alternateErrorPagesEnabled: false,
       autofillEnabled: false,
+      autofillAddressEnabled: false,
+      autofillCreditCardEnabled: false,
       passwordSavingEnabled: false,
       safeBrowsingEnabled: false,
       safeBrowsingExtendedReportingEnabled: false,
diff --git a/chrome/test/data/nosniff.empty b/chrome/test/data/nosniff.empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/test/data/nosniff.empty
diff --git a/chrome/test/data/nosniff.empty.mock-http-headers b/chrome/test/data/nosniff.empty.mock-http-headers
new file mode 100644
index 0000000..5866f62
--- /dev/null
+++ b/chrome/test/data/nosniff.empty.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Content-Length: 0
+Content-Type: text/xml; charset=utf-8
+X-Content-Type-Options: nosniff
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index d101d6cc..28bff0d 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -92,7 +92,8 @@
   this.runMochaTest(extension_sidebar_tests.TestNames.LayoutAndClickHandlers);
 });
 
-TEST_F('CrExtensionsSidebarTest', 'SetSelected', function() {
+// Flaky, see crbug.com/871541.
+TEST_F('CrExtensionsSidebarTest', 'DISABLED_SetSelected', function() {
   this.runMochaTest(extension_sidebar_tests.TestNames.SetSelected);
 });
 
@@ -346,9 +347,11 @@
   this.runMochaTest(extension_manager_tests.TestNames.Uninstall);
 });
 
-TEST_F('CrExtensionsManagerUnitTest', 'UninstallFromDetails', function() {
-  this.runMochaTest(extension_manager_tests.TestNames.UninstallFromDetails);
-});
+// Flaky, see crbug.com/871539.
+TEST_F(
+    'CrExtensionsManagerUnitTest', 'DISABLED_UninstallFromDetails', function() {
+      this.runMochaTest(extension_manager_tests.TestNames.UninstallFromDetails);
+    });
 
 TEST_F('CrExtensionsManagerUnitTest', 'ToggleIncognito', function() {
   this.runMochaTest(extension_manager_tests.TestNames.ToggleIncognitoMode);
@@ -651,10 +654,13 @@
   this.runMochaTest(extension_navigation_helper_tests.TestNames.Conversions);
 });
 
-TEST_F('CrExtensionsNavigationHelperTest', 'PushAndReplaceState', function() {
-  this.runMochaTest(
-      extension_navigation_helper_tests.TestNames.PushAndReplaceState);
-});
+// Flaky, see crbug.com/871540.
+TEST_F(
+    'CrExtensionsNavigationHelperTest', 'DISABLED_PushAndReplaceState',
+    function() {
+      this.runMochaTest(
+          extension_navigation_helper_tests.TestNames.PushAndReplaceState);
+    });
 
 TEST_F('CrExtensionsNavigationHelperTest', 'SupportedRoutes', function() {
   this.runMochaTest(
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 97cd45da6..06e274ce 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -499,7 +499,8 @@
   ]),
 };
 
-TEST_F('CrSettingsPeoplePageTest', 'All', function() {
+// Flaky, see crbug.com/871545.
+TEST_F('CrSettingsPeoplePageTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -582,7 +583,8 @@
   ]),
 };
 
-TEST_F('CrSettingsResetPageTest', 'All', function() {
+// Flaky, see crbug.com/871620.
+TEST_F('CrSettingsResetPageTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -1010,7 +1012,8 @@
   ]),
 };
 
-TEST_F('CrSettingsCategorySettingExceptionsTest', 'All', function() {
+// Flaky, see https://crbug.com/872026.
+TEST_F('CrSettingsCategorySettingExceptionsTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -1036,7 +1039,8 @@
   ]),
 };
 
-TEST_F('CrSettingsSiteEntryTest', 'All', function() {
+// Flaky, see https://crbug.com/872027.
+TEST_F('CrSettingsSiteEntryTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -1097,7 +1101,8 @@
 GEN('#define MAYBE_All All');
 GEN('#endif');
 
-TEST_F('CrSettingsSiteDetailsTest', 'MAYBE_All', function() {
+// Flaky, see crbug.com/871548.
+TEST_F('CrSettingsSiteDetailsTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -1157,7 +1162,8 @@
   mocha.grep('EditExceptionDialog').run();
 });
 
-TEST_F('CrSettingsSiteListTest', 'AddExceptionDialog', function() {
+// Flaky, see https://crbug.com/872028.
+TEST_F('CrSettingsSiteListTest', 'DISABLED_AddExceptionDialog', function() {
   mocha.grep('AddExceptionDialog').run();
 });
 
@@ -1510,7 +1516,8 @@
   ]),
 };
 
-TEST_F('CrSettingsEditDictionaryPageTest', 'All', function() {
+// Flaky, see crbug.com/871543.
+TEST_F('CrSettingsEditDictionaryPageTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -1542,8 +1549,8 @@
   ]),
 };
 
-// Flaky on Win and Linux, see http://crbug/692356.
-TEST_F('CrSettingsLanguagesTest', 'All', function() {
+// Flaky, see http://crbug/871666.
+TEST_F('CrSettingsLanguagesTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
@@ -1584,7 +1591,8 @@
   mocha.grep(assert(languages_page_tests.TestNames.InputMethods)).run();
 });
 
-TEST_F('CrSettingsLanguagesPageTest', 'Spellcheck', function() {
+// Flaky, see crbug.com/871544.
+TEST_F('CrSettingsLanguagesPageTest', 'DISABLED_Spellcheck', function() {
   mocha.grep(assert(languages_page_tests.TestNames.Spellcheck)).run();
 });
 
@@ -1605,7 +1613,8 @@
   ]),
 };
 
-TEST_F('CrSettingsRouteTest', 'All', function() {
+// Flaky, see crbug.com/871547.
+TEST_F('CrSettingsRouteTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
diff --git a/chrome/test/data/webui/settings/find_shortcut_behavior_test.js b/chrome/test/data/webui/settings/find_shortcut_behavior_test.js
index bd2ba29..d88b868 100644
--- a/chrome/test/data/webui/settings/find_shortcut_behavior_test.js
+++ b/chrome/test/data/webui/settings/find_shortcut_behavior_test.js
@@ -25,6 +25,9 @@
       fns.reduce((acc, fn) => acc.then(fn), Promise.resolve());
 
   /**
+   * This method registers the |testElement| as a find shortcut listener, runs
+   * the |wrapped| function, then removes |testElement| from being a listener.
+   * The listeners stack is global and should be empty after a successful test.
    * @param {!HTMLElement} testElement
    * @return {!function(!Function)): !Promise}
    */
@@ -35,6 +38,9 @@
   ]);
 
   /**
+   * Checks that the handleFindShortcut method is being called for all the
+   * |expectedSelves| element references in the order that they are passed in
+   * when a single find shortcut is invoked.
    * @param {!Array<!HTMLElement>} expectedSelves
    * @param {?boolean} expectedModalContextOpen
    * @return {!Promise}
@@ -53,6 +59,8 @@
   };
 
   /**
+   * Checks that the handleFindShortcut method is being called for the
+   * element reference |expectedSelf| when a find shortcut is invoked.
    * @param {!HTMLElement} expectedSelf
    * @param {?boolean} expectedModalContextOpen
    * @return {!Promise}
@@ -61,6 +69,8 @@
       checkMultiple([expectedSelf], expectedModalContextOpen);
 
   /**
+   * Register |expectedSelf| element as a listener, check that
+   * handleFindShortcut is called, then remove as a listener.
    * @param {!HTMLElement} expectedSelf
    * @param {?boolean} expectedModalContextOpen
    * @return {!Promise}
@@ -68,6 +78,23 @@
   const wrappedCheck = (expectedSelf, expectedModalContextOpen) => listenScope(
       expectedSelf)(() => check(expectedSelf, expectedModalContextOpen));
 
+  /**
+   * Registers for a keydown event to check whether the bubbled up event has
+   * defaultPrevented set to true, in which case the event was handled.
+   * @param {boolean} defaultPrevented
+   * @return {!Promise}
+   */
+  const listenOnceAndCheckDefaultPrevented = defaultPrevented => {
+    const resolver = new PromiseResolver();
+    const handler = e => {
+      window.removeEventListener('keydown', handler);
+      if (e.defaultPrevented == defaultPrevented)
+        resolver.resolve();
+    };
+    window.addEventListener('keydown', handler);
+    return resolver.promise;
+  };
+
   suiteSetup(() => {
     document.body.innerHTML = `
         <dom-module id="find-shortcut-element">
@@ -93,8 +120,6 @@
     PolymerTest.clearBody();
   });
 
-  test('no listeners are okay', () => checkMultiple([]));
-
   test('handled', () => {
     document.body.innerHTML = `<find-shortcut-element></find-shortcut-element>`;
     const testElement = document.body.querySelector('find-shortcut-element');
@@ -149,4 +174,28 @@
       assertThrows(() => testElement.becomeActiveFindShortcutListener());
     });
   });
+
+  test('cmd+ctrl+f bubbles up (defaultPrevented=false)', () => {
+    const bubbledUp = listenOnceAndCheckDefaultPrevented(false);
+    document.body.innerHTML = `<find-shortcut-element></find-shortcut-element>`;
+    const testElement = document.body.querySelector('find-shortcut-element');
+    return listenScope(testElement)(() => {
+      MockInteractions.pressAndReleaseKeyOn(window, 70, ['meta', 'ctrl'], 'f');
+      return bubbledUp;
+    });
+  });
+
+  test('find shortcut bubbles up (defaultPrevented=true)', () => {
+    const bubbledUp = listenOnceAndCheckDefaultPrevented(true);
+    document.body.innerHTML = `<find-shortcut-element></find-shortcut-element>`;
+    const testElement = document.body.querySelector('find-shortcut-element');
+    return Promise.all([wrappedCheck(testElement), bubbledUp]);
+  });
+
+  test('shortcut with no listeners bubbles up (defaultPrevented=false)', () => {
+    const bubbledUp = listenOnceAndCheckDefaultPrevented(false);
+    MockInteractions.pressAndReleaseKeyOn(
+        window, 70, cr.isMac ? 'meta' : 'ctrl', 'f');
+    return bubbledUp;
+  });
 });
diff --git a/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc b/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc
index 25eb6af..64f64e6 100644
--- a/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -51,9 +51,6 @@
 }  // namespace cast
 }  // namespace extensions
 
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(
-    extensions::cast::AutomationWebContentsObserver);
-
 namespace extensions {
 namespace cast {
 
diff --git a/chromecast/browser/extensions/cast_extension_web_contents_observer.cc b/chromecast/browser/extensions/cast_extension_web_contents_observer.cc
index 55ba563..b351c71b8 100644
--- a/chromecast/browser/extensions/cast_extension_web_contents_observer.cc
+++ b/chromecast/browser/extensions/cast_extension_web_contents_observer.cc
@@ -4,8 +4,6 @@
 
 #include "chromecast/browser/extensions/cast_extension_web_contents_observer.h"
 
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::CastExtensionWebContentsObserver);
-
 namespace extensions {
 
 CastExtensionWebContentsObserver::CastExtensionWebContentsObserver(
diff --git a/chromeos/components/drivefs/BUILD.gn b/chromeos/components/drivefs/BUILD.gn
index 2892b24..9dee7c2 100644
--- a/chromeos/components/drivefs/BUILD.gn
+++ b/chromeos/components/drivefs/BUILD.gn
@@ -27,6 +27,7 @@
     "//mojo/public/cpp/platform",
     "//net",
     "//services/identity/public/mojom",
+    "//services/network/public/cpp:cpp",
     "//services/service_manager/public/cpp",
   ]
   defines = [ "IS_DRIVEFS_IMPL" ]
@@ -63,6 +64,7 @@
     "//mojo/public/cpp/bindings",
     "//net",
     "//services/identity/public/mojom",
+    "//services/network/public/cpp:cpp",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp/test:test_support",
     "//testing/gmock",
diff --git a/chromeos/components/drivefs/drivefs_host.cc b/chromeos/components/drivefs/drivefs_host.cc
index 3678191..1b86e48c 100644
--- a/chromeos/components/drivefs/drivefs_host.cc
+++ b/chromeos/components/drivefs/drivefs_host.cc
@@ -14,6 +14,7 @@
 #include "mojo/public/cpp/platform/platform_channel_endpoint.h"
 #include "mojo/public/cpp/system/invitation.h"
 #include "services/identity/public/mojom/constants.mojom.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace drivefs {
@@ -262,7 +263,7 @@
       OnMintTokenFailure(error);
       return;
     }
-    mint_token_flow_->Start(host_->delegate_->GetRequestContext(),
+    mint_token_flow_->Start(host_->delegate_->GetURLLoaderFactory(),
                             *access_token);
   }
 
diff --git a/chromeos/components/drivefs/drivefs_host.h b/chromeos/components/drivefs/drivefs_host.h
index 98af5aaa..7ceea71 100644
--- a/chromeos/components/drivefs/drivefs_host.h
+++ b/chromeos/components/drivefs/drivefs_host.h
@@ -20,9 +20,9 @@
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
 #include "services/identity/public/mojom/identity_manager.mojom.h"
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
 
 namespace service_manager {
 class Connector;
@@ -57,7 +57,8 @@
     Delegate() = default;
     virtual ~Delegate() = default;
 
-    virtual net::URLRequestContextGetter* GetRequestContext() = 0;
+    virtual scoped_refptr<network::SharedURLLoaderFactory>
+    GetURLLoaderFactory() = 0;
     virtual service_manager::Connector* GetConnector() = 0;
     virtual const AccountId& GetAccountId() = 0;
     virtual std::string GetObfuscatedAccountId() = 0;
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc
index 0cb3b28d..ac2ce017 100644
--- a/chromeos/components/drivefs/drivefs_host_unittest.cc
+++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -19,6 +19,7 @@
 #include "chromeos/disks/mock_disk_mount_manager.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/service.h"
@@ -94,9 +95,9 @@
                                 MockOAuth2MintTokenFlow* mock)
       : OAuth2MintTokenFlow(delegate, {}), delegate_(delegate), mock_(mock) {}
 
-  void Start(net::URLRequestContextGetter* context_getter,
+  void Start(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
              const std::string& access_token) override {
-    EXPECT_EQ(nullptr, context_getter);
+    EXPECT_EQ(nullptr, url_loader_factory);
     mock_->Start(delegate_, access_token);
   }
 
@@ -125,7 +126,10 @@
 
  private:
   // DriveFsHost::Delegate:
-  net::URLRequestContextGetter* GetRequestContext() override { return nullptr; }
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
+      override {
+    return nullptr;
+  }
   service_manager::Connector* GetConnector() override {
     return connector_.get();
   }
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc
index 01e74258..cb30136 100644
--- a/chromeos/dbus/cros_disks_client.cc
+++ b/chromeos/dbus/cros_disks_client.cc
@@ -459,6 +459,7 @@
       is_read_only_(false),
       is_hidden_(true),
       is_virtual_(false),
+      is_auto_mountable_(false),
       device_type_(DEVICE_TYPE_UNKNOWN),
       total_size_in_bytes_(0) {
   InitializeFromResponse(response);
@@ -589,6 +590,8 @@
       cros_disks::kDeviceIsOnRemovableDevice, &on_removable_device_);
   properties->GetBooleanWithoutPathExpansion(cros_disks::kDeviceIsVirtual,
                                              &is_virtual_);
+  properties->GetBooleanWithoutPathExpansion(cros_disks::kIsAutoMountable,
+                                             &is_auto_mountable_);
   properties->GetStringWithoutPathExpansion(
       cros_disks::kNativePath, &system_path_);
   properties->GetStringWithoutPathExpansion(
diff --git a/chromeos/dbus/cros_disks_client.h b/chromeos/dbus/cros_disks_client.h
index c77a8d6..3e0e85c6 100644
--- a/chromeos/dbus/cros_disks_client.h
+++ b/chromeos/dbus/cros_disks_client.h
@@ -173,6 +173,9 @@
   // Is the disk virtual.
   bool is_virtual() const { return is_virtual_; }
 
+  // Is the disk auto-mountable.
+  bool is_auto_mountable() const { return is_auto_mountable_; }
+
   // Disk file path (e.g. /dev/sdb).
   const std::string& file_path() const { return file_path_; }
 
@@ -219,6 +222,7 @@
   bool is_read_only_;
   bool is_hidden_;
   bool is_virtual_;
+  bool is_auto_mountable_;
 
   std::string file_path_;
   std::string label_;
diff --git a/chromeos/dbus/cros_disks_client_unittest.cc b/chromeos/dbus/cros_disks_client_unittest.cc
index a8a6820d..799d94e 100644
--- a/chromeos/dbus/cros_disks_client_unittest.cc
+++ b/chromeos/dbus/cros_disks_client_unittest.cc
@@ -63,6 +63,7 @@
   const std::string kVendorId = "0000";
   const std::string kVendorName = "Vendor Name";
   const std::string kFileSystemType = "exfat";
+  const bool kIsAutoMountable = true;
 
   // Construct a fake response of GetDeviceProperties().
   std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
@@ -84,6 +85,8 @@
                         kDeviceIsOnRemovableDevice);
     AppendBoolDictEntry(&array_writer, cros_disks::kDeviceIsReadOnly,
                         kDeviceIsReadOnly);
+    AppendBoolDictEntry(&array_writer, cros_disks::kIsAutoMountable,
+                        kIsAutoMountable);
     {
       dbus::MessageWriter entry_writer(NULL);
       array_writer.OpenDictEntry(&entry_writer);
@@ -157,6 +160,7 @@
   EXPECT_EQ(DEVICE_TYPE_SD, result.device_type());
   EXPECT_EQ(kMountPath, result.mount_path());
   EXPECT_EQ(kFileSystemType, result.file_system_type());
+  EXPECT_EQ(kIsAutoMountable, result.is_auto_mountable());
 }
 
 TEST(CrosDisksClientTest, ComposeMountOptions) {
diff --git a/chromeos/dbus/fake_auth_policy_client.cc b/chromeos/dbus/fake_auth_policy_client.cc
index 8b8bfeb..859e720 100644
--- a/chromeos/dbus/fake_auth_policy_client.cc
+++ b/chromeos/dbus/fake_auth_policy_client.cc
@@ -59,29 +59,6 @@
       std::make_unique<dbus::Signal>(interface_name, method_name).get());
 }
 
-void StoreDevicePolicy(
-    const em::ChromeDeviceSettingsProto& device_policy,
-    const std::string& machine_name,
-    const std::string& dm_token,
-    chromeos::AuthPolicyClient::RefreshPolicyCallback callback) {
-  std::string payload;
-  CHECK(device_policy.SerializeToString(&payload));
-
-  em::PolicyFetchResponse response;
-  em::PolicyData policy_data;
-  policy_data.set_policy_type("google/chromeos/device");
-  policy_data.set_device_id(machine_name);
-  policy_data.set_request_token(dm_token);
-  policy_data.set_policy_value(payload);
-  policy_data.set_timestamp(base::Time::Now().ToJavaTime());
-  response.set_policy_data(policy_data.SerializeAsString());
-  chromeos::SessionManagerClient* session_manager_client =
-      chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
-  session_manager_client->StoreDevicePolicy(
-      response.SerializeAsString(),
-      base::BindOnce(&OnStorePolicy, std::move(callback)));
-}
-
 }  // namespace
 
 namespace chromeos {
@@ -210,17 +187,16 @@
   SessionManagerClient* session_manager_client =
       DBusThreadManager::Get()->GetSessionManagerClient();
 
+  // On first refresh, we need to restore |machine_name| and |dm_token| from
+  // the stored policy.
   if (machine_name_.empty() || dm_token_.empty()) {
-    // We need to set a new timestamp below. So we fetch the policy to get the
-    // machine name and dm_token. So we could set it as well.
     session_manager_client->RetrieveDevicePolicy(
         base::BindOnce(&FakeAuthPolicyClient::OnDevicePolicyRetrieved,
                        weak_factory_.GetWeakPtr(), std::move(callback)));
     return;
   }
 
-  StoreDevicePolicy(device_policy_, machine_name_, dm_token_,
-                    std::move(callback));
+  StoreDevicePolicy(std::move(callback));
 }
 
 void FakeAuthPolicyClient::RefreshUserPolicy(const AccountId& account_id,
@@ -239,14 +215,18 @@
   std::string payload;
   CHECK(policy.SerializeToString(&payload));
 
-  em::PolicyFetchResponse response;
   em::PolicyData policy_data;
   policy_data.set_policy_type("google/chromeos/user");
   policy_data.set_username(account_id.GetUserEmail());
   policy_data.set_device_id(account_id.GetObjGuid());
   policy_data.set_timestamp(base::Time::Now().ToJavaTime());
   policy_data.set_policy_value(payload);
+  for (const auto& id : user_affiliation_ids_)
+    policy_data.add_user_affiliation_ids(id);
+
+  em::PolicyFetchResponse response;
   response.set_policy_data(policy_data.SerializeAsString());
+
   session_manager_client->StorePolicyForUser(
       cryptohome::CreateAccountIdentifierFromAccountId(account_id),
       response.SerializeAsString(),
@@ -310,16 +290,42 @@
     std::move(callback).Run(authpolicy::ERROR_DBUS_FAILURE);
     return;
   }
+
   em::PolicyFetchResponse response;
   response.ParseFromString(protobuf);
+
   em::PolicyData policy_data;
   policy_data.ParseFromString(response.policy_data());
+
   if (policy_data.has_device_id())
     machine_name_ = policy_data.device_id();
   if (policy_data.has_request_token())
     dm_token_ = policy_data.request_token();
-  StoreDevicePolicy(device_policy_, machine_name_, dm_token_,
-                    std::move(callback));
+
+  StoreDevicePolicy(std::move(callback));
+}
+
+void FakeAuthPolicyClient::StoreDevicePolicy(RefreshPolicyCallback callback) {
+  std::string payload;
+  CHECK(device_policy_.SerializeToString(&payload));
+
+  em::PolicyData policy_data;
+  policy_data.set_policy_type("google/chromeos/device");
+  policy_data.set_device_id(machine_name_);
+  policy_data.set_request_token(dm_token_);
+  policy_data.set_policy_value(payload);
+  policy_data.set_timestamp(base::Time::Now().ToJavaTime());
+  for (const auto& id : device_affiliation_ids_)
+    policy_data.add_device_affiliation_ids(id);
+
+  em::PolicyFetchResponse response;
+  response.set_policy_data(policy_data.SerializeAsString());
+
+  chromeos::SessionManagerClient* session_manager_client =
+      chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
+  session_manager_client->StoreDevicePolicy(
+      response.SerializeAsString(),
+      base::BindOnce(&OnStorePolicy, std::move(callback)));
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_auth_policy_client.h b/chromeos/dbus/fake_auth_policy_client.h
index 3fc6c32..c357f4b 100644
--- a/chromeos/dbus/fake_auth_policy_client.h
+++ b/chromeos/dbus/fake_auth_policy_client.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_DBUS_FAKE_AUTH_POLICY_CLIENT_H_
 #define CHROMEOS_DBUS_FAKE_AUTH_POLICY_CLIENT_H_
 
+#include <set>
 #include <string>
 #include <utility>
 
@@ -114,6 +115,14 @@
     device_policy_ = device_policy;
   }
 
+  void set_user_affiliation_ids(std::set<std::string> ids) {
+    user_affiliation_ids_ = std::move(ids);
+  }
+
+  void set_device_affiliation_ids(std::set<std::string> ids) {
+    device_affiliation_ids_ = std::move(ids);
+  }
+
   void DisableOperationDelayForTesting() {
     dbus_operation_delay_ = disk_operation_delay_ =
         base::TimeDelta::FromSeconds(0);
@@ -127,6 +136,9 @@
       RefreshPolicyCallback callback,
       SessionManagerClient::RetrievePolicyResponseType response_type,
       const std::string& protobuf);
+
+  void StoreDevicePolicy(RefreshPolicyCallback callback);
+
   bool started_ = false;
   // If valid called after GetUserStatusCallback is called.
   base::OnceClosure on_get_status_closure_;
@@ -136,15 +148,22 @@
   std::string dm_token_;
   std::string user_kerberos_creds_;
   std::string user_kerberos_conf_;
+
+  std::set<std::string> user_affiliation_ids_;
+  std::set<std::string> device_affiliation_ids_;
+
   dbus::ObjectProxy::SignalCallback user_kerberos_files_changed_callback_;
+
   authpolicy::ActiveDirectoryUserStatus::PasswordStatus password_status_ =
       authpolicy::ActiveDirectoryUserStatus::PASSWORD_VALID;
   authpolicy::ActiveDirectoryUserStatus::TgtStatus tgt_status_ =
       authpolicy::ActiveDirectoryUserStatus::TGT_VALID;
+
   // Delay operations to be more realistic.
   base::TimeDelta dbus_operation_delay_ = base::TimeDelta::FromSeconds(3);
   base::TimeDelta disk_operation_delay_ =
       base::TimeDelta::FromMilliseconds(100);
+
   enterprise_management::ChromeDeviceSettingsProto device_policy_;
 
   std::vector<WaitForServiceToBeAvailableCallback>
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc
index ff426bb..62cc34e 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/fake_session_manager_client.cc
@@ -210,15 +210,6 @@
       from_here, base::BindOnce(std::move(callback), std::move(response)));
 }
 
-// Posts a task to call callback(response, policy).
-void PostReplyWithPolicy(const base::Location& from_here,
-                         RetrievePolicyCallback callback,
-                         RetrievePolicyResponseType response,
-                         const std::string& policy) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      from_here, base::BindOnce(std::move(callback), response, policy));
-}
-
 }  // namespace
 
 FakeSessionManagerClient::FakeSessionManagerClient()
@@ -387,9 +378,10 @@
         base::BindOnce(std::move(callback),
                        RetrievePolicyResponseType::SUCCESS));
   } else {
-    PostReplyWithPolicy(FROM_HERE, std::move(callback),
-                        RetrievePolicyResponseType::SUCCESS,
-                        policy_[GetMemoryStorageKey(descriptor)]);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback), RetrievePolicyResponseType::SUCCESS,
+                       policy_[GetMemoryStorageKey(descriptor)]));
   }
 }
 
diff --git a/chromeos/disks/disk.cc b/chromeos/disks/disk.cc
index 3ba6a39..3837be11 100644
--- a/chromeos/disks/disk.cc
+++ b/chromeos/disks/disk.cc
@@ -4,6 +4,10 @@
 
 #include "chromeos/disks/disk.h"
 
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+
 namespace chromeos {
 namespace disks {
 
@@ -36,55 +40,11 @@
       on_boot_device_(disk_info.on_boot_device()),
       on_removable_device_(disk_info.on_removable_device()),
       is_hidden_(disk_info.is_hidden()),
+      is_auto_mountable_(disk_info.is_auto_mountable()),
       file_system_type_(disk_info.file_system_type()),
       base_mount_path_(base_mount_path) {}
 
-Disk::Disk(const std::string& device_path,
-           const std::string& mount_path,
-           bool write_disabled_by_policy,
-           const std::string& system_path,
-           const std::string& file_path,
-           const std::string& device_label,
-           const std::string& drive_label,
-           const std::string& vendor_id,
-           const std::string& vendor_name,
-           const std::string& product_id,
-           const std::string& product_name,
-           const std::string& fs_uuid,
-           const std::string& system_path_prefix,
-           DeviceType device_type,
-           uint64_t total_size_in_bytes,
-           bool is_parent,
-           bool is_read_only_hardware,
-           bool has_media,
-           bool on_boot_device,
-           bool on_removable_device,
-           bool is_hidden,
-           const std::string& file_system_type,
-           const std::string& base_mount_path)
-    : device_path_(device_path),
-      mount_path_(mount_path),
-      write_disabled_by_policy_(write_disabled_by_policy),
-      system_path_(system_path),
-      file_path_(file_path),
-      device_label_(device_label),
-      drive_label_(drive_label),
-      vendor_id_(vendor_id),
-      vendor_name_(vendor_name),
-      product_id_(product_id),
-      product_name_(product_name),
-      fs_uuid_(fs_uuid),
-      system_path_prefix_(system_path_prefix),
-      device_type_(device_type),
-      total_size_in_bytes_(total_size_in_bytes),
-      is_parent_(is_parent),
-      is_read_only_hardware_(is_read_only_hardware),
-      has_media_(has_media),
-      on_boot_device_(on_boot_device),
-      on_removable_device_(on_removable_device),
-      is_hidden_(is_hidden),
-      file_system_type_(file_system_type),
-      base_mount_path_(base_mount_path) {}
+Disk::Disk() = default;
 
 Disk::Disk(const Disk&) = default;
 
@@ -97,18 +57,133 @@
     base_mount_path_ = mount_path;
 }
 
-bool Disk::IsAutoMountable() const {
-  // Disks are considered auto-mountable if they are:
-  // 1. Non-virtual
-  // 2. Not on boot device
-  // Only the second condition is checked here, because Disks are created from
-  // non-virtual mount devices only.
-  return !on_boot_device_;
-}
-
 bool Disk::IsStatefulPartition() const {
   return mount_path_ == kStatefulPartition;
 }
 
+Disk::Builder::Builder() : disk_(base::WrapUnique(new Disk())) {}
+
+Disk::Builder::~Builder() = default;
+
+Disk::Builder& Disk::Builder::SetDevicePath(const std::string& device_path) {
+  disk_->device_path_ = device_path;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetMountPath(const std::string& mount_path) {
+  disk_->mount_path_ = mount_path;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetWriteDisabledByPolicy(
+    bool write_disabled_by_policy) {
+  disk_->write_disabled_by_policy_ = write_disabled_by_policy;
+  return *this;
+}
+Disk::Builder& Disk::Builder::SetSystemPath(const std::string& system_path) {
+  disk_->system_path_ = system_path;
+  return *this;
+}
+Disk::Builder& Disk::Builder::SetFilePath(const std::string& file_path) {
+  disk_->file_path_ = file_path;
+  return *this;
+}
+Disk::Builder& Disk::Builder::SetDeviceLabel(const std::string& device_label) {
+  disk_->device_label_ = device_label;
+  return *this;
+}
+Disk::Builder& Disk::Builder::SetDriveLabel(const std::string& drive_label) {
+  disk_->drive_label_ = drive_label;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetVendorId(const std::string& vendor_id) {
+  disk_->vendor_id_ = vendor_id;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetVendorName(const std::string& vendor_name) {
+  disk_->vendor_name_ = vendor_name;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetProductId(const std::string& product_id) {
+  disk_->product_id_ = product_id;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetProductName(const std::string& product_name) {
+  disk_->product_name_ = product_name;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetFileSystemUUID(const std::string& fs_uuid) {
+  disk_->fs_uuid_ = fs_uuid;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetSystemPathPrefix(
+    const std::string& system_path_prefix) {
+  disk_->system_path_prefix_ = system_path_prefix;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetDeviceType(DeviceType device_type) {
+  disk_->device_type_ = device_type;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetSizeInBytes(uint64_t total_size_in_bytes) {
+  disk_->total_size_in_bytes_ = total_size_in_bytes;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetIsParent(bool is_parent) {
+  disk_->is_parent_ = is_parent;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetIsReadOnlyHardware(
+    bool is_read_only_hardware) {
+  disk_->is_read_only_hardware_ = is_read_only_hardware;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetHasMedia(bool has_media) {
+  disk_->has_media_ = has_media;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetOnBootDevice(bool on_boot_device) {
+  disk_->on_boot_device_ = on_boot_device;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetOnRemovableDevice(bool on_removable_device) {
+  disk_->on_removable_device_ = on_removable_device;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetIsHidden(bool is_hidden) {
+  disk_->is_hidden_ = is_hidden;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetFileSystemType(
+    const std::string& file_system_type) {
+  disk_->file_system_type_ = file_system_type;
+  return *this;
+}
+
+Disk::Builder& Disk::Builder::SetBaseMountPath(
+    const std::string& base_mount_path) {
+  disk_->base_mount_path_ = base_mount_path;
+  return *this;
+}
+
+std::unique_ptr<Disk> Disk::Builder::Build() {
+  return std::move(disk_);
+}
+
 }  // namespace disks
 }  // namespace chromeos
diff --git a/chromeos/disks/disk.h b/chromeos/disks/disk.h
index 63860456..f77ff9e8 100644
--- a/chromeos/disks/disk.h
+++ b/chromeos/disks/disk.h
@@ -5,8 +5,10 @@
 #ifndef CHROMEOS_DISKS_DISK_H_
 #define CHROMEOS_DISKS_DISK_H_
 
+#include <memory>
 #include <string>
 
+#include "base/macros.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/cros_disks_client.h"
 
@@ -15,6 +17,8 @@
 
 class CHROMEOS_EXPORT Disk {
  public:
+  class Builder;
+
   Disk(const DiskInfo& disk_info,
        // Whether the device is mounted in read-only mode by the policy.
        // Valid only when the device mounted and mount_path_ is non-empty.
@@ -23,32 +27,7 @@
        const std::string& base_mount_path);
 
   // For tests.
-  // TODO(amistry): Replace with a builder.
-  Disk(const std::string& device_path,
-       // The path to the mount point of this device. Empty if not mounted.
-       // (e.g. /media/removable/VOLUME)
-       const std::string& mount_path,
-       bool write_disabled_by_policy,
-       const std::string& system_path,
-       const std::string& file_path,
-       const std::string& device_label,
-       const std::string& drive_label,
-       const std::string& vendor_id,
-       const std::string& vendor_name,
-       const std::string& product_id,
-       const std::string& product_name,
-       const std::string& fs_uuid,
-       const std::string& system_path_prefix,
-       DeviceType device_type,
-       uint64_t total_size_in_bytes,
-       bool is_parent,
-       bool is_read_only_hardware,
-       bool has_media,
-       bool on_boot_device,
-       bool on_removable_device,
-       bool is_hidden,
-       const std::string& file_system_type,
-       const std::string& base_mount_path);
+  // TODO(amistry): Eliminate this copy constructor. It is only used in tests.
   Disk(const Disk&);
 
   ~Disk();
@@ -128,6 +107,9 @@
   // Shoud the device be shown in the UI, or automounted.
   bool is_hidden() const { return is_hidden_; }
 
+  // Is the disk auto-mountable.
+  bool is_auto_mountable() const { return is_auto_mountable_; }
+
   void set_write_disabled_by_policy(bool disable) {
     write_disabled_by_policy_ = disable;
   }
@@ -146,16 +128,16 @@
 
   void SetMountPath(const std::string& mount_path);
 
-  bool IsAutoMountable() const;
-
   bool IsStatefulPartition() const;
 
  private:
-  Disk() = delete;
+  friend class Builder;
+
+  Disk();
 
   std::string device_path_;
   std::string mount_path_;
-  bool write_disabled_by_policy_;
+  bool write_disabled_by_policy_ = false;
   std::string system_path_;
   std::string file_path_;
   std::string device_label_;
@@ -166,18 +148,56 @@
   std::string product_name_;
   std::string fs_uuid_;
   std::string system_path_prefix_;
-  DeviceType device_type_;
-  uint64_t total_size_in_bytes_;
-  bool is_parent_;
-  bool is_read_only_hardware_;
-  bool has_media_;
-  bool on_boot_device_;
-  bool on_removable_device_;
-  bool is_hidden_;
+  DeviceType device_type_ = DEVICE_TYPE_UNKNOWN;
+  uint64_t total_size_in_bytes_ = 0;
+  bool is_parent_ = false;
+  bool is_read_only_hardware_ = false;
+  bool has_media_ = false;
+  bool on_boot_device_ = false;
+  bool on_removable_device_ = false;
+  bool is_hidden_ = false;
+  bool is_auto_mountable_ = false;
   std::string file_system_type_;
   std::string base_mount_path_;
 };
 
+class CHROMEOS_EXPORT Disk::Builder {
+ public:
+  Builder();
+  ~Builder();
+
+  Builder& SetDevicePath(const std::string& device_path);
+  Builder& SetMountPath(const std::string& mount_path);
+  Builder& SetWriteDisabledByPolicy(bool write_disabled_by_policy);
+  Builder& SetSystemPath(const std::string& system_path);
+  Builder& SetFilePath(const std::string& file_path);
+  Builder& SetDeviceLabel(const std::string& device_label);
+  Builder& SetDriveLabel(const std::string& drive_label);
+  Builder& SetVendorId(const std::string& vendor_id);
+  Builder& SetVendorName(const std::string& vendor_name);
+  Builder& SetProductId(const std::string& product_id);
+  Builder& SetProductName(const std::string& product_name);
+  Builder& SetFileSystemUUID(const std::string& fs_uuid);
+  Builder& SetSystemPathPrefix(const std::string& system_path_prefix);
+  Builder& SetDeviceType(DeviceType device_type);
+  Builder& SetSizeInBytes(uint64_t total_size_in_bytes);
+  Builder& SetIsParent(bool is_parent);
+  Builder& SetIsReadOnlyHardware(bool is_read_only_hardware);
+  Builder& SetHasMedia(bool has_media);
+  Builder& SetOnBootDevice(bool on_boot_device);
+  Builder& SetOnRemovableDevice(bool on_removable_device);
+  Builder& SetIsHidden(bool is_hidden);
+  Builder& SetFileSystemType(const std::string& file_system_type);
+  Builder& SetBaseMountPath(const std::string& base_mount_path);
+
+  std::unique_ptr<Disk> Build();
+
+ private:
+  std::unique_ptr<Disk> disk_;
+
+  DISALLOW_COPY_AND_ASSIGN(Builder);
+};
+
 }  // namespace disks
 }  // namespace chromeos
 
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc
index 830a0a85..695867b 100644
--- a/chromeos/disks/disk_mount_manager.cc
+++ b/chromeos/disks/disk_mount_manager.cc
@@ -747,8 +747,8 @@
   // Notifies all observers about disk status update.
   void NotifyDiskStatusUpdate(DiskEvent event, const Disk& disk) {
     for (auto& observer : observers_) {
-      disk.IsAutoMountable() ? observer.OnAutoMountableDiskEvent(event, disk)
-                             : observer.OnBootDeviceDiskEvent(event, disk);
+      disk.is_auto_mountable() ? observer.OnAutoMountableDiskEvent(event, disk)
+                               : observer.OnBootDeviceDiskEvent(event, disk);
     }
   }
 
diff --git a/chromeos/disks/disk_mount_manager_unittest.cc b/chromeos/disks/disk_mount_manager_unittest.cc
index fc1e20a..18a23eae 100644
--- a/chromeos/disks/disk_mount_manager_unittest.cc
+++ b/chromeos/disks/disk_mount_manager_unittest.cc
@@ -43,7 +43,6 @@
 struct TestDiskInfo {
   const char* source_path;
   const char* mount_path;
-  bool write_disabled_by_policy;
   const char* system_path;
   const char* file_path;
   const char* device_label;
@@ -56,14 +55,8 @@
   const char* system_path_prefix;
   chromeos::DeviceType device_type;
   uint64_t size_in_bytes;
-  bool is_parent;
   bool is_read_only;
-  bool has_media;
-  bool on_boot_device;
-  bool on_removable_device;
-  bool is_hidden;
   const char* file_system_type;
-  const char* base_mount_path;
 };
 
 // Holds information to create a DiskMOuntManager::MountPointInfo instance.
@@ -79,7 +72,6 @@
     {
         kDevice1SourcePath,
         kDevice1MountPath,
-        false,  // write_disabled_by_policy
         "/device/prefix/system_path",
         "/device/file_path",
         "/device/device_label",
@@ -92,19 +84,12 @@
         "/device/prefix",
         chromeos::DEVICE_TYPE_USB,
         1073741824,  // size in bytes
-        false,       // is parent
         false,       // is read only
-        true,        // has media
-        false,       // is on boot device
-        true,        // is on removable device
-        false,       // is hidden
         kFileSystemType1,
-        ""  // base mount path
     },
     {
         kDevice2SourcePath,
         "",     // not mounted initially
-        false,  // write_disabled_by_policy
         "/device/prefix/system_path2",
         "/device/file_path2",
         "/device/device_label2",
@@ -117,19 +102,12 @@
         "/device/prefix2",
         chromeos::DEVICE_TYPE_SD,
         1073741824,  // size in bytes
-        false,       // is parent
         false,       // is read only
-        true,        // has media
-        false,       // is on boot device
-        true,        // is on removable device
-        false,       // is hidden
         kFileSystemType2,
-        ""  // base mount path
     },
     {
         kReadOnlyDeviceSourcePath,
         kReadOnlyDeviceMountPath,
-        false,  // write_disabled_by_policy
         "/device/prefix/system_path_3",
         "/device/file_path_3",
         "/device/device_label_3",
@@ -142,14 +120,8 @@
         "/device/prefix",
         chromeos::DEVICE_TYPE_USB,
         1073741824,  // size in bytes
-        false,       // is parent
         true,        // is read only
-        true,        // has media
-        false,       // is on boot device
-        true,        // is on removable device
-        false,       // is hidden
         kFileSystemType2,
-        ""  // base mount path
     },
 };
 
@@ -556,16 +528,29 @@
  private:
   // Adds a new disk to the disk mount manager.
   void AddTestDisk(const TestDiskInfo& disk) {
+    std::unique_ptr<Disk> test_disk =
+        Disk::Builder()
+            .SetDevicePath(disk.source_path)
+            .SetMountPath(disk.mount_path)
+            .SetSystemPath(disk.system_path)
+            .SetFilePath(disk.file_path)
+            .SetDeviceLabel(disk.device_label)
+            .SetDriveLabel(disk.drive_label)
+            .SetVendorId(disk.vendor_id)
+            .SetVendorName(disk.vendor_name)
+            .SetProductId(disk.product_id)
+            .SetProductName(disk.product_name)
+            .SetFileSystemUUID(disk.fs_uuid)
+            .SetSystemPathPrefix(disk.system_path_prefix)
+            .SetDeviceType(disk.device_type)
+            .SetSizeInBytes(disk.size_in_bytes)
+            .SetIsReadOnlyHardware(disk.is_read_only)
+            .SetHasMedia(true)
+            .SetOnRemovableDevice(true)
+            .SetFileSystemType(disk.file_system_type)
+            .Build();
     EXPECT_TRUE(
-        DiskMountManager::GetInstance()->AddDiskForTest(std::make_unique<Disk>(
-            disk.source_path, disk.mount_path, disk.write_disabled_by_policy,
-            disk.system_path, disk.file_path, disk.device_label,
-            disk.drive_label, disk.vendor_id, disk.vendor_name, disk.product_id,
-            disk.product_name, disk.fs_uuid, disk.system_path_prefix,
-            disk.device_type, disk.size_in_bytes, disk.is_parent,
-            disk.is_read_only, disk.has_media, disk.on_boot_device,
-            disk.on_removable_device, disk.is_hidden, disk.file_system_type,
-            disk.base_mount_path)));
+        DiskMountManager::GetInstance()->AddDiskForTest(std::move(test_disk)));
   }
 
   // Adds a new mount point to the disk mount manager.
diff --git a/chromeos/disks/disk_unittest.cc b/chromeos/disks/disk_unittest.cc
index 7d8615fa..b96bc73 100644
--- a/chromeos/disks/disk_unittest.cc
+++ b/chromeos/disks/disk_unittest.cc
@@ -140,12 +140,10 @@
   EXPECT_FALSE(disk.on_removable_device());
   EXPECT_FALSE(disk.is_mounted());
   EXPECT_FALSE(disk.IsStatefulPartition());
+  EXPECT_FALSE(disk.is_auto_mountable());
 
   // Drives are hidden by default.
   EXPECT_TRUE(disk.is_hidden());
-
-  // Drives not on the boot device are auto-mountable.
-  EXPECT_TRUE(disk.IsAutoMountable());
 }
 
 std::unique_ptr<Disk> BuildDiskWithProperty(const std::string& property,
@@ -188,6 +186,10 @@
         BuildDiskWithProperty(cros_disks::kDeviceIsOnRemovableDevice, true);
     EXPECT_TRUE(disk->on_removable_device());
   }
+  {
+    auto disk = BuildDiskWithProperty(cros_disks::kIsAutoMountable, true);
+    EXPECT_TRUE(disk->is_auto_mountable());
+  }
 }
 
 TEST(DiskTest, ConstructFromDiskInfo_WriteDisabledByPolicy) {
diff --git a/chromeos/disks/mock_disk_mount_manager.cc b/chromeos/disks/mock_disk_mount_manager.cc
index 247bbea..f809d46 100644
--- a/chromeos/disks/mock_disk_mount_manager.cc
+++ b/chromeos/disks/mock_disk_mount_manager.cc
@@ -36,6 +36,24 @@
 const char kTestUuid[] = "FFFF-FFFF";
 const char kTestFileSystemType[] = "vfat";
 
+std::unique_ptr<Disk::Builder> MakeDiskBuilder() {
+  std::unique_ptr<Disk::Builder> builder = std::make_unique<Disk::Builder>();
+  builder->SetDevicePath(kTestDevicePath)
+      .SetSystemPath(kTestSystemPath)
+      .SetFilePath(kTestFilePath)
+      .SetDriveLabel(kTestDriveLabel)
+      .SetVendorId(kTestVendorId)
+      .SetVendorName(kTestVendorName)
+      .SetProductId(kTestProductId)
+      .SetProductName(kTestProductName)
+      .SetFileSystemUUID(kTestUuid)
+      .SetSystemPathPrefix(kTestSystemPathPrefix)
+      .SetHasMedia(true)
+      .SetOnRemovableDevice(true)
+      .SetFileSystemType(kTestFileSystemType);
+  return builder;
+}
+
 }  // namespace
 
 void MockDiskMountManager::AddObserverInternal(
@@ -69,21 +87,10 @@
 MockDiskMountManager::~MockDiskMountManager() = default;
 
 void MockDiskMountManager::NotifyDeviceInsertEvents() {
-  std::unique_ptr<Disk> disk1_ptr = std::make_unique<Disk>(
-      std::string(kTestDevicePath), std::string(),
-      false,  // write_disabled_by_policy
-      std::string(kTestSystemPath), std::string(kTestFilePath), std::string(),
-      std::string(kTestDriveLabel), std::string(kTestVendorId),
-      std::string(kTestVendorName), std::string(kTestProductId),
-      std::string(kTestProductName), std::string(kTestUuid),
-      std::string(kTestSystemPathPrefix), DEVICE_TYPE_USB, 4294967295U,
-      false,  // is_parent
-      false,  // is_read_only
-      true,   // has_media
-      false,  // on_boot_device
-      true,   // on_removable_device
-      false,  // is_hidden
-      std::string(kTestFileSystemType), std::string());
+  std::unique_ptr<Disk> disk1_ptr = MakeDiskBuilder()
+                                        ->SetDeviceType(DEVICE_TYPE_USB)
+                                        .SetSizeInBytes(4294967295U)
+                                        .Build();
   Disk* disk1 = disk1_ptr.get();
 
   disks_.clear();
@@ -96,22 +103,11 @@
   NotifyDiskChanged(DISK_ADDED, disk1);
 
   // Disk Changed
-  std::unique_ptr<Disk> disk2_ptr = std::make_unique<Disk>(
-      std::string(kTestDevicePath), std::string(kTestMountPath),
-      false,  // write_disabled_by_policy
-      std::string(kTestSystemPath), std::string(kTestFilePath),
-      std::string(kTestDeviceLabel), std::string(kTestDriveLabel),
-      std::string(kTestVendorId), std::string(kTestVendorName),
-      std::string(kTestProductId), std::string(kTestProductName),
-      std::string(kTestUuid), std::string(kTestSystemPathPrefix),
-      DEVICE_TYPE_MOBILE, 1073741824,
-      false,  // is_parent
-      false,  // is_read_only
-      true,   // has_media
-      false,  // on_boot_device
-      true,   // on_removable_device
-      false,  // is_hidden
-      std::string(kTestFileSystemType), std::string());
+  std::unique_ptr<Disk> disk2_ptr = MakeDiskBuilder()
+                                        ->SetMountPath(kTestMountPath)
+                                        .SetDeviceType(DEVICE_TYPE_MOBILE)
+                                        .SetSizeInBytes(1073741824)
+                                        .Build();
   Disk* disk2 = disk2_ptr.get();
   disks_.clear();
   disks_[std::string(kTestDevicePath)] = std::move(disk2_ptr);
@@ -119,22 +115,12 @@
 }
 
 void MockDiskMountManager::NotifyDeviceRemoveEvents() {
-  std::unique_ptr<Disk> disk_ptr = std::make_unique<Disk>(
-      std::string(kTestDevicePath), std::string(kTestMountPath),
-      false,  // write_disabled_by_policy
-      std::string(kTestSystemPath), std::string(kTestFilePath),
-      std::string(kTestDeviceLabel), std::string(kTestDriveLabel),
-      std::string(kTestVendorId), std::string(kTestVendorName),
-      std::string(kTestProductId), std::string(kTestProductName),
-      std::string(kTestUuid), std::string(kTestSystemPathPrefix),
-      DEVICE_TYPE_SD, 1073741824,
-      false,  // is_parent
-      false,  // is_read_only
-      true,   // has_media
-      false,  // on_boot_device
-      true,   // on_removable_device
-      false,  // is_hidden
-      std::string(kTestFileSystemType), std::string());
+  std::unique_ptr<Disk> disk_ptr = MakeDiskBuilder()
+                                       ->SetMountPath(kTestMountPath)
+                                       .SetDeviceLabel(kTestDeviceLabel)
+                                       .SetDeviceType(DEVICE_TYPE_SD)
+                                       .SetSizeInBytes(1073741824)
+                                       .Build();
   Disk* disk = disk_ptr.get();
   disks_.clear();
   disks_[std::string(kTestDevicePath)] = std::move(disk_ptr);
@@ -184,22 +170,22 @@
     bool on_removable_device,
     const std::string& file_system_type) {
   std::unique_ptr<Disk> disk_ptr =
-      std::make_unique<Disk>(mount_info.source_path, mount_info.mount_path,
-                             false,          // write_disabled_by_policy
-                             std::string(),  // system_path
-                             mount_info.source_path, device_label,
-                             std::string(),  // drive_label
-                             std::string(),  // vendor_id
-                             vendor_name,
-                             std::string(),  // product_id
-                             product_name,
-                             device_id,      // fs_uuid
-                             std::string(),  // system_path_prefix
-                             device_type, total_size_in_bytes, is_parent,
-                             false,  // is_read_only
-                             has_media, on_boot_device, on_removable_device,
-                             false,  // is_hidden
-                             file_system_type, std::string());
+      Disk::Builder()
+          .SetDevicePath(mount_info.source_path)
+          .SetMountPath(mount_info.mount_path)
+          .SetFilePath(mount_info.source_path)
+          .SetDeviceLabel(device_label)
+          .SetVendorName(vendor_name)
+          .SetProductName(product_name)
+          .SetFileSystemUUID(device_id)
+          .SetDeviceType(device_type)
+          .SetSizeInBytes(total_size_in_bytes)
+          .SetIsParent(is_parent)
+          .SetHasMedia(has_media)
+          .SetOnBootDevice(on_boot_device)
+          .SetOnRemovableDevice(on_removable_device)
+          .SetFileSystemType(file_system_type)
+          .Build();
   disks_[std::string(mount_info.source_path)] = std::move(disk_ptr);
 }
 
@@ -228,8 +214,8 @@
 void MockDiskMountManager::NotifyDiskChanged(DiskEvent event,
                                              const Disk* disk) {
   for (auto& observer : observers_) {
-    disk->IsAutoMountable() ? observer.OnAutoMountableDiskEvent(event, *disk)
-                            : observer.OnBootDeviceDiskEvent(event, *disk);
+    disk->is_auto_mountable() ? observer.OnAutoMountableDiskEvent(event, *disk)
+                              : observer.OnBootDeviceDiskEvent(event, *disk);
   }
 }
 
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.cc b/chromeos/services/assistant/platform/audio_output_provider_impl.cc
index a57d141..b5e75bd 100644
--- a/chromeos/services/assistant/platform/audio_output_provider_impl.cc
+++ b/chromeos/services/assistant/platform/audio_output_provider_impl.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/services/assistant/platform/audio_output_provider_impl.h"
 
+#include "ash/public/interfaces/constants.mojom.h"
 #include "libassistant/shared/public/platform_audio_buffer.h"
 #include "media/audio/audio_device_description.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -122,7 +123,13 @@
 
 }  // namespace
 
-VolumeControlImpl::VolumeControlImpl() = default;
+VolumeControlImpl::VolumeControlImpl(service_manager::Connector* connector)
+    : binding_(this) {
+  connector->BindInterface(ash::mojom::kServiceName, &volume_control_ptr_);
+  ash::mojom::VolumeObserverPtr observer;
+  binding_.Bind(mojo::MakeRequest(&observer));
+  volume_control_ptr_->AddVolumeObserver(std::move(observer));
+}
 
 VolumeControlImpl::~VolumeControlImpl() = default;
 
@@ -130,12 +137,11 @@
     assistant_client::OutputStreamType focused_stream) {}
 
 float VolumeControlImpl::GetSystemVolume() {
-  // TODO(muyuanli): implement.
-  return 100.0f;
+  return volume_;
 }
 
 void VolumeControlImpl::SetSystemVolume(float new_volume, bool user_initiated) {
-  // TODO(muyuanli): implement.
+  volume_control_ptr_->SetVolume(new_volume, user_initiated);
 }
 
 float VolumeControlImpl::GetAlarmVolume() {
@@ -148,17 +154,25 @@
 }
 
 bool VolumeControlImpl::IsSystemMuted() {
-  // TODO(muyuanli): implement.
-  return false;
+  return mute_;
 }
 
 void VolumeControlImpl::SetSystemMuted(bool muted) {
-  // TODO(muyuanli): implement.
+  volume_control_ptr_->SetMuted(muted);
+}
+
+void VolumeControlImpl::OnVolumeChanged(int volume) {
+  volume_ = volume;
+}
+
+void VolumeControlImpl::OnMuteStateChanged(bool mute) {
+  mute_ = mute;
 }
 
 AudioOutputProviderImpl::AudioOutputProviderImpl(
     service_manager::Connector* connector)
-    : connector_(connector),
+    : volume_control_impl_(connector),
+      connector_(connector),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
 
 AudioOutputProviderImpl::~AudioOutputProviderImpl() = default;
@@ -181,6 +195,7 @@
       assistant_client::OutputStreamEncoding::STREAM_PCM_S16,
       assistant_client::OutputStreamEncoding::STREAM_PCM_S32,
       assistant_client::OutputStreamEncoding::STREAM_PCM_F32,
+      assistant_client::OutputStreamEncoding::STREAM_MP3,
   };
 }
 
@@ -216,14 +231,20 @@
   DCHECK(!output_device_);
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
 
+  delegate_ = delegate;
   format_ = format;
+  // TODO(wutao): Remove this after supporting mp3 encoding.
+  if (format_.encoding == assistant_client::OutputStreamEncoding::STREAM_MP3) {
+    delegate_->OnEndOfStream();
+    return;
+  }
+
   audio_param_ = GetAudioParametersFromBufferFormat(format_);
 
   // |audio_fifo_| contains 3x the number of frames to render.
   audio_fifo_ = std::make_unique<media::AudioBlockFifo>(
       format.pcm_num_channels, audio_param_.frames_per_buffer(), 3);
   audio_data_.resize(GetBufferSizeInBytesFromBufferFormat(format_));
-  delegate_ = delegate;
   ScheduleFillLocked(base::TimeTicks::Now());
 
   // |connector| is null in unittest.
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.h b/chromeos/services/assistant/platform/audio_output_provider_impl.h
index 373c8c9..25b416f 100644
--- a/chromeos/services/assistant/platform/audio_output_provider_impl.h
+++ b/chromeos/services/assistant/platform/audio_output_provider_impl.h
@@ -5,12 +5,14 @@
 #ifndef CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_OUTPUT_PROVIDER_IMPL_H_
 #define CHROMEOS_SERVICES_ASSISTANT_PLATFORM_AUDIO_OUTPUT_PROVIDER_IMPL_H_
 
+#include "ash/public/interfaces/assistant_volume_control.mojom.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "libassistant/shared/public/platform_audio_output.h"
 #include "media/base/audio_block_fifo.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/audio_renderer_sink.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "services/audio/public/cpp/output_device.h"
 
 namespace service_manager {
@@ -20,9 +22,10 @@
 namespace chromeos {
 namespace assistant {
 
-class VolumeControlImpl : public assistant_client::VolumeControl {
+class VolumeControlImpl : public assistant_client::VolumeControl,
+                          public ash::mojom::VolumeObserver {
  public:
-  VolumeControlImpl();
+  explicit VolumeControlImpl(service_manager::Connector* connector);
   ~VolumeControlImpl() override;
 
   // assistant_client::VolumeControl overrides:
@@ -35,7 +38,17 @@
   bool IsSystemMuted() override;
   void SetSystemMuted(bool muted) override;
 
+  // ash::mojom::VolumeObserver overrides:
+  void OnVolumeChanged(int volume) override;
+  void OnMuteStateChanged(bool mute) override;
+
  private:
+  ash::mojom::AssistantVolumeControlPtr volume_control_ptr_;
+  mojo::Binding<ash::mojom::VolumeObserver> binding_;
+
+  int volume_ = 100;
+  bool mute_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(VolumeControlImpl);
 };
 
diff --git a/chromeos/services/assistant/service.cc b/chromeos/services/assistant/service.cc
index 4198bba..4675431 100644
--- a/chromeos/services/assistant/service.cc
+++ b/chromeos/services/assistant/service.cc
@@ -60,6 +60,7 @@
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       power_manager_observer_(this),
       voice_interaction_observer_binding_(this),
+      assistant_interaction_subscriber_binding_(this),
       weak_ptr_factory_(this) {
   registry_.AddInterface<mojom::AssistantPlatform>(base::BindRepeating(
       &Service::BindAssistantPlatformConnection, base::Unretained(this)));
@@ -172,6 +173,15 @@
   RequestAccessToken();
 }
 
+void Service::OnInteractionFinished(
+    mojom::AssistantInteractionResolution resolution) {
+  if (resolution == mojom::AssistantInteractionResolution::kError) {
+    // When communicateion error happens, it could be caused by auth errors.
+    // Retry with a new auth token to attempt recovery.
+    RequestAccessToken();
+  }
+}
+
 void Service::BindAssistantSettingsManager(
     mojom::AssistantSettingsManagerRequest request) {
   DCHECK(assistant_settings_manager_);
@@ -299,6 +309,14 @@
       assistant_manager_service_.get()->GetAssistantSettingsManager();
   registry_.AddInterface<mojom::AssistantSettingsManager>(base::BindRepeating(
       &Service::BindAssistantSettingsManager, base::Unretained(this)));
+
+  // Subscribe to Assistant interaction events.
+  chromeos::assistant::mojom::AssistantInteractionSubscriberPtr
+      interaction_subscriber_ptr;
+  assistant_interaction_subscriber_binding_.Bind(
+      mojo::MakeRequest(&interaction_subscriber_ptr));
+  assistant_manager_service_->AddAssistantInteractionSubscriber(
+      std::move(interaction_subscriber_ptr));
 #endif
 }
 
diff --git a/chromeos/services/assistant/service.h b/chromeos/services/assistant/service.h
index c0b1c28c..4abe0c8 100644
--- a/chromeos/services/assistant/service.h
+++ b/chromeos/services/assistant/service.h
@@ -42,6 +42,7 @@
 class Service : public service_manager::Service,
                 public chromeos::PowerManagerClient::Observer,
                 public ash::mojom::SessionActivationObserver,
+                public mojom::AssistantInteractionSubscriber,
                 public mojom::AssistantPlatform,
                 public ash::mojom::VoiceInteractionObserver {
  public:
@@ -93,6 +94,25 @@
   void OnAssistantFeatureAllowedChanged(
       ash::mojom::AssistantAllowedState state) override {}
 
+  // chromeos::assistant::mojom::AssistantInteractionSubscriber:
+  void OnInteractionStarted(bool is_voice_interaction) override{};
+  void OnInteractionFinished(
+      mojom::AssistantInteractionResolution resolution) override;
+  void OnHtmlResponse(const std::string& response) override{};
+  void OnSuggestionsResponse(
+      std::vector<mojom::AssistantSuggestionPtr> response) override{};
+  void OnTextResponse(const std::string& response) override{};
+  void OnOpenUrlResponse(const GURL& url) override{};
+  void OnSpeechRecognitionStarted() override{};
+  void OnSpeechRecognitionIntermediateResult(
+      const std::string& high_confidence_text,
+      const std::string& low_confidence_text) override{};
+  void OnSpeechRecognitionEndOfUtterance() override{};
+  void OnSpeechRecognitionFinalResult(
+      const std::string& final_result) override{};
+  void OnSpeechLevelUpdated(float speech_level) override{};
+  void OnTtsStarted() override{};
+
   void BindAssistantSettingsManager(
       mojom::AssistantSettingsManagerRequest request);
 
@@ -152,6 +172,8 @@
   ash::mojom::VoiceInteractionControllerPtr voice_interaction_controller_;
   mojo::Binding<ash::mojom::VoiceInteractionObserver>
       voice_interaction_observer_binding_;
+  mojo::Binding<chromeos::assistant::mojom::AssistantInteractionSubscriber>
+      assistant_interaction_subscriber_binding_;
 
   base::WeakPtrFactory<Service> weak_ptr_factory_;
 
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn
index 5f4fd16..db010ab 100644
--- a/chromeos/services/device_sync/BUILD.gn
+++ b/chromeos/services/device_sync/BUILD.gn
@@ -90,6 +90,7 @@
     "//components/gcm_driver:test_support",
     "//components/prefs:test_support",
     "//services/identity/public/cpp:test_support",
+    "//services/network:test_support",
     "//services/service_manager/public/cpp:service_test_support",
     "//services/service_manager/public/cpp/test:test_support",
     "//testing/gtest",
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc
index cf0f24f..be5df26 100644
--- a/chromeos/services/device_sync/device_sync_impl.cc
+++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -23,8 +23,8 @@
 #include "components/cryptauth/software_feature_manager_impl.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/identity/public/cpp/identity_manager.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
@@ -51,17 +51,17 @@
     gcm::GCMDriver* gcm_driver,
     service_manager::Connector* connector,
     const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context) {
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   if (test_factory_instance_) {
     return test_factory_instance_->BuildInstance(
         identity_manager, gcm_driver, connector, gcm_device_info_provider,
-        std::move(url_request_context));
+        std::move(url_loader_factory));
   }
 
   static base::NoDestructor<DeviceSyncImpl::Factory> default_factory;
   return default_factory->BuildInstance(identity_manager, gcm_driver, connector,
                                         gcm_device_info_provider,
-                                        std::move(url_request_context));
+                                        std::move(url_loader_factory));
 }
 
 // static
@@ -76,10 +76,10 @@
     gcm::GCMDriver* gcm_driver,
     service_manager::Connector* connector,
     const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context) {
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   return base::WrapUnique(new DeviceSyncImpl(
       identity_manager, gcm_driver, connector, gcm_device_info_provider,
-      std::move(url_request_context), base::DefaultClock::GetInstance(),
+      std::move(url_loader_factory), base::DefaultClock::GetInstance(),
       std::make_unique<PrefConnectionDelegate>()));
 }
 
@@ -105,14 +105,14 @@
     gcm::GCMDriver* gcm_driver,
     service_manager::Connector* connector,
     const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     base::Clock* clock,
     std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate)
     : identity_manager_(identity_manager),
       gcm_driver_(gcm_driver),
       connector_(connector),
       gcm_device_info_provider_(gcm_device_info_provider),
-      url_request_context_(url_request_context),
+      url_loader_factory_(std::move(url_loader_factory)),
       clock_(clock),
       pref_connection_delegate_(std::move(pref_connection_delegate)),
       status_(Status::FETCHING_ACCOUNT_INFO),
@@ -329,7 +329,7 @@
 
   cryptauth_client_factory_ =
       std::make_unique<cryptauth::CryptAuthClientFactoryImpl>(
-          identity_manager_, url_request_context_,
+          identity_manager_, url_loader_factory_,
           cryptauth::device_classifier_util::GetDeviceClassifier());
 
   // Initialize |crypauth_device_manager_| and start observing. Start() is not
diff --git a/chromeos/services/device_sync/device_sync_impl.h b/chromeos/services/device_sync/device_sync_impl.h
index c1db0aa..85ca389e 100644
--- a/chromeos/services/device_sync/device_sync_impl.h
+++ b/chromeos/services/device_sync/device_sync_impl.h
@@ -39,9 +39,9 @@
 class IdentityManager;
 }  // namespace identity
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
 
 namespace service_manager {
 class Connector;
@@ -69,7 +69,7 @@
         gcm::GCMDriver* gcm_driver,
         service_manager::Connector* connector,
         const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-        scoped_refptr<net::URLRequestContextGetter> url_request_context);
+        scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
     static void SetInstanceForTesting(Factory* test_factory);
 
     virtual ~Factory();
@@ -78,7 +78,7 @@
         gcm::GCMDriver* gcm_driver,
         service_manager::Connector* connector,
         const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-        scoped_refptr<net::URLRequestContextGetter> url_request_context);
+        scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
    private:
     static Factory* test_factory_instance_;
@@ -137,7 +137,7 @@
       gcm::GCMDriver* gcm_driver,
       service_manager::Connector* connector,
       const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       base::Clock* clock,
       std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate);
 
@@ -176,7 +176,7 @@
   gcm::GCMDriver* gcm_driver_;
   service_manager::Connector* connector_;
   const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   base::Clock* clock_;
   std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate_;
 
diff --git a/chromeos/services/device_sync/device_sync_service.cc b/chromeos/services/device_sync/device_sync_service.cc
index 5014da15..5cb7577f 100644
--- a/chromeos/services/device_sync/device_sync_service.cc
+++ b/chromeos/services/device_sync/device_sync_service.cc
@@ -7,7 +7,7 @@
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "chromeos/services/device_sync/device_sync_base.h"
 #include "chromeos/services/device_sync/device_sync_impl.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 namespace chromeos {
@@ -18,11 +18,11 @@
     identity::IdentityManager* identity_manager,
     gcm::GCMDriver* gcm_driver,
     const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context)
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : identity_manager_(identity_manager),
       gcm_driver_(gcm_driver),
       gcm_device_info_provider_(gcm_device_info_provider),
-      url_request_context_(url_request_context) {}
+      url_loader_factory_(std::move(url_loader_factory)) {}
 
 DeviceSyncService::~DeviceSyncService() = default;
 
@@ -33,7 +33,7 @@
   // |device_sync_impl_| cannot be initialized until OnStart().
   device_sync_ = DeviceSyncImpl::Factory::NewInstance(
       identity_manager_, gcm_driver_, context()->connector(),
-      gcm_device_info_provider_, url_request_context_);
+      gcm_device_info_provider_, url_loader_factory_);
 
   registry_.AddInterface(base::Bind(&DeviceSyncBase::BindRequest,
                                     base::Unretained(device_sync_.get())));
diff --git a/chromeos/services/device_sync/device_sync_service.h b/chromeos/services/device_sync/device_sync_service.h
index 15902f0..3122caa 100644
--- a/chromeos/services/device_sync/device_sync_service.h
+++ b/chromeos/services/device_sync/device_sync_service.h
@@ -24,9 +24,9 @@
 class IdentityManager;
 }  // namespace identity
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
 
 namespace chromeos {
 
@@ -43,7 +43,7 @@
       identity::IdentityManager* identity_manager,
       gcm::GCMDriver* gcm_driver,
       const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context);
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
   ~DeviceSyncService() override;
 
  protected:
@@ -57,7 +57,7 @@
   identity::IdentityManager* identity_manager_;
   gcm::GCMDriver* gcm_driver_;
   const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   std::unique_ptr<DeviceSyncBase> device_sync_;
   service_manager::BinderRegistry registry_;
diff --git a/chromeos/services/device_sync/device_sync_service_unittest.cc b/chromeos/services/device_sync/device_sync_service_unittest.cc
index f3248df7..93a80d9 100644
--- a/chromeos/services/device_sync/device_sync_service_unittest.cc
+++ b/chromeos/services/device_sync/device_sync_service_unittest.cc
@@ -33,8 +33,8 @@
 #include "components/gcm_driver/fake_gcm_driver.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/identity/public/cpp/identity_test_environment.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -332,23 +332,6 @@
   cryptauth::FakeSoftwareFeatureManager* instance_ = nullptr;
 };
 
-class FakeURLRequestContextGetter : public net::URLRequestContextGetter {
- public:
-  FakeURLRequestContextGetter() : null_task_runner_(new base::NullTaskRunner) {}
-
-  net::URLRequestContext* GetURLRequestContext() override { return nullptr; }
-
-  scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
-      const override {
-    return null_task_runner_;
-  }
-
- private:
-  ~FakeURLRequestContextGetter() override {}
-
-  scoped_refptr<base::SingleThreadTaskRunner> null_task_runner_;
-};
-
 }  // namespace
 
 class DeviceSyncServiceTest : public testing::Test {
@@ -416,11 +399,11 @@
         gcm::GCMDriver* gcm_driver,
         service_manager::Connector* connector,
         const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-        scoped_refptr<net::URLRequestContextGetter> url_request_context)
+        scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
         override {
       return base::WrapUnique(new DeviceSyncImpl(
           identity_manager, gcm_driver, connector, gcm_device_info_provider,
-          std::move(url_request_context), simple_test_clock_,
+          std::move(url_loader_factory), simple_test_clock_,
           std::move(fake_pref_connection_delegate_)));
     }
 
@@ -501,8 +484,12 @@
         std::make_unique<cryptauth::FakeGcmDeviceInfoProvider>(
             GetTestGcmDeviceInfo());
 
-    fake_url_request_context_getter_ =
-        base::MakeRefCounted<FakeURLRequestContextGetter>();
+    auto shared_url_loader_factory =
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            base::BindOnce([]() -> network::mojom::URLLoaderFactory* {
+              ADD_FAILURE() << "Did not expect this to actually be used";
+              return nullptr;
+            }));
 
     fake_device_sync_observer_ = std::make_unique<FakeDeviceSyncObserver>();
     connector_factory_ =
@@ -510,7 +497,7 @@
             std::make_unique<DeviceSyncService>(
                 identity_test_environment_->identity_manager(),
                 fake_gcm_driver_.get(), fake_gcm_device_info_provider_.get(),
-                fake_url_request_context_getter_.get()));
+                shared_url_loader_factory));
   }
 
   void TearDown() override { DBusThreadManager::Shutdown(); }
@@ -943,7 +930,6 @@
   std::unique_ptr<gcm::FakeGCMDriver> fake_gcm_driver_;
   std::unique_ptr<cryptauth::FakeGcmDeviceInfoProvider>
       fake_gcm_device_info_provider_;
-  scoped_refptr<FakeURLRequestContextGetter> fake_url_request_context_getter_;
 
   std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
   std::unique_ptr<service_manager::Connector> connector_;
diff --git a/chromeos/services/device_sync/public/cpp/BUILD.gn b/chromeos/services/device_sync/public/cpp/BUILD.gn
index e669708a0..9bd23591 100644
--- a/chromeos/services/device_sync/public/cpp/BUILD.gn
+++ b/chromeos/services/device_sync/public/cpp/BUILD.gn
@@ -58,6 +58,7 @@
     "//components/gcm_driver:test_support",
     "//net",
     "//services/identity/public/cpp:test_support",
+    "//services/network:test_support",
     "//services/service_manager/public/cpp:service_test_support",
     "//services/service_manager/public/cpp/test:test_support",
     "//testing/gtest",
diff --git a/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc b/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc
index babe0a79..b4d235a 100644
--- a/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc
+++ b/chromeos/services/device_sync/public/cpp/device_sync_client_impl_unittest.cc
@@ -24,8 +24,8 @@
 #include "components/cryptauth/fake_gcm_device_info_provider.h"
 #include "components/cryptauth/remote_device_test_util.h"
 #include "components/gcm_driver/fake_gcm_driver.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/identity/public/cpp/identity_test_environment.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,7 +63,7 @@
       gcm::GCMDriver* gcm_driver,
       service_manager::Connector* connector,
       const cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context)
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
       override {
     EXPECT_TRUE(fake_device_sync_);
     return std::move(fake_device_sync_);
@@ -73,23 +73,6 @@
   std::unique_ptr<FakeDeviceSync> fake_device_sync_;
 };
 
-class FakeURLRequestContextGetter : public net::URLRequestContextGetter {
- public:
-  FakeURLRequestContextGetter() : null_task_runner_(new base::NullTaskRunner) {}
-
-  net::URLRequestContext* GetURLRequestContext() override { return nullptr; }
-
-  scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
-      const override {
-    return null_task_runner_;
-  }
-
- private:
-  ~FakeURLRequestContextGetter() override {}
-
-  scoped_refptr<base::SingleThreadTaskRunner> null_task_runner_;
-};
-
 class TestDeviceSyncClientObserver : public DeviceSyncClient::Observer {
  public:
   ~TestDeviceSyncClientObserver() override = default;
@@ -163,8 +146,6 @@
     fake_gcm_device_info_provider_ =
         std::make_unique<cryptauth::FakeGcmDeviceInfoProvider>(
             GetTestGcmDeviceInfo());
-    fake_url_request_context_getter_ =
-        base::MakeRefCounted<FakeURLRequestContextGetter>();
 
     identity_test_environment_ =
         std::make_unique<identity::IdentityTestEnvironment>();
@@ -178,10 +159,16 @@
     DeviceSyncImpl::Factory::SetInstanceForTesting(
         fake_device_sync_impl_factory_.get());
 
+    auto shared_url_loader_factory =
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            base::BindOnce([]() -> network::mojom::URLLoaderFactory* {
+              ADD_FAILURE() << "Did not expect this to actually be used";
+              return nullptr;
+            }));
+
     auto device_sync_service = std::make_unique<DeviceSyncService>(
         identity_test_environment_->identity_manager(), fake_gcm_driver_.get(),
-        fake_gcm_device_info_provider_.get(),
-        fake_url_request_context_getter_.get());
+        fake_gcm_device_info_provider_.get(), shared_url_loader_factory);
 
     connector_factory_ =
         service_manager::TestConnectorFactory::CreateForUniqueService(
@@ -441,7 +428,6 @@
   std::unique_ptr<gcm::FakeGCMDriver> fake_gcm_driver_;
   std::unique_ptr<cryptauth::FakeGcmDeviceInfoProvider>
       fake_gcm_device_info_provider_;
-  scoped_refptr<FakeURLRequestContextGetter> fake_url_request_context_getter_;
   FakeDeviceSync* fake_device_sync_;
   std::unique_ptr<FakeDeviceSyncImplFactory> fake_device_sync_impl_factory_;
   std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 33d0acef..06a62d4c 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -876,6 +876,13 @@
              base::i18n::ToLower(element->Value().Utf16())))
       continue;
 
+    // Check if we should autofill/preview/clear a select element or leave it.
+    if (!force_override && !is_initiating_element &&
+        IsSelectElement(*element) && element->UserHasEditedTheField() &&
+        base::FeatureList::IsEnabled(features::kAutofillPrefilledFields) &&
+        !SanitizedFieldIsEmpty(element->Value().Utf16()))
+      continue;
+
     if (((filters & FILTER_DISABLED_ELEMENTS) && !element->IsEnabled()) ||
         ((filters & FILTER_READONLY_ELEMENTS) && element->IsReadOnly()) ||
         // See description for FILTER_NON_FOCUSABLE_ELEMENTS.
diff --git a/components/autofill/core/browser/password_requirements_spec_printer.cc b/components/autofill/core/browser/password_requirements_spec_printer.cc
index 7a4d72e..dd7049d 100644
--- a/components/autofill/core/browser/password_requirements_spec_printer.cc
+++ b/components/autofill/core/browser/password_requirements_spec_printer.cc
@@ -4,9 +4,11 @@
 
 #include "components/autofill/core/browser/password_requirements_spec_printer.h"
 
+namespace autofill {
+
 std::ostream& operator<<(
     std::ostream& out,
-    const autofill::PasswordRequirementsSpec::CharacterClass& character_class) {
+    const PasswordRequirementsSpec::CharacterClass& character_class) {
   out << "{";
   if (character_class.has_character_set())
     out << "character_set: \"" << character_class.character_set() << "\", ";
@@ -19,7 +21,7 @@
 }
 
 std::ostream& operator<<(std::ostream& out,
-                         const autofill::PasswordRequirementsSpec& spec) {
+                         const PasswordRequirementsSpec& spec) {
   out << "{";
   if (spec.has_priority())
     out << "priority: " << spec.priority() << ", ";
@@ -42,3 +44,5 @@
   out << "}";
   return out;
 }
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/password_requirements_spec_printer.h b/components/autofill/core/browser/password_requirements_spec_printer.h
index 55db28706..8116934 100644
--- a/components/autofill/core/browser/password_requirements_spec_printer.h
+++ b/components/autofill/core/browser/password_requirements_spec_printer.h
@@ -9,11 +9,15 @@
 
 #include "components/autofill/core/browser/proto/password_requirements.pb.h"
 
+namespace autofill {
+
 std::ostream& operator<<(
     std::ostream& out,
-    const autofill::PasswordRequirementsSpec::CharacterClass& character_class);
+    const PasswordRequirementsSpec::CharacterClass& character_class);
 
 std::ostream& operator<<(std::ostream& out,
-                         const autofill::PasswordRequirementsSpec& spec);
+                         const PasswordRequirementsSpec& spec);
+
+}  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PASSWORD_REQUIREMENTS_SPEC_PRINTER_H_
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index aeb5617..551d495 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -106,7 +106,10 @@
     const char* history_disabled_pref,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
     const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
-    const scoped_refptr<autofill::AutofillWebDataService>& web_data_service,
+    const scoped_refptr<autofill::AutofillWebDataService>&
+        web_data_service_on_disk,
+    const scoped_refptr<autofill::AutofillWebDataService>&
+        web_data_service_in_memory,
     const scoped_refptr<password_manager::PasswordStore>& password_store)
     : sync_client_(sync_client),
       channel_(channel),
@@ -115,7 +118,8 @@
       history_disabled_pref_(history_disabled_pref),
       ui_thread_(ui_thread),
       db_thread_(db_thread),
-      web_data_service_(web_data_service),
+      web_data_service_on_disk_(web_data_service_on_disk),
+      web_data_service_in_memory_(web_data_service_in_memory),
       password_store_(password_store) {}
 
 ProfileSyncComponentsFactoryImpl::~ProfileSyncComponentsFactoryImpl() {}
@@ -153,7 +157,8 @@
       } else {
         controllers.push_back(
             std::make_unique<AutofillProfileDataTypeController>(
-                db_thread_, error_callback, sync_client_, web_data_service_));
+                db_thread_, error_callback, sync_client_,
+                web_data_service_on_disk_));
       }
     }
 
@@ -162,14 +167,15 @@
     bool wallet_disabled = disabled_types.Has(syncer::AUTOFILL_WALLET_DATA);
     if (!wallet_disabled) {
       if (base::FeatureList::IsEnabled(switches::kSyncUSSAutofillWalletData)) {
-        controllers.push_back(CreateWebDataModelTypeController(
-            syncer::AUTOFILL_WALLET_DATA,
-            base::BindRepeating(&AutofillWalletDelegateFromDataService)));
+        controllers.push_back(
+            CreateWebDataModelTypeControllerWithInMemorySupport(
+                syncer::AUTOFILL_WALLET_DATA,
+                base::BindRepeating(&AutofillWalletDelegateFromDataService)));
       } else {
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
                 syncer::AUTOFILL_WALLET_DATA, db_thread_, error_callback,
-                sync_client_, web_data_service_));
+                sync_client_, web_data_service_on_disk_));
       }
     }
 
@@ -187,7 +193,7 @@
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
                 syncer::AUTOFILL_WALLET_METADATA, db_thread_, error_callback,
-                sync_client_, web_data_service_));
+                sync_client_, web_data_service_on_disk_));
       }
     }
   }
@@ -413,9 +419,28 @@
             autofill::AutofillWebDataService*)>& delegate_from_web_data) {
   return std::make_unique<ModelTypeController>(
       type, std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
-                db_thread_,
-                base::BindRepeating(delegate_from_web_data,
-                                    base::RetainedRef(web_data_service_))));
+                db_thread_, base::BindRepeating(
+                                delegate_from_web_data,
+                                base::RetainedRef(web_data_service_on_disk_))));
+}
+
+std::unique_ptr<ModelTypeController> ProfileSyncComponentsFactoryImpl::
+    CreateWebDataModelTypeControllerWithInMemorySupport(
+        syncer::ModelType type,
+        const base::RepeatingCallback<
+            base::WeakPtr<syncer::ModelTypeControllerDelegate>(
+                autofill::AutofillWebDataService*)>& delegate_from_web_data) {
+  return std::make_unique<ModelTypeController>(
+      type, /*delegate_on_disk=*/
+      std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+          db_thread_,
+          base::BindRepeating(delegate_from_web_data,
+                              base::RetainedRef(web_data_service_on_disk_))),
+      /*delegate_in_memory=*/
+      std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+          db_thread_,
+          base::BindRepeating(delegate_from_web_data,
+                              base::RetainedRef(web_data_service_in_memory_))));
 }
 
 }  // namespace browser_sync
diff --git a/components/browser_sync/profile_sync_components_factory_impl.h b/components/browser_sync/profile_sync_components_factory_impl.h
index 6aafa3d..6663707 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/components/browser_sync/profile_sync_components_factory_impl.h
@@ -43,7 +43,10 @@
       const char* history_disabled_pref,
       const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread,
       const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
-      const scoped_refptr<autofill::AutofillWebDataService>& web_data_service,
+      const scoped_refptr<autofill::AutofillWebDataService>&
+          web_data_service_on_disk,
+      const scoped_refptr<autofill::AutofillWebDataService>&
+          web_data_service_in_memory,
       const scoped_refptr<password_manager::PasswordStore>& password_store);
   ~ProfileSyncComponentsFactoryImpl() override;
 
@@ -87,6 +90,15 @@
       const base::RepeatingCallback<
           base::WeakPtr<syncer::ModelTypeControllerDelegate>(
               autofill::AutofillWebDataService*)>& delegate_from_web_data);
+  // Same as above, but for datatypes supporting STORAGE_IN_MEMORY implemented
+  // as an independent AutofillWebDataService,
+  // namely |web_data_service_in_memory_|.
+  std::unique_ptr<syncer::ModelTypeController>
+  CreateWebDataModelTypeControllerWithInMemorySupport(
+      syncer::ModelType type,
+      const base::RepeatingCallback<
+          base::WeakPtr<syncer::ModelTypeControllerDelegate>(
+              autofill::AutofillWebDataService*)>& delegate_from_web_data);
 
   // Client/platform specific members.
   syncer::SyncClient* const sync_client_;
@@ -96,7 +108,10 @@
   const char* history_disabled_pref_;
   const scoped_refptr<base::SingleThreadTaskRunner> ui_thread_;
   const scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
-  const scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
+  const scoped_refptr<autofill::AutofillWebDataService>
+      web_data_service_on_disk_;
+  const scoped_refptr<autofill::AutofillWebDataService>
+      web_data_service_in_memory_;
   const scoped_refptr<password_manager::PasswordStore> password_store_;
 
   // Whether to override PREFERENCES to use USS.
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index f6df2a4..16b8176e 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/sync_auth_manager.h"
 #include "components/invalidation/impl/invalidation_prefs.h"
@@ -1589,8 +1590,17 @@
   // is supported.
   if (!IsSyncFeatureEnabled()) {
     DCHECK(IsStandaloneTransportEnabled());
-    const syncer::ModelTypeSet allowed_types = {syncer::USER_CONSENTS};
+    syncer::ModelTypeSet allowed_types = {syncer::USER_CONSENTS};
+
+    if (base::FeatureList::IsEnabled(
+            autofill::features::kAutofillEnableAccountWalletStorage) &&
+        base::FeatureList::IsEnabled(switches::kSyncUSSAutofillWalletData)) {
+      allowed_types.Put(syncer::AUTOFILL_WALLET_DATA);
+    }
+
     types = Intersection(types, allowed_types);
+    configure_context.storage_option =
+        syncer::ConfigureContext::STORAGE_IN_MEMORY;
   }
   data_type_manager_->Configure(types, configure_context);
 }
@@ -2246,12 +2256,14 @@
 
 void ProfileSyncService::ReconfigureDueToPassphrase(
     syncer::ConfigureReason reason) {
-  if (!CanConfigureDataTypes()) {
-    return;
+  if (CanConfigureDataTypes()) {
+    DCHECK(data_type_manager_->IsNigoriEnabled());
+    ConfigureDataTypeManager(reason);
   }
-  DCHECK(data_type_manager_->IsNigoriEnabled());
-  ConfigureDataTypeManager(reason);
-  // Notify observers that the passphrase status may have changed.
+  // Notify observers that the passphrase status may have changed, regardless of
+  // whether we triggered configuration or not. This is needed for the
+  // IsSetupInProgress() case where the UI needs to be updated to reflect that
+  // the passphrase was accepted (https://crbug.com/870256).
   NotifyObservers();
 }
 
diff --git a/components/browser_sync/sync_auth_manager.cc b/components/browser_sync/sync_auth_manager.cc
index 0bb12985a..7377c2a 100644
--- a/components/browser_sync/sync_auth_manager.cc
+++ b/components/browser_sync/sync_auth_manager.cc
@@ -186,6 +186,7 @@
 
 void SyncAuthManager::OnPrimaryAccountSet(
     const AccountInfo& primary_account_info) {
+  DCHECK_EQ(GoogleServiceAuthError::NONE, last_auth_error_.state());
   account_state_changed_callback_.Run();
 }
 
@@ -193,6 +194,9 @@
     const AccountInfo& previous_primary_account_info) {
   UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
                             syncer::STOP_SOURCE_LIMIT);
+  // Clear any pending request or auth errors we might have, since they aren't
+  // meaningful anymore.
+  Clear();
   account_state_changed_callback_.Run();
 }
 
diff --git a/components/browser_sync/sync_auth_manager_unittest.cc b/components/browser_sync/sync_auth_manager_unittest.cc
index 2c6f9f7..d429652 100644
--- a/components/browser_sync/sync_auth_manager_unittest.cc
+++ b/components/browser_sync/sync_auth_manager_unittest.cc
@@ -128,6 +128,35 @@
   EXPECT_EQ(auth_manager->GetAuthenticatedAccountInfo().account_id,
             second_account_id);
 }
+
+TEST_F(SyncAuthManagerTest, ClearsAuthErrorOnSignout) {
+  // Start out already signed in before the SyncAuthManager is created.
+  std::string account_id =
+      identity_env()->MakePrimaryAccountAvailable("test@email.com").account_id;
+
+  auto auth_manager = CreateAuthManager();
+  ASSERT_EQ(auth_manager->GetAuthenticatedAccountInfo().account_id, account_id);
+
+  auth_manager->RegisterForAuthNotifications();
+
+  ASSERT_EQ(auth_manager->GetLastAuthError().state(),
+            GoogleServiceAuthError::NONE);
+
+  // Sign out of the account.
+  // The ordering of removing the refresh token and the actual sign-out is
+  // undefined, see comment on IdentityManager::Observer. Here, explicitly
+  // revoke the refresh token first to force an auth error.
+  identity_env()->RemoveRefreshTokenForPrimaryAccount();
+
+  ASSERT_NE(auth_manager->GetLastAuthError().state(),
+            GoogleServiceAuthError::NONE);
+
+  // Now actually sign out, i.e. remove the primary account. This should clear
+  // the auth error, since it's now not meaningful anymore.
+  identity_env()->ClearPrimaryAccount();
+  EXPECT_EQ(auth_manager->GetLastAuthError().state(),
+            GoogleServiceAuthError::NONE);
+}
 #endif  // !OS_CHROMEOS
 
 TEST_F(SyncAuthManagerTest, ForwardsCredentialsEvents) {
diff --git a/components/certificate_transparency/log_dns_client.cc b/components/certificate_transparency/log_dns_client.cc
index 4e17c67d..311ee2e 100644
--- a/components/certificate_transparency/log_dns_client.cc
+++ b/components/certificate_transparency/log_dns_client.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -43,6 +44,20 @@
   }
 }
 
+void LogQueryResult(const std::string& name,
+                    net::Error error,
+                    const net::DnsResponse* response) {
+  base::UmaHistogramSparse(
+      base::StrCat({"Net.CertificateTransparency.DnsQuery", name, "Error"}),
+      -error);
+
+  if (response) {
+    base::UmaHistogramSparse(
+        base::StrCat({"Net.CertificateTransparency.DnsQuery", name, "Rcode"}),
+        response->rcode());
+  }
+}
+
 // Returns an EDNS option that disables the client subnet extension, as
 // described in https://tools.ietf.org/html/rfc7871. This is to avoid the
 // privacy issues caused by this extension being enabled in recursive resolvers
@@ -250,6 +265,7 @@
     : next_state_(State::NONE),
       domain_for_log_(domain_for_log),
       dns_client_(dns_client),
+      last_dns_response_(nullptr),
       net_log_(net_log),
       weak_ptr_factory_(this) {
   DCHECK(dns_client_);
@@ -297,10 +313,8 @@
         break;
       case State::REQUEST_LEAF_INDEX_COMPLETE:
         result = RequestLeafIndexComplete(result);
-        if (result == net::OK) {
-          base::UmaHistogramSparse(
-              "Net.CertificateTransparency.DnsQueryLeafIndexError", net::OK);
-        }
+        if (result == net::OK)
+          LogQueryResult("LeafIndex", net::OK, last_dns_response_);
         break;
       case State::REQUEST_AUDIT_PROOF_NODES:
         result = RequestAuditProofNodes();
@@ -321,14 +335,12 @@
       case State::REQUEST_LEAF_INDEX:
       case State::REQUEST_LEAF_INDEX_COMPLETE:
         // An error must have occurred if the query completed in this state.
-        base::UmaHistogramSparse(
-            "Net.CertificateTransparency.DnsQueryLeafIndexError", -result);
+        LogQueryResult("LeafIndex", result, last_dns_response_);
         break;
       case State::REQUEST_AUDIT_PROOF_NODES:
       case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE:
         // The query may have completed successfully.
-        base::UmaHistogramSparse(
-            "Net.CertificateTransparency.DnsQueryAuditProofError", -result);
+        LogQueryResult("AuditProof", result, last_dns_response_);
         break;
       case State::NONE:
         NOTREACHED();
@@ -453,6 +465,7 @@
     return false;
   }
 
+  last_dns_response_ = nullptr;
   current_dns_transaction_ = factory->CreateTransaction(
       qname, net::dns_protocol::kTypeTXT,
       base::BindOnce(&AuditProofQueryImpl::OnDnsTransactionComplete,
diff --git a/components/certificate_transparency/log_dns_client_unittest.cc b/components/certificate_transparency/log_dns_client_unittest.cc
index 85f50bd..0cacc9f 100644
--- a/components/certificate_transparency/log_dns_client_unittest.cc
+++ b/components/certificate_transparency/log_dns_client_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/test_timeouts.h"
 #include "components/certificate_transparency/mock_log_dns_traffic.h"
 #include "crypto/sha2.h"
@@ -32,14 +33,24 @@
 namespace certificate_transparency {
 namespace {
 
+using net::test::IsError;
+using net::test::IsOk;
 using ::testing::AllOf;
 using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::Le;
 using ::testing::Not;
 using ::testing::NotNull;
-using net::test::IsError;
-using net::test::IsOk;
+
+// Histogram names.
+const char kLeafIndexErrorHistogram[] =
+    "Net.CertificateTransparency.DnsQueryLeafIndexError";
+const char kLeafIndexRcodeHistogram[] =
+    "Net.CertificateTransparency.DnsQueryLeafIndexRcode";
+const char kAuditProofErrorHistogram[] =
+    "Net.CertificateTransparency.DnsQueryAuditProofError";
+const char kAuditProofRcodeHistogram[] =
+    "Net.CertificateTransparency.DnsQueryAuditProofRcode";
 
 // Sample Merkle leaf hashes.
 const char* const kLeafHashes[] = {
@@ -127,6 +138,8 @@
   base::MessageLoopForIO message_loop_;
   // Allows mock DNS sockets to be setup.
   MockLogDnsTraffic mock_dns_;
+  // Tests that histograms are populated as expected.
+  base::HistogramTester histograms_;
 };
 
 TEST_P(LogDnsClientTest, QueryAuditProofReportsThatLogDomainDoesNotExist) {
@@ -136,6 +149,12 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
               IsError(net::ERR_NAME_NOT_RESOLVED));
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram,
+                                 -net::ERR_NAME_NOT_RESOLVED, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNXDOMAIN, 1);
+  histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 TEST_P(LogDnsClientTest,
@@ -146,6 +165,12 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
               IsError(net::ERR_DNS_SERVER_FAILED));
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram,
+                                 -net::ERR_DNS_SERVER_FAILED, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeSERVFAIL, 1);
+  histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 TEST_P(LogDnsClientTest,
@@ -156,76 +181,44 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
               IsError(net::ERR_DNS_SERVER_FAILED));
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram,
+                                 -net::ERR_DNS_SERVER_FAILED, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeREFUSED, 1);
+  histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
-TEST_P(
-    LogDnsClientTest,
-    QueryAuditProofReportsMalformedResponseIfLeafIndexResponseContainsNoStrings) {
-  ASSERT_TRUE(mock_dns_.ExpectRequestAndResponse(
-      kLeafIndexQnames[0], std::vector<base::StringPiece>()));
+TEST_P(LogDnsClientTest, QueryAuditProofReportsMalformedLeafIndexResponse) {
+  const struct {
+    std::string name;
+    std::vector<base::StringPiece> txt_strings;
+  } tests[] = {{"contains no strings", {}},
+               {"contains more than one string", {"123456", "7"}},
+               {"is not numeric", {"foo"}},
+               {"is floating point", {"123456.0"}},
+               {"is empty"},
+               {"has non-numeric prefix", {"foo123456"}},
+               {"has non-numeric suffix", {"123456foo"}}};
 
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
-}
+  for (auto test : tests) {
+    SCOPED_TRACE(test.name);
+    base::HistogramTester histograms;
 
-TEST_P(
-    LogDnsClientTest,
-    QueryAuditProofReportsMalformedResponseIfLeafIndexResponseContainsMoreThanOneString) {
-  ASSERT_TRUE(
-      mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0], {"123456", "7"}));
+    ASSERT_TRUE(mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0],
+                                                   test.txt_strings));
 
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
-}
-
-TEST_P(LogDnsClientTest,
-       QueryAuditProofReportsMalformedResponseIfLeafIndexIsNotNumeric) {
-  ASSERT_TRUE(mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0], {"foo"}));
-
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
-}
-
-TEST_P(LogDnsClientTest,
-       QueryAuditProofReportsMalformedResponseIfLeafIndexIsFloatingPoint) {
-  ASSERT_TRUE(
-      mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0], {"123456.0"}));
-
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
-}
-
-TEST_P(LogDnsClientTest,
-       QueryAuditProofReportsMalformedResponseIfLeafIndexIsEmpty) {
-  ASSERT_TRUE(mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0], {""}));
-
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
-}
-
-TEST_P(LogDnsClientTest,
-       QueryAuditProofReportsMalformedResponseIfLeafIndexHasNonNumericPrefix) {
-  ASSERT_TRUE(
-      mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0], {"foo123456"}));
-
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
-}
-
-TEST_P(LogDnsClientTest,
-       QueryAuditProofReportsMalformedResponseIfLeafIndexHasNonNumericSuffix) {
-  ASSERT_TRUE(
-      mock_dns_.ExpectRequestAndResponse(kLeafIndexQnames[0], {"123456foo"}));
-
-  std::unique_ptr<LogDnsClient::AuditProofQuery> query;
-  ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
-              IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+    std::unique_ptr<LogDnsClient::AuditProofQuery> query;
+    ASSERT_THAT(
+        QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
+        IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+    histograms.ExpectUniqueSample(kLeafIndexErrorHistogram,
+                                  -net::ERR_DNS_MALFORMED_RESPONSE, 1);
+    histograms.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                  net::dns_protocol::kRcodeNOERROR, 1);
+    histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+    histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
+  }
 }
 
 TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsEmpty) {
@@ -254,6 +247,11 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
               IsError(net::ERR_CONNECTION_REFUSED));
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram,
+                                 -net::ERR_CONNECTION_REFUSED, 1);
+  histograms_.ExpectTotalCount(kLeafIndexRcodeHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 TEST_P(LogDnsClientTest,
@@ -263,6 +261,11 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], kTreeSizes[0], &query),
               IsError(net::ERR_DNS_TIMED_OUT));
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram,
+                                 -net::ERR_DNS_TIMED_OUT, 1);
+  histograms_.ExpectTotalCount(kLeafIndexRcodeHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 TEST_P(LogDnsClientTest, QueryAuditProof) {
@@ -291,6 +294,13 @@
   EXPECT_THAT(proof.leaf_index, Eq(123456u));
   EXPECT_THAT(proof.tree_size, Eq(999999u));
   EXPECT_THAT(proof.nodes, Eq(audit_proof));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(LogDnsClientTest, QueryAuditProofHandlesResponsesWithShortAuditPaths) {
@@ -327,6 +337,13 @@
   EXPECT_THAT(proof.leaf_index, Eq(123456u));
   EXPECT_THAT(proof.tree_size, Eq(999999u));
   EXPECT_THAT(proof.nodes, Eq(audit_proof));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(LogDnsClientTest,
@@ -339,6 +356,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_NAME_NOT_RESOLVED));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_NAME_NOT_RESOLVED, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNXDOMAIN, 1);
 }
 
 TEST_P(LogDnsClientTest,
@@ -351,6 +376,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_SERVER_FAILED));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_SERVER_FAILED, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeSERVFAIL, 1);
 }
 
 TEST_P(LogDnsClientTest,
@@ -363,6 +396,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_SERVER_FAILED));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_SERVER_FAILED, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeREFUSED, 1);
 }
 
 TEST_P(
@@ -378,6 +419,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_MALFORMED_RESPONSE, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(
@@ -403,6 +452,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_MALFORMED_RESPONSE, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(LogDnsClientTest,
@@ -418,6 +475,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_MALFORMED_RESPONSE, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfNodeTooLong) {
@@ -432,6 +497,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_MALFORMED_RESPONSE, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfEmpty) {
@@ -445,6 +518,14 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_MALFORMED_RESPONSE, 1);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
 }
 
 TEST_P(LogDnsClientTest,
@@ -477,6 +558,13 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_CONNECTION_REFUSED));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_CONNECTION_REFUSED, 1);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 TEST_P(LogDnsClientTest,
@@ -489,6 +577,13 @@
   std::unique_ptr<LogDnsClient::AuditProofQuery> query;
   ASSERT_THAT(QueryAuditProof("ct.test", kLeafHashes[0], 999999, &query),
               IsError(net::ERR_DNS_TIMED_OUT));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 1);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 1);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram,
+                                 -net::ERR_DNS_TIMED_OUT, 1);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 TEST_P(LogDnsClientTest, AdoptsLatestDnsConfigIfValid) {
@@ -657,6 +752,13 @@
     EXPECT_THAT(proof.tree_size, Eq(kTreeSizes[i]));
     EXPECT_THAT(proof.nodes, Eq(audit_proofs[i]));
   }
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 3);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 3);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram, -net::OK, 3);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 3);
 }
 
 TEST_P(LogDnsClientTest, CanBeThrottledToOneQueryAtATime) {
@@ -732,6 +834,13 @@
   EXPECT_THAT(proof3.leaf_index, Eq(666u));
   EXPECT_THAT(proof3.tree_size, Eq(999999u));
   EXPECT_THAT(proof3.nodes, Eq(audit_proof));
+
+  histograms_.ExpectUniqueSample(kLeafIndexErrorHistogram, -net::OK, 2);
+  histograms_.ExpectUniqueSample(kLeafIndexRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 2);
+  histograms_.ExpectUniqueSample(kAuditProofErrorHistogram, -net::OK, 2);
+  histograms_.ExpectUniqueSample(kAuditProofRcodeHistogram,
+                                 net::dns_protocol::kRcodeNOERROR, 2);
 }
 
 TEST_P(LogDnsClientTest, NotifiesWhenNoLongerThrottled) {
@@ -815,6 +924,11 @@
   // Give |callback| a chance to run - it shouldn't though.
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(callback.have_result());
+
+  histograms_.ExpectTotalCount(kLeafIndexErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kLeafIndexRcodeHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofErrorHistogram, 0);
+  histograms_.ExpectTotalCount(kAuditProofRcodeHistogram, 0);
 }
 
 INSTANTIATE_TEST_CASE_P(ReadMode,
diff --git a/components/crash/android/OWNERS b/components/crash/android/OWNERS
index 1c0302aa..02ccd6e 100644
--- a/components/crash/android/OWNERS
+++ b/components/crash/android/OWNERS
@@ -1,4 +1,3 @@
-gsennton@chromium.org
 isherman@chromium.org
 
 # COMPONENT: Internals>CrashReporting
diff --git a/components/cronet/cronet_prefs_manager.cc b/components/cronet/cronet_prefs_manager.cc
index 85316c2..828cbd9 100644
--- a/components/cronet/cronet_prefs_manager.cc
+++ b/components/cronet/cronet_prefs_manager.cc
@@ -232,8 +232,8 @@
   base::FilePath filepath =
       storage_file_path.Append(kPrefsDirectoryName).Append(kPrefsFileName);
 
-  json_pref_store_ = new JsonPrefStore(filepath, file_task_runner,
-                                       std::unique_ptr<PrefFilter>());
+  json_pref_store_ = new JsonPrefStore(filepath, std::unique_ptr<PrefFilter>(),
+                                       file_task_runner);
 
   // Register prefs and set up the PrefService.
   PrefServiceFactory factory;
diff --git a/components/cryptauth/DEPS b/components/cryptauth/DEPS
index 2193bca9..1e6af80 100644
--- a/components/cryptauth/DEPS
+++ b/components/cryptauth/DEPS
@@ -13,5 +13,7 @@
   "+google_apis",
   "+net",
   "+services/identity/public/cpp",
+  "+services/network/public/cpp",
+  "+services/network/test",
   "+third_party/cros_system_api/dbus/service_constants.h",
 ]
diff --git a/components/cryptauth/cryptauth_api_call_flow.cc b/components/cryptauth/cryptauth_api_call_flow.cc
index 4f6f17cb..eb5cf00 100644
--- a/components/cryptauth/cryptauth_api_call_flow.cc
+++ b/components/cryptauth/cryptauth_api_call_flow.cc
@@ -8,12 +8,14 @@
 #include "base/strings/string_number_conversions.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace cryptauth {
 
 namespace {
 
+const char kPost[] = "POST";
+
 NetworkRequestError GetErrorForHttpResponseCode(int response_code) {
   if (response_code == 400)
     return NetworkRequestError::kBadRequest;
@@ -38,17 +40,18 @@
 CryptAuthApiCallFlow::~CryptAuthApiCallFlow() {
 }
 
-void CryptAuthApiCallFlow::Start(const GURL& request_url,
-                                 net::URLRequestContextGetter* context,
-                                 const std::string& access_token,
-                                 const std::string& serialized_request,
-                                 const ResultCallback& result_callback,
-                                 const ErrorCallback& error_callback) {
+void CryptAuthApiCallFlow::Start(
+    const GURL& request_url,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    const std::string& access_token,
+    const std::string& serialized_request,
+    const ResultCallback& result_callback,
+    const ErrorCallback& error_callback) {
   request_url_ = request_url;
   serialized_request_ = serialized_request;
   result_callback_ = result_callback;
   error_callback_ = error_callback;
-  OAuth2ApiCallFlow::Start(context, access_token);
+  OAuth2ApiCallFlow::Start(std::move(url_loader_factory), access_token);
 }
 
 GURL CryptAuthApiCallFlow::CreateApiCallUrl() {
@@ -63,33 +66,42 @@
   return "application/x-protobuf";
 }
 
-net::URLFetcher::RequestType CryptAuthApiCallFlow::GetRequestTypeForBody(
+std::string CryptAuthApiCallFlow::GetRequestTypeForBody(
     const std::string& body) {
-  return net::URLFetcher::POST;
+  return kPost;
 }
 
 void CryptAuthApiCallFlow::ProcessApiCallSuccess(
-    const net::URLFetcher* source) {
-  std::string serialized_response;
-  if (!source->GetResponseAsString(&serialized_response)) {
+    const network::ResourceResponseHead* head,
+    std::unique_ptr<std::string> body) {
+  if (!body) {
     error_callback_.Run(NetworkRequestError::kResponseMalformed);
     return;
   }
-  result_callback_.Run(serialized_response);
+  result_callback_.Run(std::move(*body));
 }
 
 void CryptAuthApiCallFlow::ProcessApiCallFailure(
-    const net::URLFetcher* source) {
+    int net_error,
+    const network::ResourceResponseHead* head,
+    std::unique_ptr<std::string> body) {
   base::Optional<NetworkRequestError> error;
-  if (source->GetStatus().status() == net::URLRequestStatus::SUCCESS) {
-    error = GetErrorForHttpResponseCode(source->GetResponseCode());
+  std::string error_message;
+  if (net_error == net::OK) {
+    int response_code = -1;
+    if (head && head->headers)
+      response_code = head->headers->response_code();
+    error = GetErrorForHttpResponseCode(response_code);
   } else {
     error = NetworkRequestError::kOffline;
   }
 
-  std::string response;
-  source->GetResponseAsString(&response);
-  PA_LOG(INFO) << "API call failed:\n" << response;
+  if (body) {
+    PA_LOG(INFO) << "API call failed:\n" << *body;
+  } else {
+    PA_LOG(INFO) << "API call failed, no response body available, net_error:"
+                 << net_error;
+  }
   error_callback_.Run(*error);
 }
 
diff --git a/components/cryptauth/cryptauth_api_call_flow.h b/components/cryptauth/cryptauth_api_call_flow.h
index 1afe771b..521d64cd 100644
--- a/components/cryptauth/cryptauth_api_call_flow.h
+++ b/components/cryptauth/cryptauth_api_call_flow.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "components/cryptauth/network_request_error.h"
 #include "google_apis/gaia/oauth2_api_call_flow.h"
+#include "services/network/public/cpp/resource_response.h"
 
 namespace cryptauth {
 
@@ -34,12 +35,13 @@
   //   result_callback: Called when the flow completes successfully with a
   //       serialized response proto.
   //   error_callback: Called when the flow completes with an error.
-  virtual void Start(const GURL& request_url,
-                     net::URLRequestContextGetter* context,
-                     const std::string& access_token,
-                     const std::string& serialized_request,
-                     const ResultCallback& result_callback,
-                     const ErrorCallback& error_callback);
+  virtual void Start(
+      const GURL& request_url,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& access_token,
+      const std::string& serialized_request,
+      const ResultCallback& result_callback,
+      const ErrorCallback& error_callback);
 
   void SetPartialNetworkTrafficAnnotation(
       const net::PartialNetworkTrafficAnnotationTag&
@@ -58,10 +60,12 @@
   GURL CreateApiCallUrl() override;
   std::string CreateApiCallBody() override;
   std::string CreateApiCallBodyContentType() override;
-  net::URLFetcher::RequestType GetRequestTypeForBody(
-      const std::string& body) override;
-  void ProcessApiCallSuccess(const net::URLFetcher* source) override;
-  void ProcessApiCallFailure(const net::URLFetcher* source) override;
+  std::string GetRequestTypeForBody(const std::string& body) override;
+  void ProcessApiCallSuccess(const network::ResourceResponseHead* head,
+                             std::unique_ptr<std::string> body) override;
+  void ProcessApiCallFailure(int net_error,
+                             const network::ResourceResponseHead* head,
+                             std::unique_ptr<std::string> body) override;
   net::PartialNetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag()
       override;
 
diff --git a/components/cryptauth/cryptauth_api_call_flow_unittest.cc b/components/cryptauth/cryptauth_api_call_flow_unittest.cc
index 68941aca..ffb543a2 100644
--- a/components/cryptauth/cryptauth_api_call_flow_unittest.cc
+++ b/components/cryptauth/cryptauth_api_call_flow_unittest.cc
@@ -7,12 +7,13 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/cryptauth/network_request_error.h"
 #include "net/base/net_errors.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cryptauth {
@@ -25,58 +26,51 @@
 
 }  // namespace
 
-class CryptAuthApiCallFlowTest
-    : public testing::Test,
-      public net::TestURLFetcherDelegateForTests {
+class CryptAuthApiCallFlowTest : public testing::Test {
  protected:
   CryptAuthApiCallFlowTest()
-      : url_request_context_getter_(new net::TestURLRequestContextGetter(
-            new base::TestSimpleTaskRunner())) {
+      : shared_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {
     flow_.SetPartialNetworkTrafficAnnotation(
         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   }
 
-  void SetUp() override {
-    // The TestURLFetcherFactory will override the global URLFetcherFactory for
-    // the entire test.
-    url_fetcher_factory_.reset(new net::TestURLFetcherFactory());
-    url_fetcher_factory_->SetDelegateForTests(this);
-  }
-
   void StartApiCallFlow() {
     StartApiCallFlowWithRequest(kSerializedRequestProto);
   }
 
   void StartApiCallFlowWithRequest(const std::string& serialized_request) {
-    flow_.Start(GURL(kRequestUrl), url_request_context_getter_.get(),
-                "access_token", serialized_request,
-                base::Bind(&CryptAuthApiCallFlowTest::OnResult,
-                           base::Unretained(this)),
-                base::Bind(&CryptAuthApiCallFlowTest::OnError,
-                           base::Unretained(this)));
-    // URLFetcher object for the API request should be created.
+    flow_.Start(
+        GURL(kRequestUrl), shared_factory_, "access_token", serialized_request,
+        base::Bind(&CryptAuthApiCallFlowTest::OnResult, base::Unretained(this)),
+        base::Bind(&CryptAuthApiCallFlowTest::OnError, base::Unretained(this)));
+    // A pending fetch for the API request should be created.
     CheckCryptAuthHttpRequest(serialized_request);
   }
 
   void OnResult(const std::string& result) {
-    EXPECT_FALSE(result_);
+    EXPECT_FALSE(result_ || network_error_);
     result_.reset(new std::string(result));
   }
 
   void OnError(NetworkRequestError network_error) {
-    EXPECT_FALSE(network_error_);
+    EXPECT_FALSE(result_ || network_error_);
     network_error_.reset(new NetworkRequestError(network_error));
   }
 
   void CheckCryptAuthHttpRequest(const std::string& serialized_request) {
-    ASSERT_TRUE(url_fetcher_);
-    EXPECT_EQ(GURL(kRequestUrl), url_fetcher_->GetOriginalURL());
-    EXPECT_EQ(serialized_request, url_fetcher_->upload_data());
+    const std::vector<network::TestURLLoaderFactory::PendingRequest>& pending =
+        *test_url_loader_factory_.pending_requests();
+    ASSERT_EQ(1u, pending.size());
+    const network::ResourceRequest& request = pending[0].request;
+    EXPECT_EQ(GURL(kRequestUrl), request.url);
+    EXPECT_EQ(serialized_request, network::GetUploadData(request));
 
-    net::HttpRequestHeaders request_headers;
-    url_fetcher_->GetExtraRequestHeaders(&request_headers);
-
-    EXPECT_EQ("application/x-protobuf", url_fetcher_->upload_content_type());
+    std::string content_type;
+    EXPECT_TRUE(request.headers.GetHeader(net::HttpRequestHeaders::kContentType,
+                                          &content_type));
+    EXPECT_EQ("application/x-protobuf", content_type);
   }
 
   // Responds to the current HTTP request. If the |error| is not |net::OK|, then
@@ -84,33 +78,28 @@
   void CompleteCurrentRequest(net::Error error,
                               int response_code,
                               const std::string& response_string) {
-    ASSERT_TRUE(url_fetcher_);
-    net::TestURLFetcher* url_fetcher = url_fetcher_;
-    url_fetcher_ = nullptr;
-    url_fetcher->set_status(net::URLRequestStatus::FromError(error));
+    network::URLLoaderCompletionStatus completion_status(error);
+    network::ResourceResponseHead response_head;
+    std::string content;
     if (error == net::OK) {
-      url_fetcher->set_response_code(response_code);
-      url_fetcher->SetResponseString(response_string);
+      response_head = network::CreateResourceResponseHead(
+          static_cast<net::HttpStatusCode>(response_code));
+      content = response_string;
     }
-    url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
+    EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
+        GURL(kRequestUrl), completion_status, response_head, content));
+    scoped_task_environment_.RunUntilIdle();
+    EXPECT_TRUE(result_ || network_error_);
   }
 
-  // net::TestURLFetcherDelegateForTests overrides.
-  void OnRequestStart(int fetcher_id) override {
-    url_fetcher_ = url_fetcher_factory_->GetFetcherByID(fetcher_id);
-  }
-
-  void OnChunkUpload(int fetcher_id) override {}
-
-  void OnRequestEnd(int fetcher_id) override {}
-
-  net::TestURLFetcher* url_fetcher_;
   std::unique_ptr<std::string> result_;
   std::unique_ptr<NetworkRequestError> network_error_;
 
  private:
-  scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_;
-  std::unique_ptr<net::TestURLFetcherFactory> url_fetcher_factory_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
+
   CryptAuthApiCallFlow flow_;
 
   DISALLOW_COPY_AND_ASSIGN(CryptAuthApiCallFlowTest);
diff --git a/components/cryptauth/cryptauth_client_impl.cc b/components/cryptauth/cryptauth_client_impl.cc
index 5ab24f1..14621f1 100644
--- a/components/cryptauth/cryptauth_client_impl.cc
+++ b/components/cryptauth/cryptauth_client_impl.cc
@@ -14,6 +14,7 @@
 #include "components/cryptauth/switches.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace cryptauth {
 
@@ -56,11 +57,11 @@
 CryptAuthClientImpl::CryptAuthClientImpl(
     std::unique_ptr<CryptAuthApiCallFlow> api_call_flow,
     identity::IdentityManager* identity_manager,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const DeviceClassifier& device_classifier)
     : api_call_flow_(std::move(api_call_flow)),
       identity_manager_(identity_manager),
-      url_request_context_(url_request_context),
+      url_loader_factory_(std::move(url_loader_factory)),
       device_classifier_(device_classifier),
       has_call_started_(false),
       weak_ptr_factory_(this) {}
@@ -310,8 +311,8 @@
   access_token_used_ = access_token_info.token;
 
   api_call_flow_->Start(
-      CreateRequestUrl(request_path_), url_request_context_.get(),
-      access_token_used_, serialized_request,
+      CreateRequestUrl(request_path_), url_loader_factory_, access_token_used_,
+      serialized_request,
       base::Bind(&CryptAuthClientImpl::OnFlowSuccess<ResponseProto>,
                  weak_ptr_factory_.GetWeakPtr(), response_callback),
       base::Bind(&CryptAuthClientImpl::OnApiCallFailed,
@@ -337,10 +338,10 @@
 // CryptAuthClientFactoryImpl
 CryptAuthClientFactoryImpl::CryptAuthClientFactoryImpl(
     identity::IdentityManager* identity_manager,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const DeviceClassifier& device_classifier)
     : identity_manager_(identity_manager),
-      url_request_context_(url_request_context),
+      url_loader_factory_(std::move(url_loader_factory)),
       device_classifier_(device_classifier) {}
 
 CryptAuthClientFactoryImpl::~CryptAuthClientFactoryImpl() {
@@ -349,7 +350,7 @@
 std::unique_ptr<CryptAuthClient> CryptAuthClientFactoryImpl::CreateInstance() {
   return std::make_unique<CryptAuthClientImpl>(
       base::WrapUnique(new CryptAuthApiCallFlow()), identity_manager_,
-      url_request_context_, device_classifier_);
+      url_loader_factory_, device_classifier_);
 }
 
 }  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_client_impl.h b/components/cryptauth/cryptauth_client_impl.h
index fe5902a2..71e57be5 100644
--- a/components/cryptauth/cryptauth_client_impl.h
+++ b/components/cryptauth/cryptauth_client_impl.h
@@ -11,13 +11,17 @@
 #include "components/cryptauth/cryptauth_client.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/identity/public/cpp/access_token_info.h"
 
 namespace identity {
 class IdentityManager;
 class PrimaryAccountAccessTokenFetcher;
 }  // namespace identity
+
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
 class GoogleServiceAuthError;
 
 namespace cryptauth {
@@ -33,7 +37,7 @@
   CryptAuthClientImpl(
       std::unique_ptr<CryptAuthApiCallFlow> api_call_flow,
       identity::IdentityManager* identity_manager,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const DeviceClassifier& device_classifier);
   ~CryptAuthClientImpl() override;
 
@@ -108,7 +112,7 @@
       access_token_fetcher_;
 
   // The context for network requests.
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   // Contains basic device info of the client making the request that is sent to
   // CryptAuth with each API call.
@@ -141,7 +145,7 @@
   // |device_classifier|: Contains basic device information of the client.
   CryptAuthClientFactoryImpl(
       identity::IdentityManager* identity_manager,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const DeviceClassifier& device_classifier);
   ~CryptAuthClientFactoryImpl() override;
 
@@ -150,7 +154,7 @@
 
  private:
   identity::IdentityManager* identity_manager_;
-  const scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+  const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   const DeviceClassifier device_classifier_;
 
   DISALLOW_COPY_AND_ASSIGN(CryptAuthClientFactoryImpl);
diff --git a/components/cryptauth/cryptauth_client_impl_unittest.cc b/components/cryptauth/cryptauth_client_impl_unittest.cc
index caa24bcb2..180710e0 100644
--- a/components/cryptauth/cryptauth_client_impl_unittest.cc
+++ b/components/cryptauth/cryptauth_client_impl_unittest.cc
@@ -14,9 +14,8 @@
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "components/cryptauth/switches.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/identity/public/cpp/identity_test_environment.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -53,13 +52,14 @@
   }
   virtual ~MockCryptAuthApiCallFlow() {}
 
-  MOCK_METHOD6(Start,
-               void(const GURL&,
-                    net::URLRequestContextGetter* context,
-                    const std::string& access_token,
-                    const std::string& serialized_request,
-                    const ResultCallback& result_callback,
-                    const ErrorCallback& error_callback));
+  MOCK_METHOD6(
+      Start,
+      void(const GURL&,
+           scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+           const std::string& access_token,
+           const std::string& serialized_request,
+           const ResultCallback& result_callback,
+           const ErrorCallback& error_callback));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockCryptAuthApiCallFlow);
@@ -95,9 +95,14 @@
  protected:
   CryptAuthClientTest()
       : api_call_flow_(new StrictMock<MockCryptAuthApiCallFlow>()),
-        url_request_context_(
-            new net::TestURLRequestContextGetter(new base::NullTaskRunner())),
-        serialized_request_(std::string()) {}
+        serialized_request_(std::string()) {
+    shared_factory_ =
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            base::BindOnce([]() -> network::mojom::URLLoaderFactory* {
+              ADD_FAILURE() << "Did not expect this to actually be used";
+              return nullptr;
+            }));
+  }
 
   void SetUp() override {
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -115,7 +120,7 @@
     client_.reset(
         new CryptAuthClientImpl(base::WrapUnique(api_call_flow_),
                                 identity_test_environment_.identity_manager(),
-                                url_request_context_, device_classifier));
+                                shared_factory_, device_classifier));
   }
 
   // Sets up an expectation and captures a CryptAuth API request to
@@ -123,7 +128,7 @@
   void ExpectRequest(const std::string& request_url) {
     GURL url(request_url);
     EXPECT_CALL(*api_call_flow_,
-                Start(url, url_request_context_.get(), kAccessToken, _, _, _))
+                Start(url, shared_factory_, kAccessToken, _, _, _))
         .WillOnce(DoAll(SaveArg<3>(&serialized_request_),
                         SaveArg<4>(&flow_result_callback_),
                         SaveArg<5>(&flow_error_callback_)));
@@ -147,7 +152,8 @@
   // Owned by |client_|.
   StrictMock<MockCryptAuthApiCallFlow>* api_call_flow_;
 
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
+
   std::unique_ptr<CryptAuthClient> client_;
 
   std::string serialized_request_;
diff --git a/components/download/database/BUILD.gn b/components/download/database/BUILD.gn
index 946d154..cbbe97f1 100644
--- a/components/download/database/BUILD.gn
+++ b/components/download/database/BUILD.gn
@@ -30,8 +30,6 @@
     "in_progress/in_progress_info.h",
     "in_progress/ukm_info.cc",
     "in_progress/ukm_info.h",
-    "switches.cc",
-    "switches.h",
   ]
 
   deps = [
diff --git a/components/download/database/download_db.cc b/components/download/database/download_db.cc
index b54602f..12b7ec5 100644
--- a/components/download/database/download_db.cc
+++ b/components/download/database/download_db.cc
@@ -13,14 +13,16 @@
 
 DownloadDB::~DownloadDB() = default;
 
-void DownloadDB::Initialize(InitializeCallback callback) {
+void DownloadDB::Initialize(DownloadDBCallback callback) {
   std::move(callback).Run(true);
 }
 
 void DownloadDB::AddOrReplace(const DownloadDBEntry& entry) {}
 
-void DownloadDB::AddOrReplaceEntries(
-    const std::vector<DownloadDBEntry>& entry) {}
+void DownloadDB::AddOrReplaceEntries(const std::vector<DownloadDBEntry>& entry,
+                                     DownloadDBCallback callback) {
+  std::move(callback).Run(true);
+}
 
 void DownloadDB::LoadEntries(LoadEntriesCallback callback) {
   std::move(callback).Run(true,
diff --git a/components/download/database/download_db.h b/components/download/database/download_db.h
index 77fdd53..6b11d98e 100644
--- a/components/download/database/download_db.h
+++ b/components/download/database/download_db.h
@@ -23,19 +23,20 @@
   using LoadEntriesCallback = base::OnceCallback<void(
       bool success,
       std::unique_ptr<std::vector<DownloadDBEntry>> entries)>;
-  using InitializeCallback = base::OnceCallback<void(bool success)>;
+  using DownloadDBCallback = base::OnceCallback<void(bool success)>;
 
   DownloadDB();
   virtual ~DownloadDB();
 
   // Initializes this db asynchronously, callback will be run on completion.
-  virtual void Initialize(InitializeCallback callback);
+  virtual void Initialize(DownloadDBCallback callback);
 
   // Adds or updates |entry| in the storage.
   virtual void AddOrReplace(const DownloadDBEntry& entry);
 
   // Adds or updates multiple entries in the storage.
-  virtual void AddOrReplaceEntries(const std::vector<DownloadDBEntry>& entry);
+  virtual void AddOrReplaceEntries(const std::vector<DownloadDBEntry>& entry,
+                                   DownloadDBCallback callback);
 
   // Retrieves all entries with the given |download_namespace|.
   virtual void LoadEntries(LoadEntriesCallback callback);
diff --git a/components/download/database/download_db_impl.cc b/components/download/database/download_db_impl.cc
index 4db1658a..b52ccc3 100644
--- a/components/download/database/download_db_impl.cc
+++ b/components/download/database/download_db_impl.cc
@@ -38,6 +38,12 @@
                           base::CompareCase::INSENSITIVE_ASCII);
 }
 
+void OnUpdateDone(bool success) {
+  // TODO(qinmin): add UMA for this.
+  if (!success)
+    LOG(ERROR) << "Update Download DB failed.";
+}
+
 }  // namespace
 
 DownloadDBImpl::DownloadDBImpl(DownloadNamespace download_namespace,
@@ -69,7 +75,7 @@
   return is_initialized_;
 }
 
-void DownloadDBImpl::Initialize(InitializeCallback callback) {
+void DownloadDBImpl::Initialize(DownloadDBCallback callback) {
   DCHECK(!IsInitialized());
 
   // These options reduce memory consumption.
@@ -82,18 +88,20 @@
   // TODO(qinmin): migrate all the data from InProgressCache into this database.
 }
 
-void DownloadDBImpl::DestroyAndReinitialize(InitializeCallback callback) {
+void DownloadDBImpl::DestroyAndReinitialize(DownloadDBCallback callback) {
   is_initialized_ = false;
   db_->Destroy(base::BindOnce(&DownloadDBImpl::OnDatabaseDestroyed,
                               weak_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void DownloadDBImpl::AddOrReplace(const DownloadDBEntry& entry) {
-  AddOrReplaceEntries(std::vector<DownloadDBEntry>{entry});
+  AddOrReplaceEntries(std::vector<DownloadDBEntry>{entry},
+                      base::BindOnce(&OnUpdateDone));
 }
 
 void DownloadDBImpl::AddOrReplaceEntries(
-    const std::vector<DownloadDBEntry>& entries) {
+    const std::vector<DownloadDBEntry>& entries,
+    DownloadDBCallback callback) {
   DCHECK(IsInitialized());
   auto entries_to_save = std::make_unique<ProtoKeyEntryVector>();
   for (const auto& entry : entries) {
@@ -103,9 +111,7 @@
                                   std::move(proto));
   }
   db_->UpdateEntries(std::move(entries_to_save),
-                     std::make_unique<ProtoKeyVector>(),
-                     base::BindOnce(&DownloadDBImpl::OnUpdateDone,
-                                    weak_factory_.GetWeakPtr()));
+                     std::make_unique<ProtoKeyVector>(), std::move(callback));
 }
 
 void DownloadDBImpl::LoadEntries(LoadEntriesCallback callback) {
@@ -146,7 +152,7 @@
   std::move(callback).Run(success, std::move(result));
 }
 
-void DownloadDBImpl::OnDatabaseInitialized(InitializeCallback callback,
+void DownloadDBImpl::OnDatabaseInitialized(DownloadDBCallback callback,
                                            bool success) {
   if (!success) {
     DestroyAndReinitialize(std::move(callback));
@@ -156,7 +162,7 @@
   std::move(callback).Run(success);
 }
 
-void DownloadDBImpl::OnDatabaseDestroyed(InitializeCallback callback,
+void DownloadDBImpl::OnDatabaseDestroyed(DownloadDBCallback callback,
                                          bool success) {
   if (!success) {
     std::move(callback).Run(success);
@@ -170,12 +176,6 @@
     Initialize(std::move(callback));
 }
 
-void DownloadDBImpl::OnUpdateDone(bool success) {
-  // TODO(qinmin): add UMA for this.
-  if (!success)
-    LOG(ERROR) << "Update Download DB failed.";
-}
-
 void DownloadDBImpl::OnRemoveDone(bool success) {
   // TODO(qinmin): add UMA for this.
   if (!success)
diff --git a/components/download/database/download_db_impl.h b/components/download/database/download_db_impl.h
index 6da126e4..39e6eea 100644
--- a/components/download/database/download_db_impl.h
+++ b/components/download/database/download_db_impl.h
@@ -33,10 +33,10 @@
   ~DownloadDBImpl() override;
 
   // DownloadDB implementation.
-  void Initialize(InitializeCallback callback) override;
+  void Initialize(DownloadDBCallback callback) override;
   void AddOrReplace(const DownloadDBEntry& entry) override;
-  void AddOrReplaceEntries(
-      const std::vector<DownloadDBEntry>& entries) override;
+  void AddOrReplaceEntries(const std::vector<DownloadDBEntry>& entries,
+                           DownloadDBCallback callback) override;
   void LoadEntries(LoadEntriesCallback callback) override;
   void Remove(const std::string& guid) override;
 
@@ -45,19 +45,16 @@
 
   bool IsInitialized();
 
-  void DestroyAndReinitialize(InitializeCallback callback);
+  void DestroyAndReinitialize(DownloadDBCallback callback);
 
   // Returns the key of the db entry.
   std::string GetEntryKey(const std::string& guid) const;
 
   // Called when database is initialized.
-  void OnDatabaseInitialized(InitializeCallback callback, bool success);
+  void OnDatabaseInitialized(DownloadDBCallback callback, bool success);
 
   // Called when database is destroyed.
-  void OnDatabaseDestroyed(InitializeCallback callback, bool success);
-
-  // Called when entry is updated.
-  void OnUpdateDone(bool success);
+  void OnDatabaseDestroyed(DownloadDBCallback callback, bool success);
 
   // Called when entry is removed.
   void OnRemoveDone(bool success);
diff --git a/components/download/database/in_progress/in_progress_cache.h b/components/download/database/in_progress/in_progress_cache.h
index ddd67e49..0c6dc7a 100644
--- a/components/download/database/in_progress/in_progress_cache.h
+++ b/components/download/database/in_progress/in_progress_cache.h
@@ -38,6 +38,9 @@
 
   // Returns all entries.
   virtual std::vector<DownloadEntry> GetAllEntries() = 0;
+
+  // Destroys the file associated with the object.
+  virtual void Destroy() = 0;
 };
 
 }  // namespace download
diff --git a/components/download/database/in_progress/in_progress_cache_impl.cc b/components/download/database/in_progress/in_progress_cache_impl.cc
index a5e2dd98..775fc2fe 100644
--- a/components/download/database/in_progress/in_progress_cache_impl.cc
+++ b/components/download/database/in_progress/in_progress_cache_impl.cc
@@ -125,6 +125,16 @@
                << file_path.value();
   }
 }
+
+void DeleteFile(base::FilePath file_path) {
+  if (file_path.empty())
+    return;
+
+  if (!base::DeleteFile(file_path, false)) {
+    LOG(ERROR) << "Could not delete download cache file: " << file_path.value();
+  }
+}
+
 }  // namespace
 
 InProgressCacheImpl::InProgressCacheImpl(
@@ -220,4 +230,8 @@
   return DownloadDBConversions::DownloadEntriesFromProto(entries_);
 }
 
+void InProgressCacheImpl::Destroy() {
+  task_runner_->PostTask(FROM_HERE, base::BindOnce(&DeleteFile, file_path_));
+}
+
 }  // namespace download
diff --git a/components/download/database/in_progress/in_progress_cache_impl.h b/components/download/database/in_progress/in_progress_cache_impl.h
index 64503c9e..a21279e 100644
--- a/components/download/database/in_progress/in_progress_cache_impl.h
+++ b/components/download/database/in_progress/in_progress_cache_impl.h
@@ -34,6 +34,7 @@
   base::Optional<DownloadEntry> RetrieveEntry(const std::string& guid) override;
   void RemoveEntry(const std::string& guid) override;
   std::vector<DownloadEntry> GetAllEntries() override;
+  void Destroy() override;
 
  private:
   // States to keep track of initialization status.
diff --git a/components/download/database/switches.cc b/components/download/database/switches.cc
deleted file mode 100644
index 66416607..0000000
--- a/components/download/database/switches.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/download/database/switches.h"
-
-namespace download {
-
-namespace switches {
-
-// Enables using the default search engine country to show country specific
-// popular sites on the NTP.
-const char kEnableDownloadDB[] = "enable-download-db";
-
-}  // namespace switches
-
-}  // namespace download
diff --git a/components/download/database/switches.h b/components/download/database/switches.h
deleted file mode 100644
index 14ce4bd..0000000
--- a/components/download/database/switches.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOWNLOAD_DATABASE_SWITCHES_H_
-#define COMPONENTS_DOWNLOAD_DATABASE_SWITCHES_H_
-
-namespace download {
-
-namespace switches {
-
-// Enables the use of download database to store download metadata.
-extern const char kEnableDownloadDB[];
-
-}  // namespace switches
-
-}  // namespace download
-
-#endif  // COMPONENTS_DOWNLOAD_DATABASE_SWITCHES_H_
diff --git a/components/download/internal/common/download_db_cache.cc b/components/download/internal/common/download_db_cache.cc
index abc824bc..84d50b4 100644
--- a/components/download/internal/common/download_db_cache.cc
+++ b/components/download/internal/common/download_db_cache.cc
@@ -8,6 +8,8 @@
 #include "components/download/database/download_db_conversions.h"
 #include "components/download/database/download_db_entry.h"
 #include "components/download/database/in_progress/download_entry.h"
+#include "components/download/public/common/download_features.h"
+#include "components/download/public/common/download_stats.h"
 #include "components/download/public/common/download_utils.h"
 
 namespace download {
@@ -110,6 +112,12 @@
   }
 }
 
+void OnDownloadDBUpdated(bool success) {
+  // TODO(qinmin): handle the case that update fails.
+  if (!success)
+    LOG(ERROR) << "Unable to update DB entries";
+}
+
 }  // namespace
 
 DownloadDBCache::DownloadDBCache(std::unique_ptr<DownloadDB> download_db)
@@ -121,21 +129,22 @@
 
 DownloadDBCache::~DownloadDBCache() = default;
 
-void DownloadDBCache::Initialize(InitializeCallback callback) {
+void DownloadDBCache::Initialize(const std::vector<DownloadEntry>& entries,
+                                 InitializeCallback callback) {
   // TODO(qinmin): migrate all the data from InProgressCache into
   // |download_db_|.
   if (!initialized_) {
-    download_db_->Initialize(
-        base::BindOnce(&DownloadDBCache::OnDownloadDBInitialized,
-                       weak_factory_.GetWeakPtr(), std::move(callback)));
+    RecordInProgressDBCount(kInitializationCount);
+    download_db_->Initialize(base::BindOnce(
+        &DownloadDBCache::OnDownloadDBInitialized, weak_factory_.GetWeakPtr(),
+        entries, std::move(callback)));
     return;
   }
 
-  auto entries = std::make_unique<std::vector<DownloadDBEntry>>();
-  for (auto it = entries_.begin(); it != entries_.end(); ++it) {
-    entries->emplace_back(it->second);
-  }
-  std::move(callback).Run(std::move(entries));
+  auto db_entries = std::make_unique<std::vector<DownloadDBEntry>>();
+  for (auto it = entries_.begin(); it != entries_.end(); ++it)
+    db_entries->emplace_back(it->second);
+  std::move(callback).Run(true, std::move(db_entries));
 }
 
 base::Optional<DownloadDBEntry> DownloadDBCache::RetrieveEntry(
@@ -185,13 +194,26 @@
     DCHECK(entry);
     entries.emplace_back(entry.value());
   }
-  if (initialized_)
-    download_db_->AddOrReplaceEntries(entries);
+  if (initialized_) {
+    download_db_->AddOrReplaceEntries(entries,
+                                      base::BindOnce(&OnDownloadDBUpdated));
+  }
 }
 
 void DownloadDBCache::OnDownloadUpdated(DownloadItem* download) {
   // TODO(crbug.com/778425): Properly handle fail/resume/retry for downloads
   // that are in the INTERRUPTED state for a long time.
+  if (!base::FeatureList::IsEnabled(features::kDownloadDBForNewDownloads)) {
+    // If history service is still managing in-progress download, we can safely
+    // remove a download from the in-progress DB whenever it is completed or
+    // cancelled. Otherwise, we need to propagate the completed download to
+    // history service before we can remove it.
+    if (download->GetState() == DownloadItem::COMPLETE ||
+        download->GetState() == DownloadItem::CANCELLED) {
+      OnDownloadRemoved(download);
+      return;
+    }
+  }
   base::Optional<DownloadDBEntry> current = RetrieveEntry(download->GetGuid());
   bool fetch_error_body = GetFetchErrorBody(current);
   DownloadUrlParameters::RequestHeadersType request_header_type =
@@ -206,15 +228,20 @@
   RemoveEntry(download->GetGuid());
 }
 
-void DownloadDBCache::OnDownloadDBInitialized(InitializeCallback callback,
-                                              bool success) {
+void DownloadDBCache::OnDownloadDBInitialized(
+    const std::vector<DownloadEntry>& entries,
+    InitializeCallback callback,
+    bool success) {
   if (success) {
+    RecordInProgressDBCount(kInitializationSucceededCount);
+    MigrateFromInProgressCache(entries);
     download_db_->LoadEntries(
         base::BindOnce(&DownloadDBCache::OnDownloadDBEntriesLoaded,
                        weak_factory_.GetWeakPtr(), std::move(callback)));
   } else {
-    OnDownloadDBEntriesLoaded(std::move(callback), false,
-                              std::make_unique<std::vector<DownloadDBEntry>>());
+    RecordInProgressDBCount(kInitializationFailedCount);
+    std::move(callback).Run(false,
+                            std::make_unique<std::vector<DownloadDBEntry>>());
   }
 }
 
@@ -223,11 +250,12 @@
     bool success,
     std::unique_ptr<std::vector<DownloadDBEntry>> entries) {
   initialized_ = success;
+  RecordInProgressDBCount(success ? kLoadSucceededCount : kLoadFailedCount);
   for (auto& entry : *entries) {
     CleanUpInProgressEntry(entry);
     entries_[entry.download_info->guid] = entry;
   }
-  std::move(callback).Run(std::move(entries));
+  std::move(callback).Run(success, std::move(entries));
 }
 
 void DownloadDBCache::SetTimerTaskRunnerForTesting(
@@ -237,15 +265,23 @@
 
 void DownloadDBCache::MigrateFromInProgressCache(
     const std::vector<DownloadEntry>& entries) {
-  DCHECK(initialized_);
-  DCHECK(entries_.empty());
+  if (entries.empty())
+    return;
+  RecordInProgressDBCount(kCacheMigrationCount);
   std::vector<DownloadDBEntry> db_entries;
   for (const auto& entry : entries) {
-    entries_[entry.guid] =
-        DownloadDBConversions::DownloadDBEntryFromDownloadEntry(entry);
-    db_entries.emplace_back(entries_[entry.guid]);
+    DCHECK(entries_.find(entry.guid) == entries_.end());
+    db_entries.emplace_back(
+        DownloadDBConversions::DownloadDBEntryFromDownloadEntry(entry));
   }
-  download_db_->AddOrReplaceEntries(db_entries);
+  download_db_->AddOrReplaceEntries(
+      db_entries, base::BindOnce(&DownloadDBCache::OnInProgressCacheMigrated,
+                                 weak_factory_.GetWeakPtr()));
+}
+
+void DownloadDBCache::OnInProgressCacheMigrated(bool success) {
+  RecordInProgressDBCount(success ? kCacheMigrationSucceededCount
+                                  : kCacheMigrationFailedCount);
 }
 
 }  //  namespace download
diff --git a/components/download/internal/common/download_db_cache.h b/components/download/internal/common/download_db_cache.h
index e4a7dbb..36b3b38 100644
--- a/components/download/internal/common/download_db_cache.h
+++ b/components/download/internal/common/download_db_cache.h
@@ -31,8 +31,10 @@
   ~DownloadDBCache() override;
 
   using InitializeCallback =
-      base::OnceCallback<void(std::unique_ptr<std::vector<DownloadDBEntry>>)>;
-  void Initialize(InitializeCallback callback);
+      base::OnceCallback<void(bool /* success */,
+                              std::unique_ptr<std::vector<DownloadDBEntry>>)>;
+  void Initialize(const std::vector<DownloadEntry>& entries,
+                  InitializeCallback callback);
 
   base::Optional<DownloadDBEntry> RetrieveEntry(const std::string& guid);
   void AddOrReplaceEntry(const DownloadDBEntry& entry);
@@ -40,9 +42,6 @@
   // Remove an entry from the DownloadDB.
   void RemoveEntry(const std::string& guid);
 
-  // Migrate DownloadEntry from in-progress cache.
-  void MigrateFromInProgressCache(const std::vector<DownloadEntry>& entries);
-
  private:
   friend class DownloadDBCacheTest;
   friend class InProgressDownloadManager;
@@ -55,7 +54,9 @@
   void OnDownloadRemoved(DownloadItem* download) override;
 
   // Called when the |download_db_| is initialized.
-  void OnDownloadDBInitialized(InitializeCallback callback, bool success);
+  void OnDownloadDBInitialized(const std::vector<DownloadEntry>& entries,
+                               InitializeCallback callback,
+                               bool success);
 
   // Called when all the download db entries are loaded.
   void OnDownloadDBEntriesLoaded(
@@ -63,6 +64,12 @@
       bool success,
       std::unique_ptr<std::vector<DownloadDBEntry>> entries);
 
+  // Migrate DownloadEntry from in-progress cache.
+  void MigrateFromInProgressCache(const std::vector<DownloadEntry>& entries);
+
+  // Called when InProgressCache is migrated.
+  void OnInProgressCacheMigrated(bool success);
+
   void SetTimerTaskRunnerForTesting(
       scoped_refptr<base::SequencedTaskRunner> task_runner);
 
diff --git a/components/download/internal/common/download_db_cache_unittest.cc b/components/download/internal/common/download_db_cache_unittest.cc
index 6e19335..44a6108 100644
--- a/components/download/internal/common/download_db_cache_unittest.cc
+++ b/components/download/internal/common/download_db_cache_unittest.cc
@@ -143,9 +143,10 @@
   PrepopulateSampleEntries();
   CreateDBCache();
   std::vector<DownloadDBEntry> loaded_entries;
-  db_cache_->Initialize(base::BindOnce(&DownloadDBCacheTest::InitCallback,
-                                       base::Unretained(this), &loaded_entries,
-                                       true));
+  db_cache_->Initialize(
+      std::vector<DownloadEntry>(),
+      base::BindOnce(&DownloadDBCacheTest::InitCallback, base::Unretained(this),
+                     &loaded_entries));
   db_->InitCallback(true);
   db_->LoadCallback(true);
   ASSERT_EQ(loaded_entries.size(), 2u);
@@ -163,9 +164,10 @@
   PrepopulateSampleEntries();
   CreateDBCache();
   std::vector<DownloadDBEntry> loaded_entries;
-  db_cache_->Initialize(base::BindOnce(&DownloadDBCacheTest::InitCallback,
-                                       base::Unretained(this), &loaded_entries,
-                                       true));
+  db_cache_->Initialize(
+      std::vector<DownloadEntry>(),
+      base::BindOnce(&DownloadDBCacheTest::InitCallback, base::Unretained(this),
+                     &loaded_entries));
   db_->InitCallback(true);
   db_->LoadCallback(true);
   ASSERT_EQ(loaded_entries.size(), 2u);
@@ -188,9 +190,10 @@
   PrepopulateSampleEntries();
   CreateDBCache();
   std::vector<DownloadDBEntry> loaded_entries;
-  db_cache_->Initialize(base::BindOnce(&DownloadDBCacheTest::InitCallback,
-                                       base::Unretained(this), &loaded_entries,
-                                       true));
+  db_cache_->Initialize(
+      std::vector<DownloadEntry>(),
+      base::BindOnce(&DownloadDBCacheTest::InitCallback, base::Unretained(this),
+                     &loaded_entries));
   db_->InitCallback(true);
   db_->LoadCallback(true);
   ASSERT_EQ(loaded_entries.size(), 2u);
@@ -228,9 +231,10 @@
                      DownloadDBConversions::DownloadDBEntryToProto(entry)));
   CreateDBCache();
   std::vector<DownloadDBEntry> loaded_entries;
-  db_cache_->Initialize(base::BindOnce(&DownloadDBCacheTest::InitCallback,
-                                       base::Unretained(this), &loaded_entries,
-                                       true));
+  db_cache_->Initialize(
+      std::vector<DownloadEntry>(),
+      base::BindOnce(&DownloadDBCacheTest::InitCallback, base::Unretained(this),
+                     &loaded_entries));
   db_->InitCallback(true);
   db_->LoadCallback(true);
   ASSERT_EQ(loaded_entries.size(), 1u);
@@ -257,9 +261,10 @@
   PrepopulateSampleEntries();
   CreateDBCache();
   std::vector<DownloadDBEntry> loaded_entries;
-  db_cache_->Initialize(base::BindOnce(&DownloadDBCacheTest::InitCallback,
-                                       base::Unretained(this), &loaded_entries,
-                                       true));
+  db_cache_->Initialize(
+      std::vector<DownloadEntry>(),
+      base::BindOnce(&DownloadDBCacheTest::InitCallback, base::Unretained(this),
+                     &loaded_entries));
   db_->InitCallback(true);
   db_->LoadCallback(true);
   ASSERT_EQ(loaded_entries.size(), 2u);
@@ -285,14 +290,6 @@
 // a DownloadDBEntry in the DownloadDB.
 TEST_F(DownloadDBCacheTest, MigrateFromInProgressCache) {
   CreateDBCache();
-  std::vector<DownloadDBEntry> loaded_entries;
-  db_cache_->Initialize(base::BindOnce(&DownloadDBCacheTest::InitCallback,
-                                       base::Unretained(this), &loaded_entries,
-                                       true));
-  db_->InitCallback(true);
-  db_->LoadCallback(true);
-  ASSERT_TRUE(loaded_entries.empty());
-
   std::vector<DownloadEntry> download_entries;
   download_entries.emplace_back(
       "guid1", "foo.com", DownloadSource::DRAG_AND_DROP, true,
@@ -301,8 +298,15 @@
       "guid2", "foobar.com", DownloadSource::UNKNOWN, false,
       DownloadUrlParameters::RequestHeadersType(), 200);
 
-  db_cache_->MigrateFromInProgressCache(download_entries);
+  std::vector<DownloadDBEntry> loaded_entries;
+  db_cache_->Initialize(
+      download_entries,
+      base::BindOnce(&DownloadDBCacheTest::InitCallback, base::Unretained(this),
+                     &loaded_entries));
+  db_->InitCallback(true);
   db_->UpdateCallback(true);
+  db_->LoadCallback(true);
+  ASSERT_FALSE(loaded_entries.empty());
 
   std::unique_ptr<DownloadItem> item = CreateDownloadItem("guid1");
   OnDownloadUpdated(item.get());
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc
index 96a21a2e..0f0e81c 100644
--- a/components/download/internal/common/download_stats.cc
+++ b/components/download/internal/common/download_stats.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 "components/download/public/common//download_stats.h"
+#include "components/download/public/common/download_stats.h"
 
 #include <map>
 
@@ -1118,4 +1118,8 @@
       net::HttpUtil::GetStatusCodesForHistogram());
 }
 
+void RecordInProgressDBCount(InProgressDBCountTypes type) {
+  UMA_HISTOGRAM_ENUMERATION("Download.InProgressDB.Counts", type);
+}
+
 }  // namespace download
diff --git a/components/download/internal/common/in_progress_download_manager.cc b/components/download/internal/common/in_progress_download_manager.cc
index e51414c..fa7133290 100644
--- a/components/download/internal/common/in_progress_download_manager.cc
+++ b/components/download/internal/common/in_progress_download_manager.cc
@@ -4,7 +4,6 @@
 
 #include "components/download/public/common/in_progress_download_manager.h"
 
-#include "base/command_line.h"
 #include "base/optional.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -12,9 +11,9 @@
 #include "components/download/database/download_db_impl.h"
 #include "components/download/database/download_namespace.h"
 #include "components/download/database/in_progress/in_progress_cache_impl.h"
-#include "components/download/database/switches.h"
 #include "components/download/internal/common/download_db_cache.h"
 #include "components/download/internal/common/resource_downloader.h"
+#include "components/download/public/common/download_features.h"
 #include "components/download/public/common/download_file.h"
 #include "components/download/public/common/download_item_impl.h"
 #include "components/download/public/common/download_start_observer.h"
@@ -279,30 +278,18 @@
 
 void InProgressDownloadManager::Initialize(
     const base::FilePath& metadata_cache_dir) {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableDownloadDB)) {
-    // TODO(qinmin): migrate all the data from InProgressCache into
-    // |download_db_|.
-    download_db_cache_ = std::make_unique<DownloadDBCache>(
-        metadata_cache_dir.empty()
-            ? std::make_unique<DownloadDB>()
-            : std::make_unique<DownloadDBImpl>(
-                  DownloadNamespace::NAMESPACE_BROWSER_DOWNLOAD,
-                  metadata_cache_dir));
-    download_db_cache_->Initialize(base::BindOnce(
-        &InProgressDownloadManager::OnInitialized, weak_factory_.GetWeakPtr()));
-  } else {
-    download_metadata_cache_ = std::make_unique<InProgressCacheImpl>(
-        metadata_cache_dir.empty()
-            ? base::FilePath()
-            : metadata_cache_dir.Append(kDownloadMetadataStoreFilename),
-        base::CreateSequencedTaskRunnerWithTraits(
-            {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
-             base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
-    download_metadata_cache_->Initialize(base::BindOnce(
-        &InProgressDownloadManager::OnInitialized, weak_factory_.GetWeakPtr(),
-        std::make_unique<std::vector<DownloadDBEntry>>()));
-  }
+  // TODO(qinmin): remove |download_metadata_cache_| when migration is done for
+  // most clients.
+  download_metadata_cache_ = std::make_unique<InProgressCacheImpl>(
+      metadata_cache_dir.empty()
+          ? base::FilePath()
+          : metadata_cache_dir.Append(kDownloadMetadataStoreFilename),
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+           base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
+  download_metadata_cache_->Initialize(
+      base::BindOnce(&InProgressDownloadManager::OnMetadataCacheInitialized,
+                     weak_factory_.GetWeakPtr(), metadata_cache_dir));
 }
 
 void InProgressDownloadManager::ShutDown() {
@@ -453,11 +440,14 @@
     }
   }
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableDownloadDB)) {
-    download_db_cache_->AddOrReplaceEntry(CreateDownloadDBEntryFromItem(
-        *download, UkmInfo(info->download_source, GetUniqueDownloadId()),
-        info->fetch_error_body, info->request_headers));
+  if (download_db_cache_) {
+    base::Optional<DownloadDBEntry> entry_opt =
+        download_db_cache_->RetrieveEntry(download->GetGuid());
+    if (!entry_opt.has_value()) {
+      download_db_cache_->AddOrReplaceEntry(CreateDownloadDBEntryFromItem(
+          *download, UkmInfo(info->download_source, GetUniqueDownloadId()),
+          info->fetch_error_body, info->request_headers));
+    }
     download->RemoveObserver(download_db_cache_.get());
     download->AddObserver(download_db_cache_.get());
   } else {
@@ -492,14 +482,38 @@
     download_start_observer_->OnDownloadStarted(download);
 }
 
+void InProgressDownloadManager::OnMetadataCacheInitialized(
+    const base::FilePath& metadata_cache_dir) {
+  download_db_cache_ = std::make_unique<DownloadDBCache>(
+      metadata_cache_dir.empty()
+          ? std::make_unique<DownloadDB>()
+          : std::make_unique<DownloadDBImpl>(
+                DownloadNamespace::NAMESPACE_BROWSER_DOWNLOAD,
+                metadata_cache_dir));
+  download_db_cache_->Initialize(
+      download_metadata_cache_->GetAllEntries(),
+      base::BindOnce(&InProgressDownloadManager::OnInitialized,
+                     weak_factory_.GetWeakPtr()));
+}
+
 void InProgressDownloadManager::OnInitialized(
+    bool success,
     std::unique_ptr<std::vector<DownloadDBEntry>> entries) {
-  for (const auto& entry : *entries) {
-    auto item = CreateDownloadItemImpl(this, entry);
-    if (!item)
-      continue;
-    item->AddObserver(download_db_cache_.get());
-    in_progress_downloads_.emplace_back(std::move(item));
+  // Destroy the in-progress cache as it is no longer needed on success.
+  if (success) {
+    download_metadata_cache_->Destroy();
+    download_metadata_cache_.reset();
+  } else {
+    download_db_cache_.reset();
+  }
+  if (base::FeatureList::IsEnabled(features::kDownloadDBForNewDownloads)) {
+    for (const auto& entry : *entries) {
+      auto item = CreateDownloadItemImpl(this, entry);
+      if (!item)
+        continue;
+      item->AddObserver(download_db_cache_.get());
+      in_progress_downloads_.emplace_back(std::move(item));
+    }
   }
   is_initialized_ = true;
   for (auto& callback : on_initialized_callbacks_)
diff --git a/components/download/public/common/download_features.cc b/components/download/public/common/download_features.cc
index 2a04e258..26b0a2b 100644
--- a/components/download/public/common/download_features.cc
+++ b/components/download/public/common/download_features.cc
@@ -18,5 +18,8 @@
 #endif
 };
 
+const base::Feature kDownloadDBForNewDownloads{
+    "DownloadDBForNewDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace download
diff --git a/components/download/public/common/download_features.h b/components/download/public/common/download_features.h
index e6b6c134..6f08406 100644
--- a/components/download/public/common/download_features.h
+++ b/components/download/public/common/download_features.h
@@ -14,6 +14,11 @@
 // Whether a download can be handled by parallel jobs.
 COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kParallelDownloading;
 
+// Whether metadata for new in-progress downloads will be be stored in download
+// DB, rather than history DB.
+COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature
+    kDownloadDBForNewDownloads;
+
 }  // namespace features
 }  // namespace download
 
diff --git a/components/download/public/common/download_stats.h b/components/download/public/common/download_stats.h
index 15652249..d40169e7 100644
--- a/components/download/public/common/download_stats.h
+++ b/components/download/public/common/download_stats.h
@@ -151,6 +151,36 @@
   DOWNLOAD_DISCARD_DUE_TO_SHUTDOWN
 };
 
+// Enum for in-progress download DB, used in histogram
+// "Download.InProgressDB.Counts".
+enum InProgressDBCountTypes {
+  // Count of initialization attempts.
+  kInitializationCount = 0,
+
+  // Count of initialization attempts that succeeded.
+  kInitializationSucceededCount = 1,
+
+  // Count of initialization attempts that failed.
+  kInitializationFailedCount = 2,
+
+  // Count of load attempts that succeeded.
+  kLoadSucceededCount = 3,
+
+  // Count of load attempts that failed.
+  kLoadFailedCount = 4,
+
+  // Count of in-progress cache migration attempts.
+  kCacheMigrationCount = 5,
+
+  // Count of in-progress cache migration attempts that succeeded.
+  kCacheMigrationSucceededCount = 6,
+
+  // Count of in-progress cache migration attempts that failed.
+  kCacheMigrationFailedCount = 7,
+
+  kMaxValue = kCacheMigrationFailedCount
+};
+
 // When parallel download is enabled, the download may fall back to a normal
 // download for various reasons. This enum counts the number of parallel
 // download and fallbacks. Also records the reasons why the download falls back
@@ -390,6 +420,9 @@
 COMPONENTS_DOWNLOAD_EXPORT void RecordDownloadHttpResponseCode(
     int response_code);
 
+COMPONENTS_DOWNLOAD_EXPORT void RecordInProgressDBCount(
+    InProgressDBCountTypes type);
+
 }  // namespace download
 
 #endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_STATS_H_
diff --git a/components/download/public/common/in_progress_download_manager.h b/components/download/public/common/in_progress_download_manager.h
index 1b695711..b66b751 100644
--- a/components/download/public/common/in_progress_download_manager.h
+++ b/components/download/public/common/in_progress_download_manager.h
@@ -165,8 +165,12 @@
   void OnUrlDownloadHandlerCreated(
       UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader) override;
 
+  // Called when |download_metadata_cache_| is initialized.
+  void OnMetadataCacheInitialized(const base::FilePath& metadata_cache_dir);
+
   // Called when the object is initialized.
-  void OnInitialized(std::unique_ptr<std::vector<DownloadDBEntry>> entries);
+  void OnInitialized(bool success,
+                     std::unique_ptr<std::vector<DownloadDBEntry>> entries);
 
   // Start a DownloadItemImpl.
   void StartDownloadWithItem(
diff --git a/components/drive/OWNERS b/components/drive/OWNERS
index 7c921ec..540a62f 100644
--- a/components/drive/OWNERS
+++ b/components/drive/OWNERS
@@ -3,6 +3,5 @@
 hidehiko@chromium.org
 hirono@chromium.org
 kinaba@chromium.org
-sashab@chromium.org
 slangley@chromium.org
 yoshiki@chromium.org
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc
index 85a9ca9..8cd792c 100644
--- a/components/exo/buffer_unittest.cc
+++ b/components/exo/buffer_unittest.cc
@@ -5,6 +5,7 @@
 #include <GLES2/gl2extchromium.h>
 
 #include "base/bind.h"
+#include "base/run_loop.h"
 #include "components/exo/buffer.h"
 #include "components/exo/surface_tree_host.h"
 #include "components/exo/test/exo_test_base.h"
@@ -28,6 +29,17 @@
   (*release_call_count)++;
 }
 
+void VerifySyncTokensInCompositorFrame(viz::CompositorFrame* frame) {
+  std::vector<GLbyte*> sync_tokens;
+  for (auto& resource : frame->resource_list)
+    sync_tokens.push_back(resource.mailbox_holder.sync_token.GetData());
+  gpu::gles2::GLES2Interface* gles2 = aura::Env::GetInstance()
+                                          ->context_factory()
+                                          ->SharedMainThreadContextProvider()
+                                          ->ContextGL();
+  gles2->VerifySyncTokensCHROMIUM(sync_tokens.data(), sync_tokens.size());
+}
+
 TEST_F(BufferTest, ReleaseCallback) {
   gfx::Size buffer_size(256, 256);
   auto buffer = std::make_unique<Buffer>(
@@ -36,7 +48,7 @@
   LayerTreeFrameSinkHolder* frame_sink_holder =
       surface_tree_host->layer_tree_frame_sink_holder();
 
-  // This is needed to ensure that RunAllPendingInMessageLoop() call below
+  // This is needed to ensure that base::RunLoop().RunUntilIdle() call below
   // is always sufficient for buffer to be released.
   buffer->set_wait_for_release_delay_for_testing(base::TimeDelta());
 
@@ -60,7 +72,7 @@
   std::vector<viz::ReturnedResource> resources = {returned_resource};
   frame_sink_holder->ReclaimResources(resources);
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
   ASSERT_EQ(release_call_count, 0);
 
   buffer->OnDetach();
@@ -102,7 +114,7 @@
   returned_resource.lost = is_lost;
   std::vector<viz::ReturnedResource> resources = {returned_resource};
   frame_sink_holder->ReclaimResources(resources);
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   // Producing a new texture transferable resource for the contents of the
   // buffer.
@@ -118,7 +130,7 @@
   returned_resource2.lost = false;
   std::vector<viz::ReturnedResource> resources2 = {returned_resource2};
   frame_sink_holder->ReclaimResources(resources2);
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 }
 
 // Buffer::Texture::OnLostResources is called when the gpu crashes. This test
@@ -152,7 +164,7 @@
   LayerTreeFrameSinkHolder* frame_sink_holder =
       surface_tree_host->layer_tree_frame_sink_holder();
 
-  // This is needed to ensure that RunAllPendingInMessageLoop() call below
+  // This is needed to ensure that base::RunLoop().RunUntilIdle() call below
   // is always sufficient for buffer to be released.
   buffer->set_wait_for_release_delay_for_testing(base::TimeDelta());
 
@@ -182,13 +194,16 @@
                  gfx::Transform());
     frame.render_pass_list.push_back(std::move(pass));
     frame.resource_list.push_back(resource);
+    VerifySyncTokensInCompositorFrame(&frame);
     frame_sink_holder->SubmitCompositorFrame(std::move(frame));
   }
 
   buffer->OnDetach();
+  base::RunLoop().RunUntilIdle();
   ASSERT_EQ(release_call_count, 0);
 
   surface_tree_host.reset();
+  base::RunLoop().RunUntilIdle();
   ASSERT_EQ(release_call_count, 1);
 }
 
@@ -200,7 +215,7 @@
   LayerTreeFrameSinkHolder* frame_sink_holder =
       surface_tree_host->layer_tree_frame_sink_holder();
 
-  // This is needed to ensure that RunAllPendingInMessageLoop() call below
+  // This is needed to ensure that base::RunLoop().RunUntilIdle() call below
   // is always sufficient for buffer to be released.
   buffer->set_wait_for_release_delay_for_testing(base::TimeDelta());
 
@@ -230,6 +245,7 @@
                  gfx::Transform());
     frame.render_pass_list.push_back(std::move(pass));
     frame.resource_list.push_back(resource);
+    VerifySyncTokensInCompositorFrame(&frame);
     frame_sink_holder->SubmitCompositorFrame(std::move(frame));
 
     // Try to release buffer in last frame. This can happen during a resize
@@ -238,11 +254,12 @@
     returned_resource.id = resource.id;
     returned_resource.sync_token = resource.mailbox_holder.sync_token;
     returned_resource.lost = false;
+
     std::vector<viz::ReturnedResource> resources = {returned_resource};
     frame_sink_holder->ReclaimResources(resources);
   }
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
   buffer->OnDetach();
 
   // Release() should not have been called as resource is used by last frame.
@@ -264,6 +281,7 @@
     frame_sink_holder->SubmitCompositorFrame(std::move(frame));
   }
 
+  base::RunLoop().RunUntilIdle();
   // Release() should have been called exactly once.
   ASSERT_EQ(release_call_count, 1);
 }
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 5f40dbe..2fb5c58 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -268,10 +268,7 @@
 ClientControlledShellSurface::ClientControlledShellSurface(Surface* surface,
                                                            bool can_minimize,
                                                            int container)
-    : ShellSurfaceBase(surface, gfx::Point(), true, can_minimize, container),
-      primary_display_id_(
-          display::Screen::GetScreen()->GetPrimaryDisplay().id()) {
-  WMHelper::GetInstance()->AddDisplayConfigurationObserver(this);
+    : ShellSurfaceBase(surface, gfx::Point(), true, can_minimize, container) {
   display::Screen::GetScreen()->AddObserver(this);
 }
 
@@ -279,7 +276,6 @@
   if (wide_frame_)
     wide_frame_->Close();
 
-  WMHelper::GetInstance()->RemoveDisplayConfigurationObserver(this);
   display::Screen::GetScreen()->RemoveObserver(this);
 }
 
@@ -731,36 +727,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// ash::WindowTreeHostManager::Observer overrides:
-
-void ClientControlledShellSurface::OnDisplayConfigurationChanged() {
-  const display::Screen* screen = display::Screen::GetScreen();
-  int64_t primary_display_id = screen->GetPrimaryDisplay().id();
-  if (primary_display_id == primary_display_id_)
-    return;
-
-  display::Display old_primary_display;
-  if (screen->GetDisplayWithDisplayId(primary_display_id_,
-                                      &old_primary_display)) {
-    // Give the client a chance to adjust window positions before switching to
-    // the new coordinate system. Retain the old origin by reverting the origin
-    // delta until the next configure is acknowledged.
-    gfx::Vector2d delta = gfx::Point() - old_primary_display.bounds().origin();
-    origin_offset_ -= delta;
-    pending_origin_offset_accumulator_ += delta;
-
-    if (widget_) {
-      UpdateWidgetBounds();
-      UpdateShadow();
-    }
-
-    Configure();
-  }
-
-  primary_display_id_ = primary_display_id;
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // ui::CompositorLockClient overrides:
 
 void ClientControlledShellSurface::CompositorLockTimedOut() {
@@ -841,17 +807,6 @@
         frame_view->GetWindowBoundsForClientBounds(shadow_bounds).size());
   }
 
-  if (geometry_changed_callback_.is_null()) {
-    aura::Window* window = widget_->GetNativeWindow();
-
-    // Convert from screen to display coordinates.
-    shadow_bounds -= origin_offset_;
-    wm::ConvertRectFromScreen(window->parent(), &shadow_bounds);
-
-    // Convert from display to window coordinates.
-    shadow_bounds -= window->bounds().OffsetFromOrigin();
-  }
-
   return shadow_bounds;
 }
 
@@ -888,28 +843,20 @@
     return frame_view->GetWindowBoundsForClientBounds(GetVisibleBounds());
   }
 
-  gfx::Rect bounds(GetVisibleBounds());
-  bounds.Offset(-origin_offset_.x(), -origin_offset_.y());
-  return bounds;
+  return GetVisibleBounds();
 }
 
 gfx::Point ClientControlledShellSurface::GetSurfaceOrigin() const {
   DCHECK(resize_component_ == HTCAPTION);
-  if (geometry_changed_callback_)
-    return gfx::Point();
-  // TODO(oshima): geometry_changed_callback_ must be always set by now, so
-  // this is not necessary any more. Remove this.
-  return gfx::Point() -
-         (GetVisibleBounds().origin() - origin_offset_).OffsetFromOrigin();
+  return gfx::Point();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // ClientControlledShellSurface, private:
 
 void ClientControlledShellSurface::UpdateFrame() {
-  if (!widget_)
+  if (!widget_ || !GetFrameView()->visible())
     return;
-
   gfx::Rect work_area =
       display::Screen::GetScreen()
           ->GetDisplayNearestWindow(widget_->GetNativeWindow())
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index 87eaf2b..d144774 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "ash/display/screen_orientation_controller.h"
-#include "ash/display/window_tree_host_manager.h"
 #include "ash/wm/client_controlled_state.h"
 #include "base/callback.h"
 #include "base/macros.h"
@@ -40,17 +39,15 @@
 class ClientControlledShellSurface
     : public ShellSurfaceBase,
       public display::DisplayObserver,
-      public ash::WindowTreeHostManager::Observer,
       public ui::CompositorLockClient {
  public:
-  using GeometryChangedCallback =
-      base::RepeatingCallback<void(const gfx::Rect& geometry)>;
-
   ClientControlledShellSurface(Surface* surface,
                                bool can_minimize,
                                int container);
   ~ClientControlledShellSurface() override;
 
+  using GeometryChangedCallback =
+      base::RepeatingCallback<void(const gfx::Rect& geometry)>;
   void set_geometry_changed_callback(const GeometryChangedCallback& callback) {
     geometry_changed_callback_ = callback;
   }
@@ -216,9 +213,6 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
-  // Overridden from ash::WindowTreeHostManager::Observer:
-  void OnDisplayConfigurationChanged() override;
-
   // Overridden from ui::CompositorLockClient:
   void CompositorLockTimedOut() override;
 
@@ -268,7 +262,6 @@
   const ash::CustomFrameViewAsh* GetFrameView() const;
 
   GeometryChangedCallback geometry_changed_callback_;
-  int64_t primary_display_id_;
 
   int top_inset_height_ = 0;
   int pending_top_inset_height_ = 0;
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index c440cdc..22e15df 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -371,12 +371,8 @@
   surface->SetFrame(SurfaceFrameType::SHADOW);
   surface->Commit();
 
-  // Placing a shadow at screen origin will make the shadow's origin (-10, -10).
-  const gfx::Rect shadow_bounds(content_size);
-
-  // Expected shadow position/bounds in parent coordinates.
-  const gfx::Point expected_shadow_origin(-10, -10);
-  const gfx::Rect expected_shadow_bounds(expected_shadow_origin, content_size);
+  // In parent coordinates.
+  const gfx::Rect shadow_bounds(gfx::Point(-10, -10), content_size);
 
   views::Widget* widget = shell_surface->GetWidget();
   aura::Window* window = widget->GetNativeWindow();
@@ -388,7 +384,7 @@
 
   EXPECT_TRUE(shadow->layer()->visible());
   // Origin must be in sync.
-  EXPECT_EQ(expected_shadow_origin, shadow->content_bounds().origin());
+  EXPECT_EQ(shadow_bounds.origin(), shadow->content_bounds().origin());
 
   const gfx::Rect work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
@@ -405,13 +401,12 @@
   // area,/ thus not visible until new bounds is committed.
   widget->Restore();
   EXPECT_TRUE(shadow->layer()->visible());
-  const gfx::Rect shadow_in_maximized(expected_shadow_origin, work_area.size());
-  EXPECT_EQ(shadow_in_maximized, shadow->content_bounds());
+  EXPECT_EQ(work_area, shadow->content_bounds());
 
   // The bounds is updated.
   shell_surface->SetShadowBounds(shadow_bounds);
   surface->Commit();
-  EXPECT_EQ(expected_shadow_bounds, shadow->content_bounds());
+  EXPECT_EQ(shadow_bounds, shadow->content_bounds());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowWithTransform) {
@@ -433,8 +428,8 @@
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ui::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
 
-  // Placing a shadow at screen origin will make the shadow's origin (-10, -10).
-  const gfx::Rect shadow_bounds(content_size);
+  // In parent coordinates.
+  const gfx::Rect shadow_bounds(gfx::Point(-10, -10), content_size);
 
   // Shadow bounds relative to its parent should not be affected by a transform.
   gfx::Transform transform;
@@ -555,18 +550,6 @@
   EXPECT_EQ(client_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(client_bounds));
-
-  // Test NONE -> AUTOHIDE -> NONE
-  shell_surface->SetMaximized();
-  shell_surface->SetGeometry(fullscreen_bounds);
-  surface->SetFrame(SurfaceFrameType::AUTOHIDE);
-  surface->Commit();
-  EXPECT_TRUE(frame_view->visible());
-  EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode());
-  surface->SetFrame(SurfaceFrameType::NONE);
-  surface->Commit();
-  EXPECT_FALSE(frame_view->visible());
-  EXPECT_FALSE(frame_view->GetHeaderView()->in_immersive_mode());
 }
 
 namespace {
@@ -1495,22 +1478,12 @@
   ASSERT_TRUE(wide_frame);
   EXPECT_FALSE(wide_frame->header_view()->in_immersive_mode());
 
-  // Test AUTOHIDE -> NORMAL
+  // Set AutoHide mode.
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
-  surface->Commit();
   EXPECT_TRUE(wide_frame->header_view()->in_immersive_mode());
 
+  // Exit AutoHide mode.
   surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
-  EXPECT_FALSE(wide_frame->header_view()->in_immersive_mode());
-
-  // Test AUTOHIDE -> NONE
-  surface->SetFrame(SurfaceFrameType::AUTOHIDE);
-  surface->Commit();
-  EXPECT_TRUE(wide_frame->header_view()->in_immersive_mode());
-
-  surface->SetFrame(SurfaceFrameType::NONE);
-  surface->Commit();
   EXPECT_FALSE(wide_frame->header_view()->in_immersive_mode());
 
   // Unmaximize it and the frame should be normal.
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index 53912d0..ed01de4b 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -248,16 +248,14 @@
       root_surface_origin_, device_scale_factor,
       layer_tree_frame_sink_holder_.get(), &frame);
 
-  if (WMHelper::GetInstance()->AreVerifiedSyncTokensNeeded()) {
-    std::vector<GLbyte*> sync_tokens;
-    for (auto& resource : frame.resource_list)
-      sync_tokens.push_back(resource.mailbox_holder.sync_token.GetData());
-    ui::ContextFactory* context_factory =
-        aura::Env::GetInstance()->context_factory();
-    gpu::gles2::GLES2Interface* gles2 =
-        context_factory->SharedMainThreadContextProvider()->ContextGL();
-    gles2->VerifySyncTokensCHROMIUM(sync_tokens.data(), sync_tokens.size());
-  }
+  std::vector<GLbyte*> sync_tokens;
+  for (auto& resource : frame.resource_list)
+    sync_tokens.push_back(resource.mailbox_holder.sync_token.GetData());
+  ui::ContextFactory* context_factory =
+      aura::Env::GetInstance()->context_factory();
+  gpu::gles2::GLES2Interface* gles2 =
+      context_factory->SharedMainThreadContextProvider()->ContextGL();
+  gles2->VerifySyncTokensCHROMIUM(sync_tokens.data(), sync_tokens.size());
 
   layer_tree_frame_sink_holder_->SubmitCompositorFrame(std::move(frame));
 }
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index 27afc38..40630cf2 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -96,7 +96,7 @@
   // CompositorFrameSinkClient interface. We need to wait here for the mojo
   // call to finish so that the release callback finishes running before
   // the assertion below.
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
   ASSERT_EQ(1, release_buffer_call_count);
 }
 
@@ -133,7 +133,7 @@
   // Check that damage larger than contents is handled correctly at commit.
   surface->Damage(gfx::Rect(gfx::ScaleToCeiledSize(buffer_size, 2.0f)));
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -148,7 +148,7 @@
   // Check that damage is correct for a non-square rectangle not at the origin.
   surface->Damage(surface_damage);
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   // Adjust damage for DSF filtering and verify it below.
   if (device_scale_factor() > 1.f)
@@ -202,7 +202,7 @@
   // draw with blending.
   surface->SetOpaqueRegion(gfx::Rect(256, 256));
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -219,7 +219,7 @@
   // Setting an empty opaque region requires draw with blending.
   surface->SetOpaqueRegion(gfx::Rect());
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -241,7 +241,7 @@
   // blending.
   surface->Attach(buffer_without_alpha.get());
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -367,7 +367,7 @@
       gfx::ScaleToFlooredSize(buffer_size, 1.0f / kBufferScale).ToString(),
       surface->content_size().ToString());
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   const viz::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -398,7 +398,7 @@
   EXPECT_EQ(gfx::Size(buffer_size.height(), buffer_size.width()),
             surface->content_size());
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -440,7 +440,7 @@
       gfx::ScaleToRoundedSize(child_buffer_size, 1.0f / kChildBufferScale),
       child_surface->content_size());
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -468,6 +468,8 @@
   surface->Attach(buffer.get());
   surface->Commit();
 
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(buffer_size, surface->window()->bounds().size());
   EXPECT_EQ(buffer_size, surface->window()->layer()->bounds().size());
   std::unique_ptr<ui::LayerTreeOwner> old_layer_owner =
@@ -503,7 +505,7 @@
             surface->window()->bounds().size().ToString());
   EXPECT_EQ(viewport2.ToString(), surface->content_size().ToString());
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   const viz::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -526,7 +528,7 @@
             surface->window()->bounds().size().ToString());
   EXPECT_EQ(crop_size.ToString(), surface->content_size().ToString());
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   const viz::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -564,7 +566,7 @@
   surface->SetBufferTransform(Transform::NORMAL);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -585,7 +587,7 @@
   surface->SetBufferTransform(Transform::ROTATE_90);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -606,7 +608,7 @@
   surface->SetBufferTransform(Transform::ROTATE_180);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -627,7 +629,7 @@
   surface->SetBufferTransform(Transform::ROTATE_270);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -649,7 +651,7 @@
   surface->SetBufferTransform(Transform::NORMAL);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -670,7 +672,7 @@
   surface->SetBufferTransform(Transform::ROTATE_90);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -691,7 +693,7 @@
   surface->SetBufferTransform(Transform::ROTATE_180);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -712,7 +714,7 @@
   surface->SetBufferTransform(Transform::ROTATE_270);
   surface->Commit();
 
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   {
     const viz::CompositorFrame& frame =
@@ -741,7 +743,7 @@
   surface->Attach(buffer.get());
   surface->SetBlendMode(SkBlendMode::kSrc);
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   const viz::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -761,7 +763,7 @@
 
   surface->Attach(buffer.get());
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   const viz::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -786,7 +788,7 @@
     surface->Attach(buffer.get());
     surface->SetAlpha(0.5f);
     surface->Commit();
-    RunAllPendingInMessageLoop();
+    base::RunLoop().RunUntilIdle();
 
     const viz::CompositorFrame& frame =
         GetFrameFromSurface(shell_surface.get());
@@ -801,6 +803,8 @@
   {
     surface->SetAlpha(0.f);
     surface->Commit();
+    base::RunLoop().RunUntilIdle();
+
     const viz::CompositorFrame& frame =
         GetFrameFromSurface(shell_surface.get());
     ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -814,6 +818,8 @@
   {
     surface->SetAlpha(1.f);
     surface->Commit();
+    base::RunLoop().RunUntilIdle();
+
     const viz::CompositorFrame& frame =
         GetFrameFromSurface(shell_surface.get());
     ASSERT_EQ(1u, frame.render_pass_list.size());
@@ -852,7 +858,7 @@
   child_surface->Attach(child_buffer.get());
   child_surface->Commit();
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   // Remove the subsurface by destroying it. This should not damage |surface|.
   // TODO(penghuang): Make the damage more precise for sub surface changes.
@@ -870,7 +876,7 @@
 
   surface->Attach(buffer.get());
   surface->Commit();
-  RunAllPendingInMessageLoop();
+  base::RunLoop().RunUntilIdle();
 
   // Make sure surface size is still valid after buffer is destroyed.
   buffer.reset();
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 6b0ef7ac..4eb5d98 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -2550,10 +2550,6 @@
     display::Screen::GetScreen()->RemoveObserver(this);
   }
 
-  bool HasRelativeSurfaceHierarchy() const {
-    return wl_resource_get_version(remote_shell_resource_) >= 9;
-  }
-
   std::unique_ptr<ClientControlledShellSurface> CreateShellSurface(
       Surface* surface,
       int container,
@@ -2883,11 +2879,9 @@
   shell_surface->set_configure_callback(
       base::Bind(&HandleRemoteSurfaceConfigureCallback,
                  base::Unretained(remote_surface_resource)));
-  if (shell->HasRelativeSurfaceHierarchy()) {
-    shell_surface->set_geometry_changed_callback(
-        base::BindRepeating(&HandleRemoteSurfaceGeometryChangedCallback,
-                            base::Unretained(remote_surface_resource)));
-  }
+  shell_surface->set_geometry_changed_callback(
+      base::BindRepeating(&HandleRemoteSurfaceGeometryChangedCallback,
+                          base::Unretained(remote_surface_resource)));
 
   if (wl_resource_get_version(remote_surface_resource) >= 10) {
     shell_surface->set_client_controlled_move_resize(false);
diff --git a/components/exo/wm_helper.cc b/components/exo/wm_helper.cc
index bad907d..0432568 100644
--- a/components/exo/wm_helper.cc
+++ b/components/exo/wm_helper.cc
@@ -4,9 +4,7 @@
 
 #include "components/exo/wm_helper.h"
 
-#include "ash/public/cpp/config.h"
 #include "ash/shell.h"
-#include "ash/system/tray/system_tray_notifier.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/memory/singleton.h"
 #include "ui/aura/client/drag_drop_delegate.h"
@@ -220,11 +218,4 @@
   return 1.0f;
 }
 
-bool WMHelper::AreVerifiedSyncTokensNeeded() const {
-  // For mus and mash, the compositor isn't sharing GPU the channel with
-  // exo, so it cannot consume unverified sync token generated by exo.
-  // We need verify sync tokens before sending them to the compositor.
-  return ash::Shell::GetAshConfig() != ash::Config::CLASSIC;
-}
-
 }  // namespace exo
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index fabb42d4..3b34b483 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -97,7 +97,6 @@
   void RemovePostTargetHandler(ui::EventHandler* handler);
   bool IsTabletModeWindowManagerEnabled() const;
   double GetDefaultDeviceScaleFactor() const;
-  bool AreVerifiedSyncTokensNeeded() const;
 
   // Overridden from aura::client::DragDropDelegate:
   void OnDragEntered(const ui::DropTargetEvent& event) override;
diff --git a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java
index d0863fd..7bac546 100644
--- a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java
+++ b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java
@@ -81,7 +81,7 @@
                                          !registrationId.isEmpty());
             }
         }
-                .execute();
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     @CalledByNative
@@ -104,7 +104,7 @@
                 nativeOnUnregisterFinished(mNativeGCMDriverAndroid, appId, success);
             }
         }
-                .execute();
+                .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     // The caller of this function is responsible for ensuring the browser process is initialized.
diff --git a/components/minidump_uploader/OWNERS b/components/minidump_uploader/OWNERS
index 1c0302aa..02ccd6e 100644
--- a/components/minidump_uploader/OWNERS
+++ b/components/minidump_uploader/OWNERS
@@ -1,4 +1,3 @@
-gsennton@chromium.org
 isherman@chromium.org
 
 # COMPONENT: Internals>CrashReporting
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn
index c91410c..a79a59f 100644
--- a/components/mirroring/service/BUILD.gn
+++ b/components/mirroring/service/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//testing/test.gni")
 
-source_set("service") {
+component("mirroring_service") {
   sources = [
     "captured_audio_input.cc",
     "captured_audio_input.h",
@@ -60,6 +60,8 @@
     "//services/network/public/mojom",
     "//ui/gfx",
   ]
+
+  defines = [ "IS_MIRRORING_SERVICE_IMPL" ]
 }
 
 source_set("unittests") {
@@ -83,7 +85,7 @@
   ]
 
   deps = [
-    ":service",
+    ":mirroring_service",
     "//base",
     "//base/test:test_support",
     "//components/mirroring/mojom:service",
diff --git a/components/mirroring/service/captured_audio_input.h b/components/mirroring/service/captured_audio_input.h
index 557861d..cf4441c 100644
--- a/components/mirroring/service/captured_audio_input.h
+++ b/components/mirroring/service/captured_audio_input.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_MIRRORING_SERVICE_CAPTURED_AUDIO_INPUT_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "components/mirroring/mojom/resource_provider.mojom.h"
@@ -17,9 +18,10 @@
 
 // CapturedAudioInput handles the creation, initialization and control of an
 // audio input stream created by Audio Service.
-class CapturedAudioInput final : public media::AudioInputIPC,
-                                 public mojom::AudioStreamCreatorClient,
-                                 public media::mojom::AudioInputStreamClient {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) CapturedAudioInput final
+    : public media::AudioInputIPC,
+      public mojom::AudioStreamCreatorClient,
+      public media::mojom::AudioInputStreamClient {
  public:
   using StreamCreatorCallback =
       base::RepeatingCallback<void(mojom::AudioStreamCreatorClientPtr client,
diff --git a/components/mirroring/service/features.h b/components/mirroring/service/features.h
index 913d437c..bf4e153d 100644
--- a/components/mirroring/service/features.h
+++ b/components/mirroring/service/features.h
@@ -5,11 +5,13 @@
 #ifndef COMPONENTS_MIRRORING_SERVICE_FEATURES_H_
 #define COMPONENTS_MIRRORING_SERVICE_FEATURES_H_
 
+#include "base/component_export.h"
 #include "base/feature_list.h"
 
 namespace mirroring {
 namespace features {
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 extern const base::Feature kMirroringService;
 
 }  // namespace features
diff --git a/components/mirroring/service/media_remoter.h b/components/mirroring/service/media_remoter.h
index edaf8e3c..1910da16 100644
--- a/components/mirroring/service/media_remoter.h
+++ b/components/mirroring/service/media_remoter.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_MIRRORING_SERVICE_MEDIA_REMOTER_H_
 #define COMPONENTS_MIRRORING_SERVICE_MEDIA_REMOTER_H_
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "media/cast/cast_config.h"
 #include "media/mojo/interfaces/remoting.mojom.h"
@@ -37,7 +38,8 @@
 // browser and the Cast Receiver. The audio/video data streams are delivered
 // from the media renderer to the Mirroring Service through mojo datapipes, and
 // are then sent out to Cast Receiver through Cast Streaming.
-class MediaRemoter final : public media::mojom::Remoter {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) MediaRemoter final
+    : public media::mojom::Remoter {
  public:
   class Client {
    public:
diff --git a/components/mirroring/service/message_dispatcher.h b/components/mirroring/service/message_dispatcher.h
index 82205229..3323fae 100644
--- a/components/mirroring/service/message_dispatcher.h
+++ b/components/mirroring/service/message_dispatcher.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_MIRRORING_SERVICE_MESSAGE_DISPATCHER_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "components/mirroring/mojom/cast_message_channel.mojom.h"
@@ -17,7 +18,8 @@
 // Dispatches inbound/outbound messages. The outbound messages are sent out
 // through |outbound_channel|, and the inbound messages are handled by this
 // class.
-class MessageDispatcher final : public mojom::CastMessageChannel {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) MessageDispatcher final
+    : public mojom::CastMessageChannel {
  public:
   using ErrorCallback = base::RepeatingCallback<void(const std::string&)>;
   MessageDispatcher(mojom::CastMessageChannelPtr outbound_channel,
diff --git a/components/mirroring/service/mirror_settings.h b/components/mirroring/service/mirror_settings.h
index ac2ee3c5..11c96c6 100644
--- a/components/mirroring/service/mirror_settings.h
+++ b/components/mirroring/service/mirror_settings.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_MIRRORING_SERVICE_MIRROR_SETTINGS_H_
 #define COMPONENTS_MIRRORING_SERVICE_MIRROR_SETTINGS_H_
 
+#include "base/component_export.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "media/capture/video_capture_types.h"
@@ -22,7 +23,7 @@
 // TODO(xjz): Add the function to generate the audio capture contraints.
 // TODO(xjz): Add setters to the settings that might be overriden by integration
 // tests.
-class MirrorSettings {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) MirrorSettings {
  public:
   MirrorSettings();
   ~MirrorSettings();
diff --git a/components/mirroring/service/receiver_response.h b/components/mirroring/service/receiver_response.h
index 0429e2fc6..152cfd7 100644
--- a/components/mirroring/service/receiver_response.h
+++ b/components/mirroring/service/receiver_response.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/values.h"
 
 namespace mirroring {
@@ -22,7 +23,7 @@
   RPC,                    // Rpc binary messages. The payload is base64 encoded.
 };
 
-struct Answer {
+struct COMPONENT_EXPORT(MIRRORING_SERVICE) Answer {
   Answer();
   ~Answer();
   Answer(const Answer& answer);
@@ -43,7 +44,7 @@
   std::string cast_mode;
 };
 
-struct ReceiverStatus {
+struct COMPONENT_EXPORT(MIRRORING_SERVICE) ReceiverStatus {
   ReceiverStatus();
   ~ReceiverStatus();
   ReceiverStatus(const ReceiverStatus& status);
@@ -56,7 +57,7 @@
   std::vector<int32_t> wifi_speed;
 };
 
-struct ReceiverKeySystem {
+struct COMPONENT_EXPORT(MIRRORING_SERVICE) ReceiverKeySystem {
   ReceiverKeySystem();
   ~ReceiverKeySystem();
   ReceiverKeySystem(const ReceiverKeySystem& receiver_key_system);
@@ -82,7 +83,7 @@
   std::string distinctive_identifier_support;
 };
 
-struct ReceiverCapability {
+struct COMPONENT_EXPORT(MIRRORING_SERVICE) ReceiverCapability {
   ReceiverCapability();
   ~ReceiverCapability();
   ReceiverCapability(const ReceiverCapability& capabilities);
@@ -93,7 +94,7 @@
   std::vector<ReceiverKeySystem> key_systems;
 };
 
-struct ReceiverError {
+struct COMPONENT_EXPORT(MIRRORING_SERVICE) ReceiverError {
   ReceiverError();
   ~ReceiverError();
   bool Parse(const base::Value& raw_value);
@@ -103,7 +104,7 @@
   std::string details;  // In JSON format.
 };
 
-struct ReceiverResponse {
+struct COMPONENT_EXPORT(MIRRORING_SERVICE) ReceiverResponse {
   ReceiverResponse();
   ~ReceiverResponse();
   ReceiverResponse(ReceiverResponse&& receiver_response);
diff --git a/components/mirroring/service/remoting_sender.h b/components/mirroring/service/remoting_sender.h
index d36d005..150eebed 100644
--- a/components/mirroring/service/remoting_sender.h
+++ b/components/mirroring/service/remoting_sender.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -29,8 +30,9 @@
 // RTP sender for a single Cast Remoting RTP stream. The client calls Send() to
 // instruct the sender to read from a Mojo data pipe and transmit the data using
 // a CastTransport.
-class RemotingSender final : public media::mojom::RemotingDataStreamSender,
-                             public media::cast::FrameSender {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) RemotingSender final
+    : public media::mojom::RemotingDataStreamSender,
+      public media::cast::FrameSender {
  public:
   // |transport| is expected to outlive this class.
   RemotingSender(scoped_refptr<media::cast::CastEnvironment> cast_environment,
diff --git a/components/mirroring/service/rtp_stream.h b/components/mirroring/service/rtp_stream.h
index dbbf667..d2a908c3 100644
--- a/components/mirroring/service/rtp_stream.h
+++ b/components/mirroring/service/rtp_stream.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -32,7 +33,7 @@
 
 namespace mirroring {
 
-class RtpStreamClient {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) RtpStreamClient {
  public:
   virtual ~RtpStreamClient() {}
 
@@ -61,7 +62,8 @@
 // regular intervals for a short period of time. This provides the video
 // encoder, downstream, several copies of the last frame so that it may clear up
 // lossy encoding artifacts.
-class VideoRtpStream : public base::SupportsWeakPtr<VideoRtpStream> {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) VideoRtpStream
+    : public base::SupportsWeakPtr<VideoRtpStream> {
  public:
   VideoRtpStream(std::unique_ptr<media::cast::VideoSender> video_sender,
                  base::WeakPtr<RtpStreamClient> client);
@@ -94,7 +96,8 @@
 };
 
 // Receives audio data and submits the data to media::cast::AudioSender.
-class AudioRtpStream : public base::SupportsWeakPtr<AudioRtpStream> {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) AudioRtpStream
+    : public base::SupportsWeakPtr<AudioRtpStream> {
  public:
   AudioRtpStream(std::unique_ptr<media::cast::AudioSender> audio_sender,
                  base::WeakPtr<RtpStreamClient> client);
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h
index ce29e28..ecb266e8 100644
--- a/components/mirroring/service/session.h
+++ b/components/mirroring/service/session.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_MIRRORING_SERVICE_SESSION_H_
 #define COMPONENTS_MIRRORING_SERVICE_SESSION_H_
 
+#include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
@@ -44,7 +45,9 @@
 // occurs. |observer| will get notified when status changes. |outbound_channel|
 // is responsible for sending messages to the mirroring receiver through Cast
 // Channel. |inbound_channel| receives message sent from the mirroring receiver.
-class Session final : public RtpStreamClient, public MediaRemoter::Client {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) Session final
+    : public RtpStreamClient,
+      public MediaRemoter::Client {
  public:
   Session(mojom::SessionParametersPtr session_params,
           const gfx::Size& max_resolution,
diff --git a/components/mirroring/service/session_monitor.h b/components/mirroring/service/session_monitor.h
index 039397e..b43ac57e 100644
--- a/components/mirroring/service/session_monitor.h
+++ b/components/mirroring/service/session_monitor.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -47,7 +48,7 @@
 //
 // To avoid unbounded memory use, older data is discarded automatically if too
 // much is accumulating.
-class SessionMonitor {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) SessionMonitor {
  public:
   using EventsAndStats =
       std::pair<std::string /* events */, std::string /* stats */>;
diff --git a/components/mirroring/service/udp_socket_client.h b/components/mirroring/service/udp_socket_client.h
index c58a7ee..4f9f2b5 100644
--- a/components/mirroring/service/udp_socket_client.h
+++ b/components/mirroring/service/udp_socket_client.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_MIRRORING_SERVICE_UDP_SOCKET_CLIENT_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "media/cast/net/cast_transport_config.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/base/ip_endpoint.h"
@@ -20,8 +21,9 @@
 // |remote_endpoint_| when StartReceiving() is called. Sending/Receiving ends
 // when StopReceiving() is called or this class is destructed. |error_callback|
 // will be called if the UDPSocket is failed to be created or connected.
-class UdpSocketClient final : public media::cast::PacketTransport,
-                              public network::mojom::UDPSocketReceiver {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) UdpSocketClient final
+    : public media::cast::PacketTransport,
+      public network::mojom::UDPSocketReceiver {
  public:
   UdpSocketClient(const net::IPEndPoint& remote_endpoint,
                   network::mojom::NetworkContext* context,
diff --git a/components/mirroring/service/value_util.h b/components/mirroring/service/value_util.h
index d324774..9a57167 100644
--- a/components/mirroring/service/value_util.h
+++ b/components/mirroring/service/value_util.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/component_export.h"
 #include "base/values.h"
 
 namespace mirroring {
@@ -15,25 +16,32 @@
 // false if |key| exists and the type of the data mismatches. Return true
 // otherwise.
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 bool GetInt(const base::Value& value, const std::string& key, int32_t* result);
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 bool GetDouble(const base::Value& value,
                const std::string& key,
                double* result);
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 bool GetString(const base::Value& value,
                const std::string& key,
                std::string* result);
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 bool GetBool(const base::Value& value, const std::string& key, bool* result);
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 bool GetIntArray(const base::Value& value,
                  const std::string& key,
                  std::vector<int32_t>* result);
 
+COMPONENT_EXPORT(MIRRORING_SERVICE)
 bool GetStringArray(const base::Value& value,
                     const std::string& key,
                     std::vector<std::string>* result);
+
 }  // namespace mirroring
 
 #endif  // COMPONENTS_MIRRORING_SERVICE_VALUE_UTIL_H_
diff --git a/components/mirroring/service/video_capture_client.h b/components/mirroring/service/video_capture_client.h
index a417dcde..f7fe833 100644
--- a/components/mirroring/service/video_capture_client.h
+++ b/components/mirroring/service/video_capture_client.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_MIRRORING_SERVICE_VIDEO_CAPTURE_CLIENT_H_
 
 #include "base/callback.h"
+#include "base/component_export.h"
 #include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
@@ -25,7 +26,8 @@
 // media::mojom::VideoCaptureHost interface and requests to launch a video
 // capture device. After the device is started, the captured video frames are
 // received through the media::mojom::VideoCaptureObserver interface.
-class VideoCaptureClient : public media::mojom::VideoCaptureObserver {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) VideoCaptureClient
+    : public media::mojom::VideoCaptureObserver {
  public:
   VideoCaptureClient(const media::VideoCaptureParams& params,
                      media::mojom::VideoCaptureHostPtr host);
diff --git a/components/mirroring/service/wifi_status_monitor.h b/components/mirroring/service/wifi_status_monitor.h
index b6f9b6fd..ef68793a 100644
--- a/components/mirroring/service/wifi_status_monitor.h
+++ b/components/mirroring/service/wifi_status_monitor.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/time/time.h"
@@ -27,7 +28,7 @@
 // updates, processes responses, and maintains a recent history of data points.
 // This data can be included in feedback logs to help identify and diagnose
 // issues related to lousy network performance.
-class WifiStatusMonitor {
+class COMPONENT_EXPORT(MIRRORING_SERVICE) WifiStatusMonitor {
  public:
   // |message_dispatcher| must keep alive during the lifetime of this class.
   explicit WifiStatusMonitor(MessageDispatcher* message_dispatcher);
diff --git a/components/offline_items_collection/core/BUILD.gn b/components/offline_items_collection/core/BUILD.gn
index f4eb2d53..ad8419c 100644
--- a/components/offline_items_collection/core/BUILD.gn
+++ b/components/offline_items_collection/core/BUILD.gn
@@ -40,6 +40,8 @@
       "android/offline_content_aggregator_bridge.h",
       "android/offline_item_bridge.cc",
       "android/offline_item_bridge.h",
+      "android/offline_item_share_info_bridge.cc",
+      "android/offline_item_share_info_bridge.h",
       "android/offline_item_visuals_bridge.cc",
       "android/offline_item_visuals_bridge.h",
     ]
@@ -68,13 +70,16 @@
   android_library("core_java") {
     java_files = [
       "android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemBridge.java",
+      "android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemShareInfoBridge.java",
       "android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemVisualsBridge.java",
       "android/java/src/org/chromium/components/offline_items_collection/ContentId.java",
       "android/java/src/org/chromium/components/offline_items_collection/LegacyHelpers.java",
       "android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java",
       "android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java",
       "android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java",
+      "android/java/src/org/chromium/components/offline_items_collection/OfflineItemShareInfo.java",
       "android/java/src/org/chromium/components/offline_items_collection/OfflineItemVisuals.java",
+      "android/java/src/org/chromium/components/offline_items_collection/ShareCallback.java",
       "android/java/src/org/chromium/components/offline_items_collection/VisualsCallback.java",
     ]
 
@@ -92,6 +97,7 @@
     sources = [
       "android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java",
       "android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemBridge.java",
+      "android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemShareInfoBridge.java",
       "android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemVisualsBridge.java",
     ]
 
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
index a1ad7b8..e71dc41d 100644
--- a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
@@ -87,6 +87,12 @@
     }
 
     @Override
+    public void getShareInfoForItem(ContentId id, ShareCallback callback) {
+        nativeGetShareInfoForItem(
+                mNativeOfflineContentAggregatorBridge, id.namespace, id.id, callback);
+    }
+
+    @Override
     public void addObserver(final OfflineContentProvider.Observer observer) {
         mObservers.addObserver(observer);
     }
@@ -128,6 +134,12 @@
         callback.onVisualsAvailable(new ContentId(nameSpace, id), visuals);
     }
 
+    @CalledByNative
+    private static void onShareInfoAvailable(
+            ShareCallback callback, String nameSpace, String id, OfflineItemShareInfo shareInfo) {
+        callback.onShareInfoAvailable(new ContentId(nameSpace, id), shareInfo);
+    }
+
     /**
      * Called when the C++ OfflineContentAggregatorBridge is destroyed.  This tears down the Java
      * component of the JNI bridge so that this class, which may live due to other references, no
@@ -167,4 +179,6 @@
             long nativeOfflineContentAggregatorBridge, Callback<ArrayList<OfflineItem>> callback);
     private native void nativeGetVisualsForItem(long nativeOfflineContentAggregatorBridge,
             String nameSpace, String id, VisualsCallback callback);
+    private native void nativeGetShareInfoForItem(long nativeOfflineContentAggregatorBridge,
+            String nameSpace, String id, ShareCallback callback);
 }
\ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
index 254951e..30d711c 100644
--- a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
@@ -52,6 +52,9 @@
     /** See OfflineContentProvider::GetVisualsForItem(...). */
     void getVisualsForItem(ContentId id, VisualsCallback callback);
 
+    /** See OfflineContentProvider::GetShareInfoForItem(...). */
+    void getShareInfoForItem(ContentId id, ShareCallback callback);
+
     /** See OfflineContentProvider::AddObserver(...). */
     void addObserver(Observer observer);
 
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java
index f4f584a..a8ad9d0 100644
--- a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItem.java
@@ -74,6 +74,7 @@
     public boolean isTransient;
     public boolean isSuggested;
     public boolean isAccelerated;
+    public boolean refreshVisuals;
 
     // Content Metadata.
     public long totalSizeBytes;
@@ -119,6 +120,7 @@
         clone.isTransient = isTransient;
         clone.isSuggested = isSuggested;
         clone.isAccelerated = isAccelerated;
+        clone.refreshVisuals = refreshVisuals;
         clone.totalSizeBytes = totalSizeBytes;
         clone.externallyRemoved = externallyRemoved;
         clone.creationTimeMs = creationTimeMs;
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItemShareInfo.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItemShareInfo.java
new file mode 100644
index 0000000..cf5b041d
--- /dev/null
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineItemShareInfo.java
@@ -0,0 +1,16 @@
+// 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.
+
+package org.chromium.components.offline_items_collection;
+
+import android.net.Uri;
+
+/**
+ * This class is the Java counterpart to the C++ OfflineItemShareInfo
+ * (components/offline_items_collection/core/offline_item.h) class.
+ *
+ * For all member variable descriptions see the C++ class.
+ * TODO(dtrainor): Investigate making all class members for this and the C++ counterpart const.
+ */
+public class OfflineItemShareInfo { public Uri uri; }
\ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/ShareCallback.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/ShareCallback.java
new file mode 100644
index 0000000..84fdceb
--- /dev/null
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/ShareCallback.java
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.offline_items_collection;
+
+import android.support.annotation.Nullable;
+
+/**
+ * This interface is a Java counterpart to the C++ base::Callback meant to be used in response
+ * to {@link OfflineItemShareInfo} requests.
+ */
+public interface ShareCallback {
+    /**
+     * @param id        The {@link ContentId} that {@code shareInfo} is associated with.
+     * @param shareInfo The {@link OfflineItemShareInfo}, if any, associated with {@code id}.
+     */
+    void onShareInfoAvailable(ContentId id, @Nullable OfflineItemShareInfo shareInfo);
+}
\ No newline at end of file
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemBridge.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemBridge.java
index 8f826e05..0a5b5700 100644
--- a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemBridge.java
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemBridge.java
@@ -45,11 +45,12 @@
     private static OfflineItem createOfflineItemAndMaybeAddToList(ArrayList<OfflineItem> list,
             String nameSpace, String id, String title, String description,
             @OfflineItemFilter int filter, boolean isTransient, boolean isSuggested,
-            boolean isAccelerated, long totalSizeBytes, boolean externallyRemoved,
-            long creationTimeMs, long lastAccessedTimeMs, boolean isOpenable, String filePath,
-            String mimeType, String pageUrl, String originalUrl, boolean isOffTheRecord,
-            @OfflineItemState int state, @PendingState int pendingState, boolean isResumable,
-            boolean allowMetered, long receivedBytes, long progressValue, long progressMax,
+            boolean isAccelerated, boolean refreshVisuals, long totalSizeBytes,
+            boolean externallyRemoved, long creationTimeMs, long lastAccessedTimeMs,
+            boolean isOpenable, String filePath, String mimeType, String pageUrl,
+            String originalUrl, boolean isOffTheRecord, @OfflineItemState int state,
+            @PendingState int pendingState, boolean isResumable, boolean allowMetered,
+            long receivedBytes, long progressValue, long progressMax,
             @OfflineItemProgressUnit int progressUnit, long timeRemainingMs, boolean isDangerous) {
         OfflineItem item = new OfflineItem();
         item.id.namespace = nameSpace;
@@ -60,6 +61,7 @@
         item.isTransient = isTransient;
         item.isSuggested = isSuggested;
         item.isAccelerated = isAccelerated;
+        item.refreshVisuals = refreshVisuals;
         item.totalSizeBytes = totalSizeBytes;
         item.externallyRemoved = externallyRemoved;
         item.creationTimeMs = creationTimeMs;
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemShareInfoBridge.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemShareInfoBridge.java
new file mode 100644
index 0000000..fc4f9b7
--- /dev/null
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/bridges/OfflineItemShareInfoBridge.java
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.offline_items_collection.bridges;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
+
+/**
+ * The Java counterpart to the C++ class OfflineItemShareInfoBridge
+ * (components/offline_items_collection/core/android/offline_item_share_info_bridge.h).  This class
+ * has no public members or methods and is meant as a private factory to build
+ * {@link OfflineItemShareInfo} instances.
+ */
+@JNINamespace("offline_items_collection::android")
+public final class OfflineItemShareInfoBridge {
+    private OfflineItemShareInfoBridge() {}
+
+    /**
+     * This is a helper method to allow C++ to create an {@link OfflineItemShareInfo} object.
+     * @return The newly created {@link OfflineItemShareInfo} based on the input parameters.
+     */
+    @CalledByNative
+    private static OfflineItemShareInfo createOfflineItemShareInfo(String uri) {
+        OfflineItemShareInfo shareInfo = new OfflineItemShareInfo();
+        if (!TextUtils.isEmpty(uri)) shareInfo.uri = Uri.parse(uri);
+        return shareInfo;
+    }
+}
\ No newline at end of file
diff --git a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
index 407811c6..6c9e7129 100644
--- a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
+++ b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/offline_items_collection/core/android/offline_item_bridge.h"
+#include "components/offline_items_collection/core/android/offline_item_share_info_bridge.h"
 #include "components/offline_items_collection/core/android/offline_item_visuals_bridge.h"
 #include "components/offline_items_collection/core/offline_item.h"
 #include "components/offline_items_collection/core/throttled_offline_content_provider.h"
@@ -39,6 +40,8 @@
                    ConvertJavaStringToUTF8(env, j_id));
 }
 
+// Helper callback that glues the Java-specific callback logic to the native
+// VisualsCallback that is required by the OfflineContentProvider native class.
 void GetVisualsForItemHelperCallback(
     ScopedJavaGlobalRef<jobject> j_callback,
     const ContentId& id,
@@ -51,6 +54,18 @@
                                                          std::move(visuals)));
 }
 
+void ForwardShareInfoToJavaCallback(
+    ScopedJavaGlobalRef<jobject> j_callback,
+    const ContentId& id,
+    std::unique_ptr<OfflineItemShareInfo> shareInfo) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_OfflineContentAggregatorBridge_onShareInfoAvailable(
+      env, j_callback, ConvertUTF8ToJavaString(env, id.name_space),
+      ConvertUTF8ToJavaString(env, id.id),
+      OfflineItemShareInfoBridge::CreateOfflineItemShareInfo(
+          env, std::move(shareInfo)));
+}
+
 void RunGetAllItemsCallback(const base::android::JavaRef<jobject>& j_callback,
                             const std::vector<OfflineItem>& items) {
   JNIEnv* env = AttachCurrentThread();
@@ -185,8 +200,21 @@
   provider_->GetVisualsForItem(
       JNI_OfflineContentAggregatorBridge_CreateContentId(env, j_namespace,
                                                          j_id),
-      base::Bind(&GetVisualsForItemHelperCallback,
-                 ScopedJavaGlobalRef<jobject>(env, j_callback)));
+      base::BindOnce(&GetVisualsForItemHelperCallback,
+                     ScopedJavaGlobalRef<jobject>(env, j_callback)));
+}
+
+void OfflineContentAggregatorBridge::GetShareInfoForItem(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jobj,
+    const JavaParamRef<jstring>& j_namespace,
+    const JavaParamRef<jstring>& j_id,
+    const JavaParamRef<jobject>& j_callback) {
+  provider_->GetShareInfoForItem(
+      JNI_OfflineContentAggregatorBridge_CreateContentId(env, j_namespace,
+                                                         j_id),
+      base::BindOnce(&ForwardShareInfoToJavaCallback,
+                     ScopedJavaGlobalRef<jobject>(env, j_callback)));
 }
 
 void OfflineContentAggregatorBridge::OnItemsAdded(
diff --git a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
index e55f337..862cc018 100644
--- a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
+++ b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
@@ -72,6 +72,12 @@
       const base::android::JavaParamRef<jstring>& j_namespace,
       const base::android::JavaParamRef<jstring>& j_id,
       const base::android::JavaParamRef<jobject>& j_callback);
+  void GetShareInfoForItem(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jobj,
+      const base::android::JavaParamRef<jstring>& j_namespace,
+      const base::android::JavaParamRef<jstring>& j_id,
+      const base::android::JavaParamRef<jobject>& j_callback);
 
  private:
   OfflineContentAggregatorBridge(OfflineContentAggregator* aggregator);
diff --git a/components/offline_items_collection/core/android/offline_item_bridge.cc b/components/offline_items_collection/core/android/offline_item_bridge.cc
index 19eb372..58ef3b4 100644
--- a/components/offline_items_collection/core/android/offline_item_bridge.cc
+++ b/components/offline_items_collection/core/android/offline_item_bridge.cc
@@ -33,9 +33,10 @@
       ConvertUTF8ToJavaString(env, item.title),
       ConvertUTF8ToJavaString(env, item.description),
       static_cast<jint>(item.filter), item.is_transient, item.is_suggested,
-      item.is_accelerated, item.total_size_bytes, item.externally_removed,
-      item.creation_time.ToJavaTime(), item.last_accessed_time.ToJavaTime(),
-      item.is_openable, ConvertUTF8ToJavaString(env, item.file_path.value()),
+      item.is_accelerated, item.refresh_visuals, item.total_size_bytes,
+      item.externally_removed, item.creation_time.ToJavaTime(),
+      item.last_accessed_time.ToJavaTime(), item.is_openable,
+      ConvertUTF8ToJavaString(env, item.file_path.value()),
       ConvertUTF8ToJavaString(env, item.mime_type),
       ConvertUTF8ToJavaString(env, item.page_url.spec()),
       ConvertUTF8ToJavaString(env, item.original_url.spec()),
diff --git a/components/offline_items_collection/core/android/offline_item_share_info_bridge.cc b/components/offline_items_collection/core/android/offline_item_share_info_bridge.cc
new file mode 100644
index 0000000..c46b4a4
--- /dev/null
+++ b/components/offline_items_collection/core/android/offline_item_share_info_bridge.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_items_collection/core/android/offline_item_share_info_bridge.h"
+
+#include "base/android/jni_string.h"
+#include "components/offline_items_collection/core/offline_item.h"
+#include "jni/OfflineItemShareInfoBridge_jni.h"
+
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
+
+namespace offline_items_collection {
+namespace android {
+
+// static
+ScopedJavaLocalRef<jobject>
+OfflineItemShareInfoBridge::CreateOfflineItemShareInfo(
+    JNIEnv* env,
+    std::unique_ptr<OfflineItemShareInfo> const share_info) {
+  if (!share_info)
+    return nullptr;
+
+  return Java_OfflineItemShareInfoBridge_createOfflineItemShareInfo(
+      env, ConvertUTF8ToJavaString(env, share_info->uri.value()));
+}
+
+}  // namespace android
+}  // namespace offline_items_collection
diff --git a/components/offline_items_collection/core/android/offline_item_share_info_bridge.h b/components/offline_items_collection/core/android/offline_item_share_info_bridge.h
new file mode 100644
index 0000000..74d365d
--- /dev/null
+++ b/components/offline_items_collection/core/android/offline_item_share_info_bridge.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_SHARE_INFO_BRIDGE_H_
+#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_SHARE_INFO_BRIDGE_H_
+
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+namespace offline_items_collection {
+
+struct OfflineItemShareInfo;
+
+namespace android {
+
+// A helper class for creating Java OfflineItemShareInfo instances from the C++
+// OfflineItemShareInfo counterpart.
+class OfflineItemShareInfoBridge {
+ public:
+  // Creates a Java OfflineItemVisuals from |visuals|.
+  static base::android::ScopedJavaLocalRef<jobject> CreateOfflineItemShareInfo(
+      JNIEnv* env,
+      std::unique_ptr<OfflineItemShareInfo> share_info);
+
+ private:
+  OfflineItemShareInfoBridge();
+};
+
+}  // namespace android
+}  // namespace offline_items_collection
+
+#endif  // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_ANDROID_OFFLINE_ITEM_SHARE_INFO_BRIDGE_H_
diff --git a/components/offline_items_collection/core/offline_content_aggregator.cc b/components/offline_items_collection/core/offline_content_aggregator.cc
index 18dcc4f..09e2b811 100644
--- a/components/offline_items_collection/core/offline_content_aggregator.cc
+++ b/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -182,19 +182,31 @@
     std::move(callback).Run(item_vec);
 }
 
-void OfflineContentAggregator::GetVisualsForItem(
-    const ContentId& id,
-    const VisualsCallback& callback) {
+void OfflineContentAggregator::GetVisualsForItem(const ContentId& id,
+                                                 VisualsCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto it = providers_.find(id.name_space);
 
   if (it == providers_.end()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, id, nullptr));
+        FROM_HERE, base::BindOnce(std::move(callback), id, nullptr));
     return;
   }
 
-  it->second->GetVisualsForItem(id, callback);
+  it->second->GetVisualsForItem(id, std::move(callback));
+}
+
+void OfflineContentAggregator::GetShareInfoForItem(const ContentId& id,
+                                                   ShareCallback callback) {
+  auto it = providers_.find(id.name_space);
+
+  if (it == providers_.end()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), id, nullptr));
+    return;
+  }
+
+  it->second->GetShareInfoForItem(id, std::move(callback));
 }
 
 void OfflineContentAggregator::AddObserver(
diff --git a/components/offline_items_collection/core/offline_content_aggregator.h b/components/offline_items_collection/core/offline_content_aggregator.h
index f9f4d8e..0ae4163 100644
--- a/components/offline_items_collection/core/offline_content_aggregator.h
+++ b/components/offline_items_collection/core/offline_content_aggregator.h
@@ -65,7 +65,10 @@
   void GetItemById(const ContentId& id, SingleItemCallback callback) override;
   void GetAllItems(MultipleItemCallback callback) override;
   void GetVisualsForItem(const ContentId& id,
-                         const VisualsCallback& callback) override;
+                         VisualsCallback callback) override;
+  void GetShareInfoForItem(const ContentId& id,
+                           ShareCallback callback) override;
+
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
diff --git a/components/offline_items_collection/core/offline_content_aggregator_unittest.cc b/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
index 5864889..0e64a2c1 100644
--- a/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
+++ b/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
@@ -187,6 +187,8 @@
   EXPECT_CALL(provider2, PauseDownload(id2)).Times(1);
   EXPECT_CALL(provider1, GetVisualsForItem(id1, _)).Times(1);
   EXPECT_CALL(provider2, GetVisualsForItem(id2, _)).Times(1);
+  EXPECT_CALL(provider1, GetShareInfoForItem(id1, _)).Times(1);
+  EXPECT_CALL(provider2, GetShareInfoForItem(id2, _)).Times(1);
   aggregator_.OpenItem(id1);
   aggregator_.OpenItem(id2);
   aggregator_.RemoveItem(id1);
@@ -199,6 +201,8 @@
   aggregator_.PauseDownload(id2);
   aggregator_.GetVisualsForItem(id1, OfflineContentProvider::VisualsCallback());
   aggregator_.GetVisualsForItem(id2, OfflineContentProvider::VisualsCallback());
+  aggregator_.GetShareInfoForItem(id1, OfflineContentProvider::ShareCallback());
+  aggregator_.GetShareInfoForItem(id2, OfflineContentProvider::ShareCallback());
 }
 
 TEST_F(OfflineContentAggregatorTest, ActionPropagatesImmediately) {
diff --git a/components/offline_items_collection/core/offline_content_provider.h b/components/offline_items_collection/core/offline_content_provider.h
index 0d225ebc..e86b9ca 100644
--- a/components/offline_items_collection/core/offline_content_provider.h
+++ b/components/offline_items_collection/core/offline_content_provider.h
@@ -17,6 +17,7 @@
 
 struct ContentId;
 struct OfflineItem;
+struct OfflineItemShareInfo;
 struct OfflineItemVisuals;
 
 // A provider of a set of OfflineItems that are meant to be exposed to the UI.
@@ -24,8 +25,11 @@
  public:
   using OfflineItemList = std::vector<OfflineItem>;
   using VisualsCallback =
-      base::Callback<void(const ContentId&,
-                          std::unique_ptr<OfflineItemVisuals>)>;
+      base::OnceCallback<void(const ContentId&,
+                              std::unique_ptr<OfflineItemVisuals>)>;
+  using ShareCallback =
+      base::OnceCallback<void(const ContentId&,
+                              std::unique_ptr<OfflineItemShareInfo>)>;
   using MultipleItemCallback = base::OnceCallback<void(const OfflineItemList&)>;
   using SingleItemCallback =
       base::OnceCallback<void(const base::Optional<OfflineItem>&)>;
@@ -92,8 +96,19 @@
   // |id| or |nullptr| if one doesn't exist.  The implementer should post any
   // replies even if the results are available immediately to prevent reentrancy
   // and for consistent behavior.
+  // |callback| should be called no matter what (error, unavailable content,
+  // etc.).
   virtual void GetVisualsForItem(const ContentId& id,
-                                 const VisualsCallback& callback) = 0;
+                                 VisualsCallback callback) = 0;
+
+  // Asks for the right URI to use to share an OfflineItem represented by |id|
+  // or |nullptr| if there is no associated information to use to share the
+  // item.  Implementer should post any replies even if the results are
+  // available immediately to prevent reentrancy and for consistent behavior.
+  // |callback| should be called no matter what (error, unavailable content,
+  // etc.).
+  virtual void GetShareInfoForItem(const ContentId& id,
+                                   ShareCallback callback) = 0;
 
   // Adds an observer that should be notified of OfflineItem list modifications.
   virtual void AddObserver(Observer* observer) = 0;
diff --git a/components/offline_items_collection/core/offline_item.cc b/components/offline_items_collection/core/offline_item.cc
index 2a31be2..993d4efb 100644
--- a/components/offline_items_collection/core/offline_item.cc
+++ b/components/offline_items_collection/core/offline_item.cc
@@ -43,6 +43,7 @@
       is_transient(false),
       is_suggested(false),
       is_accelerated(false),
+      refresh_visuals(false),
       total_size_bytes(0),
       externally_removed(false),
       is_openable(false),
@@ -71,6 +72,7 @@
          is_transient == offline_item.is_transient &&
          is_suggested == offline_item.is_suggested &&
          is_accelerated == offline_item.is_accelerated &&
+         refresh_visuals == offline_item.refresh_visuals &&
          total_size_bytes == offline_item.total_size_bytes &&
          externally_removed == offline_item.externally_removed &&
          creation_time == offline_item.creation_time &&
@@ -96,4 +98,9 @@
     default;
 OfflineItemVisuals::~OfflineItemVisuals() = default;
 
+OfflineItemShareInfo::OfflineItemShareInfo() = default;
+OfflineItemShareInfo::OfflineItemShareInfo(const OfflineItemShareInfo& other) =
+    default;
+OfflineItemShareInfo::~OfflineItemShareInfo() = default;
+
 }  // namespace offline_items_collection
diff --git a/components/offline_items_collection/core/offline_item.h b/components/offline_items_collection/core/offline_item.h
index 0426be0..f86765c 100644
--- a/components/offline_items_collection/core/offline_item.h
+++ b/components/offline_items_collection/core/offline_item.h
@@ -116,6 +116,9 @@
   // Whether this item is going through accelerated download.
   bool is_accelerated;
 
+  // Whether there are new visuals available.
+  bool refresh_visuals;
+
   // TODO(dtrainor): Build out custom per-item icon support.
 
   // Content Metadata.
@@ -213,6 +216,24 @@
   gfx::Image icon;
 };
 
+// This struct holds additional information related to sharing a particular
+// OfflineItem.  This information doesn't necessarily exist within OfflineItem
+// because it may be expensive/unnecessary to compute until the user attempts to
+// share the item.
+struct OfflineItemShareInfo {
+  OfflineItemShareInfo();
+  OfflineItemShareInfo(const OfflineItemShareInfo& other);
+
+  ~OfflineItemShareInfo();
+
+  // The local URI where the file can be accessed on disk.  This may be
+  // different from |OfflineItem::file_path| depending on whether or not the
+  // file can be accessed directly.
+  // If this path is invalid the request data from OfflineItem will be used
+  // to share the information instead (e.g. |OfflineItem::page_url|).
+  base::FilePath uri;
+};
+
 }  // namespace offline_items_collection
 
 #endif  // COMPONENTS_OFFLINE_ITEMS_COLLECTION_OFFLINE_ITEM_H_
diff --git a/components/offline_items_collection/core/test_support/mock_offline_content_provider.h b/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
index f4c427e..a6279fc 100644
--- a/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
+++ b/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
@@ -41,8 +41,8 @@
   MOCK_METHOD1(CancelDownload, void(const ContentId&));
   MOCK_METHOD1(PauseDownload, void(const ContentId&));
   MOCK_METHOD2(ResumeDownload, void(const ContentId&, bool));
-  MOCK_METHOD2(GetVisualsForItem,
-               void(const ContentId&, const VisualsCallback&));
+  MOCK_METHOD2(GetVisualsForItem, void(const ContentId&, VisualsCallback));
+  MOCK_METHOD2(GetShareInfoForItem, void(const ContentId&, ShareCallback));
   void GetAllItems(MultipleItemCallback callback) override;
   void GetItemById(const ContentId& id, SingleItemCallback callback) override;
   void AddObserver(Observer* observer) override;
diff --git a/components/offline_items_collection/core/test_support/offline_item_test_support.cc b/components/offline_items_collection/core/test_support/offline_item_test_support.cc
index 6a221a9..a45b381 100644
--- a/components/offline_items_collection/core/test_support/offline_item_test_support.cc
+++ b/components/offline_items_collection/core/test_support/offline_item_test_support.cc
@@ -22,6 +22,7 @@
   os << ", is_transient: " << item.is_transient;
   os << ", is_suggested: " << item.is_suggested;
   os << ", is_accelerated: " << item.is_accelerated;
+  os << ", refresh_visuals: " << item.refresh_visuals;
   os << ", total_size_bytes: " << item.total_size_bytes;
   os << ", externally_removed: " << item.externally_removed;
   os << ", creation_time: " << item.creation_time;
diff --git a/components/offline_items_collection/core/throttled_offline_content_provider.cc b/components/offline_items_collection/core/throttled_offline_content_provider.cc
index d712f78..4064d68 100644
--- a/components/offline_items_collection/core/throttled_offline_content_provider.cc
+++ b/components/offline_items_collection/core/throttled_offline_content_provider.cc
@@ -96,8 +96,14 @@
 
 void ThrottledOfflineContentProvider::GetVisualsForItem(
     const ContentId& id,
-    const VisualsCallback& callback) {
-  wrapped_provider_->GetVisualsForItem(id, callback);
+    VisualsCallback callback) {
+  wrapped_provider_->GetVisualsForItem(id, std::move(callback));
+}
+
+void ThrottledOfflineContentProvider::GetShareInfoForItem(
+    const ContentId& id,
+    ShareCallback callback) {
+  wrapped_provider_->GetShareInfoForItem(id, std::move(callback));
 }
 
 void ThrottledOfflineContentProvider::AddObserver(
diff --git a/components/offline_items_collection/core/throttled_offline_content_provider.h b/components/offline_items_collection/core/throttled_offline_content_provider.h
index 1558128..69fe5e5 100644
--- a/components/offline_items_collection/core/throttled_offline_content_provider.h
+++ b/components/offline_items_collection/core/throttled_offline_content_provider.h
@@ -45,7 +45,9 @@
   void GetItemById(const ContentId& id, SingleItemCallback callback) override;
   void GetAllItems(MultipleItemCallback callback) override;
   void GetVisualsForItem(const ContentId& id,
-                         const VisualsCallback& callback) override;
+                         VisualsCallback callback) override;
+  void GetShareInfoForItem(const ContentId& id,
+                           ShareCallback callback) override;
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.cc b/components/offline_pages/core/downloads/download_ui_adapter.cc
index a8ce641..6915ed00 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -231,26 +231,35 @@
       std::move(callback), std::move(offline_items)));
 }
 
-void DownloadUIAdapter::GetVisualsForItem(
-    const ContentId& id,
-    const VisualsCallback& visuals_callback) {
-  model_->GetPageByGuid(
-      id.id,
-      base::BindOnce(&DownloadUIAdapter::OnPageGetForVisuals,
-                     weak_ptr_factory_.GetWeakPtr(), id, visuals_callback));
+void DownloadUIAdapter::GetVisualsForItem(const ContentId& id,
+                                          VisualsCallback visuals_callback) {
+  model_->GetPageByGuid(id.id,
+                        base::BindOnce(&DownloadUIAdapter::OnPageGetForVisuals,
+                                       weak_ptr_factory_.GetWeakPtr(), id,
+                                       std::move(visuals_callback)));
 }
 
-void DownloadUIAdapter::OnPageGetForVisuals(
-    const ContentId& id,
-    const VisualsCallback& visuals_callback,
-    const OfflinePageItem* page) {
+void DownloadUIAdapter::GetShareInfoForItem(const ContentId& id,
+                                            ShareCallback callback) {
+  // TODO(853850): Publish and expose the content URI here instead of in
+  // DownloadUtils.java.
+  // TODO(xingliu): Provide OfflineItemShareInfo to |callback|.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), id,
+                                nullptr /* OfflineItemShareInfo */));
+}
+
+void DownloadUIAdapter::OnPageGetForVisuals(const ContentId& id,
+                                            VisualsCallback visuals_callback,
+                                            const OfflinePageItem* page) {
   if (!page) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(visuals_callback, id, nullptr));
+        FROM_HERE, base::BindOnce(std::move(visuals_callback), id, nullptr));
     return;
   }
 
-  VisualResultCallback callback = base::BindOnce(visuals_callback, id);
+  VisualResultCallback callback =
+      base::BindOnce(std::move(visuals_callback), id);
   if (page->client_id.name_space == kSuggestedArticlesNamespace) {
     // Report PrefetchedItemHasThumbnail along with result callback.
     auto report_and_callback =
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.h b/components/offline_pages/core/downloads/download_ui_adapter.h
index ab1e738..c9c48cb1 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.h
+++ b/components/offline_pages/core/downloads/download_ui_adapter.h
@@ -91,7 +91,9 @@
   void GetAllItems(
       OfflineContentProvider::MultipleItemCallback callback) override;
   void GetVisualsForItem(const ContentId& id,
-                         const VisualsCallback& callback) override;
+                         VisualsCallback callback) override;
+  void GetShareInfoForItem(const ContentId& id,
+                           ShareCallback callback) override;
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
@@ -139,7 +141,7 @@
       std::unique_ptr<OfflineContentProvider::OfflineItemList> offline_items,
       std::vector<std::unique_ptr<SavePageRequest>> requests);
   void OnPageGetForVisuals(const ContentId& id,
-                           const VisualsCallback& visuals_callback,
+                           VisualsCallback visuals_callback,
                            const OfflinePageItem* page);
   void OnPageGetForGetItem(const ContentId& id,
                            OfflineContentProvider::SingleItemCallback callback,
diff --git a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
index da51771..97204fe8 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -675,6 +675,44 @@
   EXPECT_TRUE(called);
 }
 
+TEST_F(DownloadUIAdapterTest, GetShareInfoForItem) {
+  AddInitialPage(kTestClientIdPrefetch);
+  bool called = false;
+  auto callback = base::BindLambdaForTesting(
+      [&](const offline_items_collection::ContentId& id,
+          std::unique_ptr<offline_items_collection::OfflineItemShareInfo>
+              share_info) {
+        EXPECT_EQ(kTestContentId1, id);
+        // TODO(853850): Properly test that the correct URI is used once
+        // supported.
+        EXPECT_FALSE(share_info);
+        called = true;
+      });
+
+  adapter->GetShareInfoForItem(kTestContentId1, callback);
+  PumpLoop();
+
+  EXPECT_TRUE(called);
+}
+
+TEST_F(DownloadUIAdapterTest, GetShareInfoForItemInvalidItem) {
+  AddInitialPage(kTestClientIdPrefetch);
+  const ContentId kContentID("not", "valid");
+  bool called = false;
+  auto callback = base::BindLambdaForTesting(
+      [&](const offline_items_collection::ContentId& id,
+          std::unique_ptr<offline_items_collection::OfflineItemShareInfo>
+              share_info) {
+        EXPECT_EQ(kContentID, id);
+        EXPECT_FALSE(share_info);
+        called = true;
+      });
+  adapter->GetShareInfoForItem(kContentID, callback);
+  PumpLoop();
+
+  EXPECT_TRUE(called);
+}
+
 TEST_F(DownloadUIAdapterTest, ThumbnailAddedUpdatesItem) {
   // Add an item without a thumbnail. Then notify the adapter about the added
   // thumbnail. It should notify the delegate about the updated item.
diff --git a/components/omnibox/browser/omnibox_client.cc b/components/omnibox/browser/omnibox_client.cc
index 9938d2b..598d847 100644
--- a/components/omnibox/browser/omnibox_client.cc
+++ b/components/omnibox/browser/omnibox_client.cc
@@ -57,6 +57,10 @@
   return false;
 }
 
+bool OmniboxClient::IsDefaultSearchProviderEnabled() const {
+  return true;
+}
+
 bookmarks::BookmarkModel* OmniboxClient::GetBookmarkModel() {
   return nullptr;
 }
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h
index de88b39..ddc5a86 100644
--- a/components/omnibox/browser/omnibox_client.h
+++ b/components/omnibox/browser/omnibox_client.h
@@ -83,6 +83,9 @@
   // Returns whether |url| corresponds to the user's home page.
   virtual bool IsHomePage(const GURL& url) const;
 
+  // Returns false if Default Search is disabled by a policy.
+  virtual bool IsDefaultSearchProviderEnabled() const;
+
   // Returns the session ID of the current page.
   virtual const SessionID& GetSessionID() const = 0;
 
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index c437ed9..3377a3e 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -556,6 +556,9 @@
 
 void OmniboxEditModel::EnterKeywordModeForDefaultSearchProvider(
     KeywordModeEntryMethod entry_method) {
+  if (!client_->IsDefaultSearchProviderEnabled())
+    return;
+
   autocomplete_controller()->Stop(false);
 
   keyword_ =
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index cb0941cf..3cfe66c 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -55,6 +55,7 @@
       profile_comparator_(app_locale, *spec),
       weak_ptr_factory_(this) {
   if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) {
+    DCHECK(web_contents);
     get_all_instruments_finished_ = false;
     ServiceWorkerPaymentAppFactory::GetInstance()->GetAllPaymentApps(
         web_contents,
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc
index a2763ed..6e618f2 100644
--- a/components/payments/content/payment_request_state_unittest.cc
+++ b/components/payments/content/payment_request_state_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/guid.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
@@ -16,6 +17,7 @@
 #include "components/payments/content/payment_request_spec.h"
 #include "components/payments/content/test_content_payment_request_delegate.h"
 #include "components/payments/core/journey_logger.h"
+#include "content/public/common/content_features.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/modules/payments/payment_request.mojom.h"
@@ -33,6 +35,8 @@
                         ukm::UkmRecorder::GetNewSourceID()),
         address_(autofill::test::GetFullProfile()),
         credit_card_visa_(autofill::test::GetCreditCard()) {
+    scoped_feature_list_.InitAndDisableFeature(
+        features::kServiceWorkerPaymentApps);
     test_personal_data_manager_.SetAutofillCreditCardEnabled(true);
     test_personal_data_manager_.SetAutofillProfileEnabled(true);
     test_personal_data_manager_.SetAutofillWalletImportEnabled(true);
@@ -119,6 +123,7 @@
   }
 
  private:
+  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<PaymentRequestState> state_;
   std::unique_ptr<PaymentRequestSpec> spec_;
   int num_on_selected_information_changed_called_;
diff --git a/components/payments/core/features.cc b/components/payments/core/features.cc
index 5e9a313b3..ce5eb5b 100644
--- a/components/payments/core/features.cc
+++ b/components/payments/core/features.cc
@@ -24,13 +24,8 @@
 const base::Feature kWebPaymentsModifiers{"WebPaymentsModifiers",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
-#if defined(OS_ANDROID)
 const base::Feature kWebPaymentsSingleAppUiSkip{
     "WebPaymentsSingleAppUiSkip", base::FEATURE_ENABLED_BY_DEFAULT};
-#else
-const base::Feature kWebPaymentsSingleAppUiSkip{
-    "WebPaymentsSingleAppUiSkip", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
 
 const base::Feature kWebPaymentsJustInTimePaymentApp{
     "WebPaymentsJustInTimePaymentApp", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 06a35ee..513639dd 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -12623,10 +12623,11 @@
       'name': 'WebRtcEventLogCollectionAllowed',
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      # TODO(crbug.com/775415): Support for ChromeOS as well.
       'supported_on': ['chrome.*:70-'],
       'features': {
-        'dynamic_refresh': True,
+        # TODO(crbug.com/775415): Support dynamic refresh, then add support
+        # for ChromeOS as well.
+        'dynamic_refresh': False,
         'per_profile': True,
       },
       'example_value': True,
diff --git a/components/policy/resources/policy_templates_bn.xtb b/components/policy/resources/policy_templates_bn.xtb
index cd6ff47..5608c654b 100644
--- a/components/policy/resources/policy_templates_bn.xtb
+++ b/components/policy/resources/policy_templates_bn.xtb
@@ -603,6 +603,11 @@
       যদি এই নীতি মিথ্যাতে সেট করা হয় তাহলে <ph name="PRODUCT_OS_NAME" /> লগ-ইনের স্ক্রিনে আগে থেকে থাকা ব্যবহারকারীদের নাম দেখাবে না। কোনও পাবলিক সেশন কনফিগার না করা থাকলে সাধারণ সাইন-ইন স্ক্রিন (যেখানে ব্যবহারকারীকে ইমেল এবং পাসওয়ার্ড বা ফোন নম্বর দিতে বলা হয়) অথবা SAML ইন্টারস্টিশিয়্যাল স্ক্রিন (যদি<ph name="LOGIN_AUTHENTICATION_BEHAVIOR_POLICY_NAME" /> এর মাধ্যমে সক্ষম করা থাকে) দেখানো হবে। যদি কোনও পাবলিক সেশন কনফিগার করা থাকে তাহলে কোনও একটি বেছে নেওয়ার জন্য শুধুমাত্র পাবলিক সেশন অ্যাকাউন্টগুলি দেখানো হবে।
 
       মনে রাখবেন, ডিভাইসে স্থানীয় ব্যবহারকারীর ডেটা রাখা হয় বা পরিত্যাগ করা হয় তার উপর এই নীতি কোনও প্রভাব ফেলে না।</translation>
+<translation id="2433412232489478893">যেকোনও ব্যবহারকারীর জন্য <ph name="PRODUCT_NAME" />-এর নেটওয়ার্ক ফাইল শেয়ার করার বৈশিষ্ট্যটি অনুমোদিত কিনা তা এই নীতি নিয়ন্ত্রণ করে।
+
+      যখন এই নীতিটি কনফিগার করা হয় না অথবা ট্রুতে সেট করা থাকে তখন ব্যবহারকারী নেটওয়ার্ক ফাইল শেয়ার বৈশিষ্ট্যটি ব্যবহার করতে পারবেন।
+
+      যখন এই নীতিটি ফলসে সেট করা থাকে তখন ব্যবহারকারী নেটওয়ার্ক ফাইল শেয়ার বৈশিষ্ট্যটি ব্যবহার করতে পারবেন না।</translation>
 <translation id="2438609638493026652">Android অ্যাপ ইনস্টল করার সময় Google-এ মূল ইভেন্টগুলির রিপোর্টিং চালু করে। যেসব অ্যাপের ইনস্টলেশন নীতির মাধ্যমে ট্রিগার করা হয়েছে শুধুমাত্র সেই সব অ্যাপের ইভেন্ট ক্যাপচার করা হবে।
 
       নীতিগুলি 'ট্রু' হিসেবে সেট করা হলে, ইভেন্ট লগ করা হবে।
@@ -689,6 +694,7 @@
 <translation id="2598508021807251719">লোকেলগুলির কনফিগার <ph name="PRODUCT_OS_NAME" /> এ প্রদর্শিত হতে পারে।
 
       যদি এই নীতিটি সেট করা থাকে, ব্যবহারকারী শুধুমাত্র এই নীতি দ্বারা নির্দিষ্ট লোকেলগুলির মধ্যে একটি প্রদর্শিত করতে <ph name="PRODUCT_OS_NAME" /> কনফিগার করতে পারেন। যদি এই নীতিটি সেট না করা হয় বা খালি তালিকাতে সেট করা হয়, তবে <ph name="PRODUCT_OS_NAME" /> সব সমর্থিত লোকেলে প্রদর্শিত হতে পারে। যদি এই নীতিটি একটি ভুল মানগুলির তালিকাতে সেট করা থাকে, তবে সমস্ত ভুল মান উপেক্ষা করা হবে। একজন ব্যবহারকারীকে পূর্বে কনফিগার হলে <ph name="PRODUCT_OS_NAME" /> এই নীতি দ্বারা অনুমোদিত নয় এমনভাবে প্রদর্শিত হবে, পরের বার যখন ব্যবহারকারী সাইন-ইন করবেন তখন প্রদর্শিত লোকেলকে অনুমোদিত UI লোকেলে পাল্টানো হবে। ব্যবহারকারী যদি পছন্দসই লোকেলে কনফিগার করেন এবং এই পছন্দের লোকেলগুলির মধ্যে একটি এই নীতি দ্বারা অনুমোদিত হয়, <ph name="PRODUCT_OS_NAME" /> এই লোকেলে পাল্টে যাবে। অন্যথায়, যদি এই নীতিটিতে কেবল ভুল এন্ট্রি থাকে, তবে এই নীতি দ্বারা নির্দিষ্ট করা প্রথম সঠিক মান বা একটি ফলব্যাক লোকেল (সম্প্রতি en-US) -এ <ph name="PRODUCT_OS_NAME" /> পাল্টানো হবে।</translation>
+<translation id="2604182581880595781">নেটওয়ার্ক ফাইলের সাথে সম্পর্কিত নীতিগুলি কনফিগার করুন।</translation>
 <translation id="2623014935069176671">প্রাথমিক ব্যবহারকারী ক্রিয়াকলাপের জন্য অপেক্ষা করুন</translation>
 <translation id="262740370354162807"><ph name="CLOUD_PRINT_NAME" />-তে দস্তাবেজ জমা সক্ষম করুন</translation>
 <translation id="2627554163382448569">এন্টারপ্রাইজ প্রিন্টারগুলির জন্য কনফিগারেশন প্রদান করে।
@@ -781,6 +787,7 @@
 
           যদি এই নীতি সেট না করা থাকে তাহলে কোনও সর্বোচ্চ দৈর্ঘ্য এনফোর্স করা হয় না।</translation>
 <translation id="2838830882081735096">ডেটা মাইগ্রেশন এবং ARC এর অনুমতি দেবেন না</translation>
+<translation id="2839294585867804686">নেটওয়ার্ক ফাইল শেয়ার সেটিংস</translation>
 <translation id="2840269525054388612">এমন প্রিন্টারের বিষয়ে উল্লেখ করে যেটি ব্যবহারকারী ব্যবহার করতে পারবেন।
 
        শুধুমাত্র <ph name="DEVICE_PRINTERS_ACCESS_MODE" /> এর জন্য <ph name="PRINTERS_WHITELIST" /> বেছে নেওয়া হলেই এই নীতিটি ব্যবহার করা হয়।
@@ -1368,6 +1375,7 @@
       যদি এই নীতিটি সেট না করা থাকে, তাহলে ইউআরএল- কী পরিচয় গোপন করা ডেটা সংগ্রহ চালু থাকবে কিন্তু ব্যবহারকারী এটিকে পরিবর্তন করতে পারবে।</translation>
 <translation id="4250680216510889253">না</translation>
 <translation id="4261820385751181068">ডিভাইস সাইন-ইন স্ক্রিন লোকেল</translation>
+<translation id="4264607809747169568">ChromeOS উপলভ্যতার জন্য নেটওয়ার্ক ফাইল শেয়ার নিয়ন্ত্রণ করুন</translation>
 <translation id="427220754384423013">এমন প্রিন্টারের বিষয়ে উল্লেখ করে যেটি ব্যবহারকারী ব্যবহার করতে পারবেন।
 
       শুধুমাত্র <ph name="BULK_PRINTERS_ACCESS_MODE" /> এর জন্য <ph name="PRINTERS_WHITELIST" /> বেছে নেওয়া হলেই এই নীতিটি ব্যবহার করা হয়।
@@ -1910,6 +1918,15 @@
       নীতি মান মিলিসেকেন্ডে নির্দিষ্ট করা উচিত৷</translation>
 <translation id="5511702823008968136">বুকমার্ক দণ্ড সক্ষম করুন</translation>
 <translation id="5512418063782665071">হোম পেজের URL</translation>
+<translation id="551639594034811656">আপডেটটি প্রথম যখন খুঁজে পাওয়া যাবে, সেদিন থেকে শুরু করে প্রতি দিনে OU-এর যতগুলি <ph name="PRODUCT_OS_NAME" /> ডিভাইস আপডেট করতে হবে, তার শতকরা হারের একটি তালিকা এই নীতিতে নির্দিষ্ট করা থাকে। আপডেট দেখার সময়টি আপডেট প্রকাশিত হওয়ার সময়ের পরে আসে, কারণ প্রকাশ করার বেশ কিছুক্ষণ বা কিছু দিন পরে ডিভাইসটি আপডেট খুঁজতে পারে।
+
+      প্রতিটি (দিন, শতাংশ) জোড়ার মধ্যে আপডেট হওয়ার পর দিনের সংখ্যা অনুসারে আপডেট করা ডিভাইসের শতাংশ। উদাহরণস্বরূপ, যদি আমাদের [(৪, ৪০), (১০, ৭০), (১৫, ১০০)] জোড়া থাকে, তাহলে আপডেটের ৪দিন পরে ৪০% ডিভাইস আপডেট করা উচিত। গণনা অনুযায়ী, ১০ দিন পর ৭০% আপডেট করা আবশ্যক।
+
+      এই নীতির জন্য যদি কোনও মান উল্লেখ করা থাকে তাহলে আপডেটগুলি <ph name="DEVICE_UPDATE_SCATTER_FACTOR_POLICY_NAME" /> নীতির বদলে এটি অনুসরণ করবে।
+
+      এই তালিকাটি যদি খালি থাকে তাহলে স্টেজিং করা হবে না এবং আপডেটগুলি ডিভাইসের অন্যান্য নীতি অনুযায়ী প্রয়োগ করা হবে।
+
+      চ্যানেল পরিবর্তনের ক্ষেত্রে এই নীতিটি প্রযোজ্য নয়।</translation>
 <translation id="5523812257194833591">একটি বিলম্বের পর স্বয়ংক্রিয়ভাবে লগইন করার জন্য একটি সর্বজনীন সেশন৷
 
       যদি এই নীতিটি সেট থাকে, তাহলে নির্দিষ্ট সেশনটি ব্যবহারকারীর কোনো ভূমিকা ছাড়াই লগইন স্ক্রিনে একটি অতিবাহিত সময়ের পর স্বয়ংক্রিয়ভাবে লগইন হবে৷ সর্বজনীন সেশনটিকে অবশ্যই ইতিমধ্যেই কনফিগার করা হতে হবে (|DeviceLocalAccounts| দেখুন)৷
@@ -2931,6 +2948,11 @@
       যদি নীতিটি বন্ধ করা থাকে, তাহলে কোনও সুনির্দিষ্ট সাইট পৃথকীকরণ হবে না এবং IsolateOrigins ও SitePerProcess-এর ফিল্ড ট্রায়াল বন্ধ হয়ে যাবে। ব্যবহারকারীরা এখনও নিজে থেকে SitePerProcess চালু করতে পারবে।
       এই নীতিটি কনফিগার করা না হলে ব্যবহারকারী পরে এটির সেটিং পরিবর্তন করতে পারবেন।
       </translation>
+<translation id="7902255855035461275">এই তালিকার প্যাটার্নগুলি অনুরোধ করা URL এর নিরাপত্তার
+      উৎসের সাথে মিলে যাবে। যদি কোনও মিল খুঁজে পাওয়া যায়, তাহলে বিজ্ঞপ্তি ছাড়াই
+      ভিডিও ক্যাপচার ডিভাইসগুলির অ্যাক্সেস অনুমোদিত হবে।
+
+      দ্রষ্টব্য: ভার্সন ৪৫ পর্যন্ত এই নীতি শুধুমাত্র Kiosk মোডে সমর্থিত ছিল।</translation>
 <translation id="7912255076272890813">অনুমতিপ্রাপ্ত অ্যাপ্লিকেশন/এক্সটেনশন প্রকারগুলি কনফিগার করুন</translation>
 <translation id="7915236031252389808">আপনি এখানে কোনো প্রক্সীর .pac ফাইলের একটি URL নির্দিষ্ট করতে পারেন৷
 
diff --git a/components/policy/resources/policy_templates_cs.xtb b/components/policy/resources/policy_templates_cs.xtb
index b816ba69..2d6f269 100644
--- a/components/policy/resources/policy_templates_cs.xtb
+++ b/components/policy/resources/policy_templates_cs.xtb
@@ -284,9 +284,9 @@
       Pokud některá možnost nebude nakonfigurována, použije se výchozí hodnota.
 
       Pokud tato zásada není nastavena, budou pro všechna nastavení použity výchozí hodnoty.</translation>
-<translation id="1958138414749279167">Aktivuje v prohlížeči <ph name="PRODUCT_NAME" /> funkci Automatické vyplňování a umožňuje uživatelům automaticky ve webových formulářích vyplňovat informace o adresách pomocí dříve uložených údajů.
+<translation id="1958138414749279167">Aktivuje v prohlížeči <ph name="PRODUCT_NAME" /> funkci Automatické vyplňování a umožňuje uživatelům automaticky ve webových formulářích vyplňovat adresní údaje s použitím dříve uložených dat.
 
-      Pokud je toto nastavení vypnuto, automatické vyplňování nebude navrhovat ani vyplňovat informace o adresách a nebude ani ukládat další informace o adresách, které uživatel při prohlížení webu odešle.
+      Pokud je toto nastavení vypnuto, automatické vyplňování nebude navrhovat ani vyplňovat adresní údaje a nebude ani ukládat další informace o adresách, které uživatel při prohlížení webu odešle.
 
       Pokud je toto nastavení zapnuto nebo nemá žádnou hodnotu, uživatel bude moci automatické vyplňování adres ovládat v uživatelském rozhraní.</translation>
 <translation id="1960840544413786116">Udává, zda mají být povoleny certifikáty vydané místními kotvami vztahu důvěryhodnosti bez rozšíření subjectAlternativeName.</translation>
diff --git a/components/policy/resources/policy_templates_es-419.xtb b/components/policy/resources/policy_templates_es-419.xtb
index 7355ac7..856ebf8 100644
--- a/components/policy/resources/policy_templates_es-419.xtb
+++ b/components/policy/resources/policy_templates_es-419.xtb
@@ -503,6 +503,11 @@
       Si no se establece esta opción, el usuario podrá decidir si quiere o no utilizar esta función.
 
       Esta opción se eliminó de la versión 29 de <ph name="PRODUCT_NAME" /> y versiones posteriores.</translation>
+<translation id="2433412232489478893">Esta política controla si un usuario puede usar la función "Network File Shares" para <ph name="PRODUCT_NAME" />.
+
+      Cuando no se configura o se establece como verdadera, los usuarios podrán usar esta función.
+
+      Cuando se establece como falsa, los usuarios no podrán usar esta función.</translation>
 <translation id="2438609638493026652">Permite informar eventos clave durante la instalación de apps de Android en Google. Solo se capturan los eventos de las apps cuya instalación se activó a través de la política.
 
       Si la política se establece como verdadera, se registrarán los eventos.
@@ -580,6 +585,7 @@
 <translation id="2598508021807251719">Permite configurar los idiomas en que se puede mostrar <ph name="PRODUCT_OS_NAME" />.
 
       Si se establece esta política, el usuario solo puede configurar <ph name="PRODUCT_OS_NAME" /> para que se muestre en uno de los idiomas especificados por esta política. Si se establece con una lista vacía o no se establece, <ph name="PRODUCT_OS_NAME" /> se puede mostrar en todos los idiomas de IU compatibles. Si se establece con una lista de valores no válidos, se ignorarán todos estos. Si un usuario configuró anteriormente <ph name="PRODUCT_OS_NAME" /> para que se mostrara en un idioma de IU que no se permite según esta política, el idioma de visualización se cambiará a uno permitido la próxima vez que acceda el usuario. Si este configuró los idiomas preferidos y la política permite uno de ellos, <ph name="PRODUCT_OS_NAME" /> se cambiará a ese idioma. De lo contrario, <ph name="PRODUCT_OS_NAME" /> se cambiará al primer valor válido que especifica esta política o a un idioma alternativo (actualmente en-US) si esta política solo contiene entradas no válidas.</translation>
+<translation id="2604182581880595781">Configura las políticas relacionadas con la función "Network File Shares".</translation>
 <translation id="2623014935069176671">Esperar actividad inicial del usuario</translation>
 <translation id="262740370354162807">Habilitar el envío de documentos a <ph name="CLOUD_PRINT_NAME" /></translation>
 <translation id="2627554163382448569">Proporciona configuraciones para las impresoras empresariales.
@@ -659,6 +665,7 @@
 <translation id="2823870601012066791">Ubicación del registro de Windows para los clientes de <ph name="PRODUCT_OS_NAME" />:</translation>
 <translation id="2824715612115726353">Activar el modo de incógnito</translation>
 <translation id="2838830882081735096">No permitir la migración de datos y ARC</translation>
+<translation id="2839294585867804686">Configuración de "Network File Shares"</translation>
 <translation id="2840269525054388612">Especifica las impresoras que puede utilizar el usuario.
 
       Esta política solo se usa si se elige <ph name="PRINTERS_WHITELIST" /> para <ph name="DEVICE_PRINTERS_ACCESS_MODE" />
@@ -1140,6 +1147,7 @@
       Si no se establece, se habilitará la recopilación, y el usuario podrá cambiarla.</translation>
 <translation id="4250680216510889253">No</translation>
 <translation id="4261820385751181068">Configuración regional de la pantalla de acceso del dispositivo</translation>
+<translation id="4264607809747169568">Controlar la disponibilidad de "Network File Shares" para el Sistema operativo Chrome</translation>
 <translation id="427220754384423013">Especifica las impresoras que puede utilizar el usuario.
 
       Esta política solo se usa si se elige <ph name="PRINTERS_WHITELIST" /> para <ph name="BULK_PRINTERS_ACCESS_MODE" />.
@@ -1537,6 +1545,14 @@
       El valor de la política se debe especificar en milisegundos.</translation>
 <translation id="5511702823008968136">Habilitar barra de favoritos</translation>
 <translation id="5512418063782665071">URL de la página principal</translation>
+<translation id="551639594034811656">Esta política define una lista de porcentajes que determinará la fracción de dispositivos <ph name="PRODUCT_OS_NAME" /> en la UO que se actualizará por día a partir del momento en que se descubre la actualización (posterior a la publicación, conforme a lo que tarde el dispositivo en buscar actualizaciones).
+      Cada par (día, porcentaje) contiene el porcentaje de la flota que se debe actualizar en una cantidad dada de días a partir del descubrimiento de la actualización. Por ejemplo, si tenemos los pares [(4, 40), (10, 70), (15, 100)], el 40% de la flota debe haberse actualizado 4 días después de descubrir la actualización. El 70% debe actualizarse después de 10 días, y así sucesivamente.
+
+      Si hay un valor definido para esta política, las actualizaciones ignorarán la política <ph name="DEVICE_UPDATE_SCATTER_FACTOR_POLICY_NAME" /> y, en su lugar, seguirán esta.
+
+      Si esta lista está vacía, no se definirán etapas y se aplicarán las actualizaciones conforme a otras políticas de dispositivo.
+
+      No se aplica esta política para los cambios de canales.</translation>
 <translation id="5523812257194833591">Una sesión pública para acceso automático después de una demora
 
       Si se establece esta política, se accederá automáticamente a la sesión especificada después de que haya transcurrido un período en la pantalla de acceso sin la interacción del usuario. La sesión pública ya debe estar configurada (ver |DeviceLocalAccounts|).
@@ -2438,6 +2454,11 @@
       Si se inhabilita, no se aplicará el aislamiento de sitios, y se inhabilitarán las pruebas de campo de IsolateOrigins y SitePerProcess. Aun así, los usuarios podrán habilitar SitePerProcess de forma manual.
       Si no se establece, el usuario podrá cambiar esta configuración.
       </translation>
+<translation id="7902255855035461275">Los patrones de esta lista se compararán con el origen
+      de seguridad de la URL solicitante. Si se encuentra una coincidencia,
+      se concede acceso a los dispositivos de captura de video sin solicitarlo.
+
+      NOTA: Hasta la versión 45, esta política solo se admitía en modo kiosco.</translation>
 <translation id="7912255076272890813">Configurar tipos de extensiones o aplicaciones permitidos</translation>
 <translation id="7915236031252389808">Puedes especificar una URL para un archivo .pac de proxy aquí.
 
diff --git a/components/policy/resources/policy_templates_es.xtb b/components/policy/resources/policy_templates_es.xtb
index 4d3fae67..9aa73c9 100644
--- a/components/policy/resources/policy_templates_es.xtb
+++ b/components/policy/resources/policy_templates_es.xtb
@@ -297,11 +297,11 @@
       Si no se configura una opción, se utilizará el valor predeterminado.
 
       Si no se define esta política, se utilizarán todos los valores predeterminados.</translation>
-<translation id="1958138414749279167">Habilita la función Autocompletar de <ph name="PRODUCT_NAME" /> y permite que los usuarios rellenen automáticamente formularios web con información almacenada anteriormente, como la información de la dirección.
+<translation id="1958138414749279167">Habilita la función Autocompletar de <ph name="PRODUCT_NAME" /> y permite que los usuarios rellenen formularios web automáticamente con direcciones almacenadas anteriormente.
 
-      Si inhabilitas esta opción, la función Autocompletar no hará sugerencias ni rellenará la información de la dirección, y tampoco guardará información adicional de la dirección que el usuario envíe cuando esté navegando por la Web.
+      Si inhabilitas esta opción, la función Autocompletar no hará sugerencias ni rellenará los datos de la dirección, y tampoco guardará información adicional de la dirección que el usuario envíe cuando esté navegando por la Web.
 
-      Si habilitas esta opción o no estableces ningún valor, el usuario podrá controlar la función Autocompletar para información de la dirección en la IU.</translation>
+      Si habilitas esta opción o no estableces ningún valor, el usuario podrá controlar la función Autocompletar para datos de la dirección en la UI.</translation>
 <translation id="1960840544413786116">Si se permiten los certificados emitidos por los anclajes de confianza locales que no tienen la extensión subjectAlternativeName</translation>
 <translation id="1964634611280150550">Modo de incógnito inhabilitado</translation>
 <translation id="1964802606569741174">Esta política no influye en la aplicación YouTube para Android. Si se debe aplicar el modo seguro en YouTube, deberás inhabilitar la descarga de la aplicación YouTube para Android.</translation>
diff --git a/components/policy/resources/policy_templates_hi.xtb b/components/policy/resources/policy_templates_hi.xtb
index aaa13789..e9dbaee 100644
--- a/components/policy/resources/policy_templates_hi.xtb
+++ b/components/policy/resources/policy_templates_hi.xtb
@@ -304,7 +304,7 @@
       अगर यह नीति सेट नहीं होती है तो, सभी सेटिंग के लिए डिफ़ॉल्ट का उपयोग किया जाता है.</translation>
 <translation id="1958138414749279167">यह नीति <ph name="PRODUCT_NAME" /> की 'अपने आप भरने की सुविधा (ऑटो फ़िल)' चालू करती है. इसके ज़रिए उपयोगकर्ताओं को पहले से संग्रहित जानकारी की मदद से वेब फ़ॉर्म में पते की जानकारी अपने आप भरने की सुविधा मिलती है.
 
-      अगर यह सेटिंग बंद होती है, तो 'अपने आप भरने की सुविधा (ऑटो फ़िल)' न तो कभी कोई सुझाव देगी न ही पते की जानकारी भरेगी. साथ ही यह पते की ऐसी और ज़्यादा जानकारी सेव नहीं करेगी जिसे उपयोगकर्ता ने शायद वेब ब्राउज़ करते समय सबमिट किया होगा.
+      अगर यह सेटिंग बंद होती है, तो 'अपने आप भरने की सुविधा (ऑटो फ़िल)' न तो कभी कोई सुझाव देगी, न ही पते की जानकारी भरेगी. साथ ही यह पते की ऐसी और ज़्यादा जानकारी सेव नहीं करेगी जिसे उपयोगकर्ता ने शायद वेब ब्राउज़ करते समय सबमिट किया होगा.
 
       अगर यह सेटिंग चालू होती है या इसका कोई मान न दिया गया हो, तो उपयोगकर्ता यूज़र इंटरफ़ेस (यूआई) में पते की जानकारी के लिए 'अपने आप भरने की सुविधा (ऑटो फ़िल)' को नियंत्रित कर पाएगा.</translation>
 <translation id="1960840544413786116">स्थानीय विश्वसनीय एंकरों की ओर से जारी किए जाने वाले ऐसे प्रमाणपत्रों को अनुमति दें या नहीं जिनमें subjectAlternativeName एक्सटेंशन मौजूद नहीं है</translation>
diff --git a/components/policy/resources/policy_templates_ml.xtb b/components/policy/resources/policy_templates_ml.xtb
index 7be29ee..f825581 100644
--- a/components/policy/resources/policy_templates_ml.xtb
+++ b/components/policy/resources/policy_templates_ml.xtb
@@ -346,7 +346,7 @@
 
       ഈ ക്രമീകരണം പ്രവർത്തനരഹിതമാക്കിയാൽ, സ്വമേധയാ പൂരിപ്പിക്കൽ ഒരിക്കലും വിലാസ വിവരം നിർദേശിക്കുകയോ പൂരിപ്പിക്കുകയോ ഇല്ല, വെബ് ബ്രൗസ് ചെയ്യുമ്പോൾ ഉപയോക്താവ് സമർപ്പിച്ചേക്കാവുന്ന അധിക വിലാസ വിവരം സംരക്ഷിക്കുകയുമില്ല.
 
-      ഈ ക്രമീകരണം പ്രവർത്തനക്ഷമമാക്കിയാലോ അതിന് മൂല്യം ഇല്ലെങ്കിലോ, UI-യിൽ വിലാസത്തിനായി സ്വമേധയാ പൂരിപ്പിക്കൽ നിയന്ത്രിക്കാൻ ഉപയോക്താവിന് കഴിയും.</translation>
+      ഈ ക്രമീകരണം പ്രവർത്തനക്ഷമമാക്കിയാലോ അതിന് മൂല്യം ഇല്ലെങ്കിലോ, UI-യിൽ വിലാസത്തിനായുള്ള സ്വമേധയാ പൂരിപ്പിക്കൽ നിയന്ത്രിക്കാൻ ഉപയോക്താവിന് കഴിയും.</translation>
 <translation id="1960840544413786116">subjectAlternativeName വിപുലീകരണം ലഭ്യമല്ലാത്ത ലോക്കൽ ട്രസ്‌റ്റ് ആങ്കറുകൾ നൽകുന്ന സർട്ടിഫിക്കറ്റുകൾ അനുവദിക്കണോ</translation>
 <translation id="1964634611280150550">ആൾമാറാട്ട മോഡ് പ്രവർത്തനരഹിതമാക്കി</translation>
 <translation id="1964802606569741174">ഈ നയം Android YouTube ആപ്പിന് ബാധകമല്ല. YouTube-ലെ സുരക്ഷാ മോഡ് നടപ്പിലാക്കണമെങ്കിൽ, Android YouTube ആപ്പിന്റെ ഇൻസ്‌റ്റലേഷൻ അനുവദിക്കരുത്.</translation>
@@ -2184,7 +2184,7 @@
 <translation id="6440051664870270040">ഒരേ സമയത്ത് നാവിഗേറ്റ് ചെയ്യാനും പോപ്പ്-അപ്പുകൾ തുറക്കാനും സൈറ്റുകളെ അനുവദിക്കുക</translation>
 <translation id="6447948611083700881">ബാക്കപ്പും പുനഃസ്ഥാപിക്കലും പ്രവർത്തനരഹിതമാക്കി</translation>
 <translation id="645425387487868471"><ph name="PRODUCT_NAME" /> ഉൽപ്പന്നത്തിന് നിർബന്ധിത സൈൻ ഇൻ പ്രവർത്തനക്ഷമമാക്കുക</translation>
-<translation id="6464074037294098618">വിലാസങ്ങൾക്കായി സ്വമേധയാ പൂരിപ്പിക്കൽ പ്രവർത്തനക്ഷമമാക്കുക</translation>
+<translation id="6464074037294098618">വിലാസങ്ങൾക്കായുള്ള സ്വമേധയാ പൂരിപ്പിക്കൽ പ്രവർത്തനക്ഷമമാക്കുക</translation>
 <translation id="6467613372414922590">ഉപയോക്തൃനില പ്രാദേശിക സന്ദേശമയയ്‌ക്കൽ ഹോസ്‌‌റ്റുകളെ അനുവദിക്കുക (അഡ്‌മിൻ അനുമതികളില്ലാതെ ഇൻസ്‌റ്റാൾചെയ്‌തത്)</translation>
 <translation id="6468980648680553776">ഈ നയം അവസാനിപ്പിച്ചിരിക്കുന്നു. പകരം RemoteAccessHostClientDomainList ഉപയോഗിക്കുക.</translation>
 <translation id="6473623140202114570">സുരക്ഷിത ബ്രൗസിംഗ് മുന്നറിയിപ്പ് ട്രിഗർ ചെയ്യാത്ത ഡൊമെയ്‌നുകളുടെ ലിസ്റ്റ് കോൺഫിഗർ ചെയ്യുക.</translation>
diff --git a/components/policy/resources/policy_templates_no.xtb b/components/policy/resources/policy_templates_no.xtb
index 052817ce..974755b 100644
--- a/components/policy/resources/policy_templates_no.xtb
+++ b/components/policy/resources/policy_templates_no.xtb
@@ -301,7 +301,7 @@
       Hvis en innstilling ikke angis, brukes en standardverdi.
 
       Hvis denne planen ikke angis, brukes standardverdiene for alle innstillingene.</translation>
-<translation id="1958138414749279167">Slår på autofyllfunksjonen i <ph name="PRODUCT_NAME" />og gjør det mulig for brukere å fylle ut adresseinformasjon i nettskjemaer automatisk ved hjelp av tidligere lagret informasjon.
+<translation id="1958138414749279167">Slår på autofyllfunksjonen i <ph name="PRODUCT_NAME" /> og gjør det mulig for brukere å fylle ut adresseinformasjon i nettskjemaer automatisk ved hjelp av tidligere lagret informasjon.
 
       Hvis denne innstillingen er av, gir ikke autofyllfunksjonen forslag, og den fyller ikke inn informasjon automatisk. Den lagrer heller ikke lenger informasjon som brukeren sender inn på nettet.
 
diff --git a/components/policy/resources/policy_templates_sl.xtb b/components/policy/resources/policy_templates_sl.xtb
index be5cffe..cb5b3ccd 100644
--- a/components/policy/resources/policy_templates_sl.xtb
+++ b/components/policy/resources/policy_templates_sl.xtb
@@ -304,7 +304,7 @@
       Če ta pravilnik ni nastavljen, se za vse nastavitve uporabijo privzete vrednosti.</translation>
 <translation id="1958138414749279167">Omogoči funkcijo za samodejno izpolnjevanje v brskalniku <ph name="PRODUCT_NAME" /> in uporabnikom omogoča samodejno izpolnjevanje podatkov o naslovu v spletnih obrazcih s predhodno shranjenimi podatki.
 
-      Če je ta nastavitev onemogočena, samodejno izpolnjevanje ne bo nikoli predlagalo ali vneslo podatkov o naslovu in prav tako ne bo shranilo dodatnih podatkov o naslovu, ki jih uporabnik lahko pošlje med brskanjem v spletu.
+      Če je ta nastavitev onemogočena, samodejno izpolnjevanje ne bo nikoli predlagalo ali vneslo podatkov o naslovu in prav tako ne bo shranilo dodatnih podatkov o naslovu, ki jih uporabnik morda vnese med brskanjem v spletu.
 
       Če je ta nastavitev omogočena ali nima nastavljene vrednosti, bo uporabnik lahko nadziral samodejno izpolnjevanje za naslove v uporabniškem vmesniku.</translation>
 <translation id="1960840544413786116">Ali naj se dovoli potrdila, ki jih izdajo lokalna sidra zaupanja in jim manjka razširitev subjectAlternativeName</translation>
diff --git a/components/policy/resources/policy_templates_sr.xtb b/components/policy/resources/policy_templates_sr.xtb
index 0c28b172..740008e 100644
--- a/components/policy/resources/policy_templates_sr.xtb
+++ b/components/policy/resources/policy_templates_sr.xtb
@@ -301,7 +301,7 @@
       Ако не наведете подешавање, користи се подразумевана вредност.
 
       Ако не подесите ове смернице, користе се подразумеване вредности за сва подешавања.</translation>
-<translation id="1958138414749279167">Омогућавају функцију Аутоматско попуњавање у <ph name="PRODUCT_NAME" />-у и омогућавају корисницима да аутоматски довршавају податке о адреси у веб-обрасцима помоћу раније сачуваних података.
+<translation id="1958138414749279167">Омогућава функцију Аутоматско попуњавање услуге <ph name="PRODUCT_NAME" /> и омогућава корисницима да аутоматски довршавају податке о адреси у веб-обрасцима помоћу раније сачуваних података.
 
       Ако је ово подешавање онемогућено, Аутоматско попуњавање никада неће предлагати или попуњавати податке о адреси нити ће чувати додатне податке о адреси које корисник може да пошаље док прегледа веб.
 
@@ -1935,7 +1935,7 @@
 <translation id="6440051664870270040">Дозвољавају сајтовима да се истовремено померају и отварају искачуће прозоре</translation>
 <translation id="6447948611083700881">Прављење резервних копија и враћање је онемогућено</translation>
 <translation id="645425387487868471">Омогућавају принудно пријављивање у <ph name="PRODUCT_NAME" /></translation>
-<translation id="6464074037294098618">Омогућавају Аутоматско попуњавање за адресе</translation>
+<translation id="6464074037294098618">Омогућава Аутоматско попуњавање за адресе</translation>
 <translation id="6473623140202114570">Конфигуришите листу домена на којима Безбедно прегледање неће активирати упозорења.</translation>
 <translation id="6491139795995924304">Омогућите Bluetooth на уређају</translation>
 <translation id="6520802717075138474">Увези претраживач из подразумеваног прегледача при првом покретању</translation>
diff --git a/components/policy/resources/policy_templates_te.xtb b/components/policy/resources/policy_templates_te.xtb
index 4b488655..6eef4b54 100644
--- a/components/policy/resources/policy_templates_te.xtb
+++ b/components/policy/resources/policy_templates_te.xtb
@@ -431,7 +431,7 @@
 
       ఈ విధానం ప్రాక్సీ కాన్ఫిగర్ అయినప్పుడు మాత్రమే ప్రభావం చూపుతుంది (ఉదాహరణకు విధానం ద్వారా, వినియోగదారు ద్వారా chrome://settingsలో లేదా ఎక్స్‌టెన్షన్‌ల ద్వారా).
 
-      మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, ప్రస్తుత వినియోగదారు కోసం అన్ని విధానం సెట్టింగ్‌లను మరియు నియంత్రణలను విస్మరించి వేరే విండోలో ఏవైనా క్యాప్టివ్ పోర్టల్ ప్రమాణీకరణ పేజీలను ప్రదర్శిస్తాయి (అంటే <ph name="PRODUCT_NAME" /> విజయవంతమైన ఇంటర్నెట్ కనెక్షన్‌ని గుర్తించే వరకు క్యాప్టివ్ పోర్టల్ సైన్ ఇన్ పేజీతో ప్రారంభమయ్యే అన్ని వెబ్ పేజీలు).
+      మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, ప్రస్తుత వినియోగదారు కోసం అన్ని విధానం సెట్టింగ్‌లను మరియు నియంత్రణలను విస్మరించి వేరే విండోలో ఏవైనా క్యాప్టివ్ పోర్టల్ ప్రమాణీకరణ పేజీలు ప్రదర్శించబడతాయి (అంటే <ph name="PRODUCT_NAME" /> విజయవంతమైన ఇంటర్నెట్ కనెక్షన్‌ని గుర్తించే వరకు క్యాప్టివ్ పోర్టల్ సైన్ ఇన్ పేజీతో ప్రారంభమయ్యే అన్ని వెబ్ పేజీలు).
 
       మీరు ఈ సెట్టింగ్‌ను నిలిపివేస్తే లేదా సెట్ చేయకుండా వదిలివేస్తే, ఏవైనా క్యాప్టివ్ పోర్టల్ ప్రమాణీకరణ పేజీలు ప్రస్తుత వినియోగదారు ప్రాక్సీ సెట్టింగ్‌లను ఉపయోగించి (సాధారణ) కొత్త బ్రౌజర్ ట్యాబ్‌లో చూపబడతాయి.</translation>
 <translation id="21394354835637379">పొడిగింపులను, అనువర్తనాలను మరియు థీమ్‌లను ఇన్‌స్టాల్ చేయడానికి అనుమతించవలసిన URLలను పేర్కొనడానికి మిమ్మల్ని అనుమతిస్తుంది.
@@ -600,6 +600,11 @@
 ఈ విధానం తప్పుకు సెట్ చేయబడి ఉంటే, <ph name="PRODUCT_OS_NAME" /> లాగిన్ స్క్రీన్‌లో ఇప్పటికే ఉన్న వినియోగదారులను చూపదు. పబ్లిక్ సెషన్ కాన్ఫిగర్ చేయబడితే మినహా, సాధారణ సైన్ ఇన్ స్క్రీన్ (వినియోగదారు ఇమెయిల్ మరియు పాస్‌వర్డ్ లేదా ఫోన్ అడుగుతూ) లేదా SAML కణముల మధ్యనున్న స్క్రీన్ (<ph name="LOGIN_AUTHENTICATION_BEHAVIOR_POLICY_NAME" /> విధానం ద్వారా ప్రారంభిస్తే) చూపించబడతాయి. పబ్లిక్ సెషన్ కాన్ఫిగర్ చేయబడినప్పుడు, ఒకదాన్ని ఎంచుకోవడానికి అనుమతిస్తూ పబ్లిక్ సెషన్ ఖాతాలు మాత్రమే చూపించబడతాయి.
 
 ఈ విధానం స్థానిక వినియోగదారు డేటాను పరికరం ఉంచుతుందా లేదా తీసివేస్తుందా అన్నదాన్ని ప్రభావితం చేయదు.</translation>
+<translation id="2433412232489478893">వినియోగదారునికి <ph name="PRODUCT_NAME" /> కోసం నెట్‌వర్క్ ఫైల్ షేరింగ్‌లు ఫీచర్‌కు అనుమతి ఉంటుందా లేదా అనేదాన్ని ఈ విధానం నియంత్రిస్తుంది.
+
+ఈ విధానం కాన్ఫిగర్ చేయబడనప్పుడు లేదా ఒప్పుకి సెట్ చేయబడినప్పుడు, వినియోగదారులు నెట్‌వర్క్ ఫైల్ షేరింగ్‌లను ఉపయోగించుకోగలగుతారు.
+
+ఈ విధానం తప్పుకి సెట్ చేయబడినప్పుడు, వినియోగదారులు నెట్‌వర్క్ ఫైల్ షేరింగ్‌లను ఉపయోగించుకోలేరు.</translation>
 <translation id="2438609638493026652">Android యాప్ ఇన్‌స్టాలేషన్ సమయంలో కీలక ఈవెంట్‌లను Googleకి నివేదించడం ప్రారంభిస్తుంది. విధానం ప్రకారం ఇన్‌స్టాలేషన్ యాక్టివేట్ చేయబడిన యాప్‌ల కోసం మాత్రమే ఈవెంట్‌లు నివేదించబడతాయి.
 
       విధానాన్ని ఒప్పుకు సెట్ చేస్తే, ఈవెంట్‌లు లాగ్ చేయబడతాయి.
@@ -679,6 +684,7 @@
 <translation id="2598508021807251719"><ph name="PRODUCT_OS_NAME" />ని ప్రదర్శించే లొకేల్‌లను కాన్ఫిగర్ చేస్తుంది.
 
       ఈ విధానం సెట్ చేయబడినట్లయితే, వినియోగదారు ఈ విధానం ద్వారా పేర్కొన్న లొకేల్‌లలో ఒకదానిలో ప్రదర్శించడానికి మాత్రమే <ph name="PRODUCT_OS_NAME" />ని కాన్ఫిగర్ చేయగలరు. ఈ విధానాన్ని సెట్ చేయకపోతే లేదా ఖాళీ జాబితాకి సెట్ చేయబడినట్లయితే, <ph name="PRODUCT_OS_NAME" /> మద్దతు ఉన్న అన్ని UI లొకేల్‌లలో ప్రదర్శించబడుతుంది. ఈ విధానం చెల్లని విలువలు ఉన్న జాబితాకి సెట్ చేయబడినట్లయితే, చెల్లని అన్ని విలువలు విస్మరించబడతాయి. వినియోగదారు మునుపు ఈ విధానం అనుమతించని లొకేల్‌లో ప్రదర్శించడానికి <ph name="PRODUCT_OS_NAME" />ని కాన్ఫిగర్ చేసి ఉంటే, తర్వాతి సారి వినియోగదారు సైన్ ఇన్ చేసినప్పుడు ప్రదర్శన లొకేల్ అనుమతించిన UI లొకేల్‌కి మార్చబడుతుంది. వినియోగదారు ప్రాధాన్య లొకేల్‌లను కాన్ఫిగర్ చేసి ఉంటే మరియు ఈ విధానం ద్వారా ప్రాధాన్య లొకేల్‌లో ఒకటి అనుమతించబడి ఉంటే, <ph name="PRODUCT_OS_NAME" /> ఈ లొకేల్‌కు మార్చబడుతుంది. లేదంటే, <ph name="PRODUCT_OS_NAME" /> ఈ విధానం ద్వారా పేర్కొన్న చెల్లుబాటు అయ్యే మొదటి విలువకు మార్చబడుతుంది లేదా ఈ విధానం చెల్లుబాటు కాని నమోదులను మాత్రమే కలిగి ఉంటే, ఫాల్‌బ్యాక్ లొకేల్‌కి (ప్రస్తుతం en-US) మార్చబడుతుంది.</translation>
+<translation id="2604182581880595781">నెట్‌వర్క్ ఫైల్ షేరింగ్‌ సంబంధిత విధానాలను కాన్ఫిగర్ చేయండి.</translation>
 <translation id="2623014935069176671">ప్రారంభ వినియోగదారు కార్యాచరణ కోసం వేచి ఉండండి</translation>
 <translation id="262740370354162807">పత్రాలను <ph name="CLOUD_PRINT_NAME" />కు సమర్పించడాన్ని ప్రారంభిస్తుంది</translation>
 <translation id="2627554163382448569">ఎంటర్‌ప్రైజ్ ప్రింటర్‌ల కోసం కాన్ఫిగరేషన్‌లను అందిస్తుంది.
@@ -707,13 +713,13 @@
           'DefaultSearchProviderEnabled' విధానాన్ని ప్రారంభించినప్పుడు, ఈ ఎంపికను తప్పనిసరిగా సెట్ చేయాలి, ఇది ఈ సందర్భంలో మాత్రమే పరిగణించబడుతుంది.</translation>
 <translation id="2660846099862559570">ఇప్పటి వరకు ప్రాక్సీని ఉపయోగించలేదా</translation>
 <translation id="267596348720209223">శోధన ప్రొవైడర్ ద్వారా మద్దతు గల అక్షర ఎన్‌కోడింగ్‌లను పేర్కొంటుంది. ఎన్‌కోడింగ్‌లు అంటే UTF-8 GB2312 మరియు ISO-8859-1 వంటి కోడ్ పేజీ పేర్లు. అవి అందించబడిన క్రమంలో ప్రయత్నించబడతాయి. ఈ విధానం ఐచ్ఛికం. సెట్ చేయకపోతే, UTF-8 డిఫాల్ట్ ఉపయోగించబడుతుంది. ఈ విధానం కేవలం 'DefaultSearchProviderEnabled' విధానం ప్రారంభించబడితే పరిగణించబడుతుంది.</translation>
-<translation id="2682697254900811431"><ph name="PRODUCT_NAME" /> గురించి వినియోగం యొక్క అజ్ఞాత నివేదికను మరియు క్రాష్-సంబంధిత డేటాను Googleకి పంపడాన్ని ప్రారంభిస్తుంది మరియు ఈ సెట్టింగ్‌ను మార్చకుండా వినియోగదారులను నిరోధిస్తుంది.
+<translation id="2682697254900811431"><ph name="PRODUCT_NAME" /> గురించి వినియోగం మరియు క్రాష్-సంబంధిత డేటాను అజ్ఞాతంగా Googleకి నివేదించడాన్ని ప్రారంభిస్తుంది మరియు ఈ సెట్టింగ్‌ను మార్చకుండా వినియోగదారులను నిరోధిస్తుంది.
 
-      ఈ సెట్టింగ్ ప్రారంభించబడితే, వినియోగం యొక్క అజ్ఞాత నివేదికను మరియు క్రాష్-సంబంధిత
-      డేటా Googleకి పంపబడుతుంది.  ఇది నిలిపివేయబడితే, ఈ సమాచారం Googleకి
-      పంపబడదు.  రెండు సందర్భాలలో, వినియోగదారులు సెట్టింగ్‌లను మార్చలేరు లేదా భర్తీ చేయలేరు.
-      ఈ విధానం సెట్ చేయబడకపోతే, సెట్టింగ్ వినియోగదారు ఇన్‌స్టాలేషన్ / మొదటిసారి అమలు చేస్తున్నప్పుడు
-      ఏది ఎంచుకుంటారో అదే ఉంటుంది.
+      ఈ సెట్టింగ్ ప్రారంభించబడితే, వినియోగం మరియు క్రాష్-సంబంధిత
+      డేటా Googleకి అజ్ఞాతంగా నివేదించబడుతుంది. ఇది నిలిపివేయబడితే, ఈ సమాచారం Googleకి
+      పంపబడదు. ఈ రెండు సందర్భాలలో, వినియోగదారులు సెట్టింగ్‌లను మార్చలేరు లేదా భర్తీ చేయలేరు.
+      ఈ విధానం సెట్ చేయబడకపోతే, వినియోగదారు ఇన్‌స్టాలేషన్ / మొదటిసారి అమలు చేస్తున్నప్పుడు
+      ఏ సెట్టింగ్ ఎంచుకుంటారో అదే ఉంటుంది.
 
       ఈ విధానం <ph name="MS_AD_NAME" /> డొమైన్‌లో చేరని Windows సందర్భాలకు
       అందుబాటులో ఉండదు.  (Chrome OS కోసం,
@@ -774,6 +780,7 @@
           
 విధానం సెట్ చేయకపోతే, గరిష్ట అంకెల పరిమితి అమలు చేయబడదు.</translation>
 <translation id="2838830882081735096">డేటా బదిలీ మరియు ARCని అనుమతించకండి</translation>
+<translation id="2839294585867804686">నెట్‌వర్క్ ఫైల్ షేరింగ్‌ సెట్టింగ్‌లు</translation>
 <translation id="2840269525054388612">వినియోగదారు ఉపయోగించగల ప్రింటర్‌లను పేర్కొంటుంది.
 
       <ph name="DEVICE_PRINTERS_ACCESS_MODE" /> కోసం <ph name="PRINTERS_WHITELIST" />ని ఎంచుకున్నప్పుడు మాత్రమే ఈ విధానం ఉపయోగించబడుతుంది
@@ -1208,7 +1215,7 @@
 <translation id="3950239119790560549">సమయ పరిమితులను అప్‌డేట్ చేయండి</translation>
 <translation id="3957134519352019843">డిఫాల్ట్ శోధన ప్రదాత వినియోగాన్ని ప్రారంభిస్తుంది.
 
-          మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, URL కాని ఓమ్నిబాక్స్‌లో వినియోగదారు వచనాన్ని టైప్ చేస్తున్నప్పుడు ఒక డిఫాల్ట్ శోధన అమలవుతుంది.
+          మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, ఓమ్నిబాక్స్‌లో URL కాని వచనాన్ని వినియోగదారు టైప్ చేస్తున్నప్పుడు ఒక డిఫాల్ట్ శోధన అమలవుతుంది.
 
           మిగిలిన డిఫాల్ట్ శోధన విధానాలను సెట్ చేయడం ద్వారా మీరు ఉపయోగించాల్సిన డిఫాల్ట్ శోధన ప్రదాతను పేర్కొనవచ్చు. వీటిని ఖాళీగా వదిలివేస్తే, వినియోగదారు డిఫాల్ట్ ప్రదాతను ఎంచుకోగలరు.
 
@@ -1344,15 +1351,16 @@
 <translation id="4239720644496144453">Android అనువర్తనాల కోసం కాష్ ఉపయోగించబడదు. అనేకమంది వినియోగదారులు ఒకే Android అనువర్తనాన్ని ఇన్‌స్టాల్ చేస్తే, ప్రతి వినియోగదారు కోసం అది కొత్తగా డౌన్‌లోడ్ చేయబడుతుంది.</translation>
 <translation id="4243336580717651045"><ph name="PRODUCT_NAME" />లో URL కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణను ప్రారంభించి, ఈ సెట్టింగ్‌ను మార్చనీయకుండా వినియోగదారులను నిరోధిస్తుంది.
 
-      URL-కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణ శోధనలు మరియు బ్రౌజింగ్‌ను మెరుగ్గా చేయడానికి వినియోగదారు సందర్శించే పేజీల URLలను Googleకు పంపుతుంది.
+      URL-కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణ అనేది, శోధనలు మరియు బ్రౌజింగ్‌ను మెరుగ్గా చేయడానికి వినియోగదారు సందర్శించే పేజీల URLలను Googleకు పంపుతుంది.
 
       మీరు ఈ విధానాన్ని ప్రారంభిస్తే, URL-కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణ ఎల్లప్పుడూ యాక్టివ్‌గా ఉంటుంది.
 
-      మీరు ఈ విధానాన్ని నిలిపివేస్తే, URL-కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణ ఎప్పుడూ యాక్టివ్ కాదు.
+      మీరు ఈ విధానాన్ని నిలిపివేస్తే, URL-కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణ ఎప్పుడూ యాక్టివ్‌గా ఉండదు.
 
       ఈ విధానాన్ని సెట్ చేయకపోతే, URL-కీ ఉన్న అజ్ఞాతీకరించిన డేటా సేకరణ ప్రారంభించబడుతుంది, కానీ వినియోగదారు దీన్ని మార్చగలుగుతారు.</translation>
 <translation id="4250680216510889253">కాదు</translation>
 <translation id="4261820385751181068">పరికర సైన్-ఇన్ స్క్రీన్ లొకేల్</translation>
+<translation id="4264607809747169568">ChromeOS లభ్యత కోసం నెట్‌వర్క్ ఫైల్ షేరింగ్‌లను నియంత్రిస్తుంది</translation>
 <translation id="427220754384423013">వినియోగదారు ఉపయోగించగల ప్రింటర్‌లను పేర్కొంటుంది.
 
       <ph name="BULK_PRINTERS_ACCESS_MODE" /> కోసం <ph name="PRINTERS_WHITELIST" />ని ఎంచుకున్నప్పుడు మాత్రమే ఈ విధానం ఉపయోగించబడుతుంది.
@@ -1583,17 +1591,17 @@
       ఈ విధానం సెట్ చేయకుండా వదిలివేయబడితే లేదా ఖాళీగా ఉంటే, ఏ వినియోగదారు అయినా <ph name="PRODUCT_NAME" />కు సైన్ ఇన్ చేయగలరు.</translation>
 <translation id="4852080537521553509">ప్రారంభ ప్రవర్తనను పేర్కొనడానికి మిమ్మల్ని అనుమతిస్తుంది.
 
-          మీరు 'కొత్త ట్యాబ్ పేజీని తెరవండి' ఎంచుకుంటే కొత్త ట్యాబ్ పేజీ మీరు <ph name="PRODUCT_NAME" />ని ప్రారంభించినప్పుడు ఎల్లప్పుడూ తెరవబడుతుంది.
+          మీరు 'కొత్త ట్యాబ్ పేజీని తెరవండి' ఎంచుకుంటే, మీరు <ph name="PRODUCT_NAME" />ని ప్రారంభించినప్పుడు ఎల్లప్పుడూ కొత్త ట్యాబ్ పేజీ తెరవబడుతుంది.
 
-          మీరు 'చివరి సెషన్‌ని పునరుద్ధరించు' ఎంచుకుంటే, చివరిసారి <ph name="PRODUCT_NAME" />ని మూసివేసినప్పుడు తెరిచి ఉన్న URLలు మళ్లీ తెరవబడతాయి మరియు బ్రౌజింగ్ సెషన్ నుండి నిష్క్రమించబడినందున అది పునరుద్ధరించబడుతుంది.
+          మీరు 'చివరి సెషన్‌ని పునరుద్ధరించు' ఎంచుకుంటే, చివరిసారి <ph name="PRODUCT_NAME" />ని మూసివేసినప్పుడు తెరిచి ఉన్న URLలు మళ్లీ తెరవబడతాయి మరియు బ్రౌజింగ్ సెషన్ ఎలా నిష్క్రమించబడిందో, అలాగే పునరుద్ధరించబడుతుంది.
           
-ఈ ఎంపికను ఎంచుకోవడం వలన సెషన్‌లపై ఆధారపడే లేదా నిష్క్రమించినప్పుడు చర్యలు (నిష్క్రమించినప్పుడు బ్రౌజింగ్ డేటాను లేదా సెషన్-మాత్రమే కుక్కీలను తీసివేయడం) అమలు చేసే కొన్ని సెట్టింగ్‌లను నిలిపివేస్తాయి.
+ఈ ఎంపికను ఎంచుకోవడం వలన సెషన్‌లపై ఆధారపడే లేదా నిష్క్రమించినప్పుడు చర్యలు (నిష్క్రమించినప్పుడు బ్రౌజింగ్ డేటాను లేదా సెషన్-మాత్రమే కుక్కీలను తీసివేయడం) అమలు చేసే కొన్ని సెట్టింగ్‌లు నిలిపివేయబడతాయి.
 
-          'URLల జాబితాను తెరవండి' ఎంచుకుంటే, 'ప్రారంభంలో తెరవాల్సిన URLల' జాబితా వినియోగదారు <ph name="PRODUCT_NAME" />ని ప్రారంభించినప్పుడు తెరవబడుతుంది.
+          'URLల జాబితాను తెరవండి' ఎంచుకుంటే, వినియోగదారు <ph name="PRODUCT_NAME" />ని ప్రారంభించినప్పుడు 'ప్రారంభంలో తెరవాల్సిన URLల' జాబితా తెరవబడుతుంది.
 
           మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, వినియోగదారులు దాన్ని <ph name="PRODUCT_NAME" />లో మార్చలేరు లేదా భర్తీ చేయలేరు.
 
-          ఈ సెట్టింగ్‌ని నిలిపివేయడం కాన్ఫిగర్ చేయకుండా వదిలివేయడానికి సమానం. వినియోగదారు ఇప్పటికీ దీన్ని <ph name="PRODUCT_NAME" />లో మార్చగలరు.
+          ఈ సెట్టింగ్‌ని నిలిపివేయడం అన్నది దానిని కాన్ఫిగర్ చేయకుండా వదిలివేయడానికి సమానం. వినియోగదారు ఇప్పటికీ దీన్ని <ph name="PRODUCT_NAME" />లో మార్చగలరు.
 
           ఈ విధానం <ph name="MS_AD_NAME" /> డొమైన్‌లో చేరని Windows సందర్భాలకు
           అందుబాటులో ఉండదు.</translation>
@@ -1666,7 +1674,7 @@
 
       సెట్ చేయనప్పుడు (లేదా ఒప్పుకి సెట్ చేసినప్పుడు), విశ్వసనీయ మూలం నుండి డౌన్‌లోడ్ చేయబడిన ఫైల్‌లు అయినప్పటికీ సురక్షిత బ్రౌజింగ్ ద్వారా విశ్లేషించబడటానికి పంపబడతాయి.
 
-      ఈ నియంత్రణలు వెబ్ పేజీ కంటెంట్ నుండి ప్రారంభించిన డౌన్‌లోడ్‌లకు అలాగే 'డౌన్‌లోడ్ లింక్...' సందర్భ మెను ఎంపికకు వర్తిస్తాయని గమనించండి. ఈ నియంత్రణలు ప్రస్తుతం ప్రదర్శించబడే పేజీని సేవ్ చేయికి / డౌన్‌లోడ్ చేయికి వర్తించవు, అలాగే ప్రింట్ ఎంపికలలో  PDFగా సేవ్ చేస్తోందికి వర్తించవు.
+      ఈ నియంత్రణలు వెబ్ పేజీ కంటెంట్ నుండి ప్రారంభించిన డౌన్‌లోడ్‌లకు అలాగే 'డౌన్‌లోడ్ లింక్...' సందర్భ మెను ఎంపికకు వర్తిస్తాయని గమనించండి. ఈ నియంత్రణలు ప్రస్తుతం ప్రదర్శించబడే పేజీని సేవ్ చేయి / డౌన్‌లోడ్ చేయికి వర్తించవు, అలాగే ప్రింట్ ఎంపికలలో PDFగా సేవ్ చేసే ఎంపికకి వర్తించవు.
 
       ఈ విధానం <ph name="MS_AD_NAME" /> డొమైన్‌లో చేరని Windows సందర్భాలకు అందుబాటులో ఉండదు.</translation>
 <translation id="5105313908130842249">బ్యాటరీ శక్తితో అమలవుతున్నప్పుడు స్క్రీన్ లాక్ ఆలస్యం</translation>
@@ -1711,7 +1719,7 @@
 <translation id="523505283826916779">ప్రాప్యత సెట్టింగ్‌లు</translation>
 <translation id="5235958368503433463"><ph name="PRODUCT_NAME" />లో డిఫాల్ట్ హోమ్ పేజీ యొక్క రకాన్ని కాన్ఫిగర్ చేస్తుంది మరియు హోమ్ పేజీ ప్రాధాన్యతలను మార్చకుండా వినియోగదారులను నిరోధిస్తుంది. హోమ్ పేజీ మీరు పేర్కొనే URLకి సెట్ చేయబడవచ్చు లేదా కొత్త ట్యాబ్ పేజీకి సెట్ చేయబడవచ్చు.
 
-          మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, కొత్త ట్యాబ్ పేజీ ఎల్లప్పుడూ హోమ్ పేజీ కోసం ఉపయోగించబడుతుంది మరియు హోమ్ పేజీ URL స్థానం విస్మరించబడుతుంది.
+          మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, హోమ్ పేజీ కోసం ఎల్లప్పుడూ కొత్త ట్యాబ్ పేజీ ఉపయోగించబడుతుంది మరియు హోమ్ పేజీ URL స్థానం విస్మరించబడుతుంది.
 
           మీరు ఈ సెట్టింగ్‌ను నిలిపివేస్తే, వినియోగదారు హోమ్ పేజీ URLని 'chrome://newtab'కి సెట్ చేస్తే మినహా ఎన్నటికీ అది కొత్త ట్యాబ్ పేజీ కాదు.
 
@@ -1852,6 +1860,14 @@
       విధానం విలువ మిల్లీసెకన్లలో పేర్కొనాలి.</translation>
 <translation id="5511702823008968136">బుక్‌మార్క్ బార్‌ని ప్రారంభించు</translation>
 <translation id="5512418063782665071">హోమ్ పేజీ URL</translation>
+<translation id="551639594034811656">ఈ విధానం అప్‌డేట్ మొదట కనుగొనబడిన రోజు నుండి, OUలోని ప్రతి రోజు అప్‌డేట్ చేయబడిన <ph name="PRODUCT_OS_NAME" /> పరికరాల నిష్పత్తిని నిర్వచించే శాతాల జాబితాను నిర్వచిస్తుంది. అప్‌డేట్ ప్రచురించబడినప్పటి నుండి పరికరం అప్‌డేట్‌లను తనిఖీ చేయడానికి కాస్త సమయం పడుతుంది కాబట్టి, అప్‌డేట్‌ను కనుగొన్న సమయం అది ప్రచురింపబడిన సమయం తర్వాతే అయి ఉంటుంది.
+ప్రతి (రోజు, శాతం) జత అప్‌డేట్ కనుగొనబడినప్పటి నుండి ఇవ్వబడిన రోజులలో అప్‌డేట్ కాబడవలసిన ఫ్లీట్ శాతాన్ని కలిగి ఉంటుంది. ఉదాహరణకు, మన దగ్గర [(4, 40), (10, 70), (15, 100)] జతలు ఉంటే, అప్‌డేట్‌ను చూసిన తర్వాత 4 రోజులలో 40% ఫ్లీట్ అప్‌డేట్ చేయబడి ఉండాలి. 10 రోజుల తర్వాత 70% చేయబడాలి, అలాగే మిగిలినవి కూడా.
+
+ఈ విధానానికి నిర్వచించబడిన ఎదైనా విలువ ఉంటే, అప్‌డేట్‌లు <ph name="DEVICE_UPDATE_SCATTER_FACTOR_POLICY_NAME" /> విధానాన్ని విస్మరించి, దానికి బదులు ఈ విధానాన్ని అనుసరిస్తాయి.
+
+ఈ జాబితా ఖాళీగా ఉంటే, ఎలాంటి స్టేజింగ్ ఉండదు మరియు అప్‌డేట్‌లు పరికరం ఇతర విధానాలను బట్టి వర్తింపచేయబడతాయి.
+
+ఈ విధానం ఛానెల్ మార్పులకు వర్తించదు.</translation>
 <translation id="5523812257194833591">ఆలస్యం తర్వాత స్వీయ లాగిన్‌కు పబ్లిక్ సెషన్‌.
 
       ఈ విధానం సెట్ చేయబడితే, లాగిన్ స్క్రీన్‌లో వినియోగదారు పరస్పర చర్య లేని సమయ వ్యవధి తర్వాత నిర్దిష్ట సెషన్ స్వయంచాలకంగా లాగిన్ చేయబడుతుంది. పబ్లిక్ సెషన్‌ను తప్పనిసరిగా ముందుగానే కాన్ఫిగర్ చేయాలి (|DeviceLocalAccounts|ని చూడండి).
@@ -1909,7 +1925,7 @@
 ఈ విధానాన్ని సెట్ చేయనప్పుడు, డిఫాల్ట్ చర్య అయిన తాత్కాలిక తొలగింపు తీసుకోబడుతుంది.
 
 చర్య తాత్కాలిక తొలగింపు అయితే, తాత్కాలిక తొలగింపుకు పూర్వం స్క్రీన్ లాక్ కావాలని లేదా లాక్ కాకూడదని <ph name="PRODUCT_OS_NAME" /> వేరుగా కాన్ఫిగర్ చేయబడవచ్చు.</translation>
-<translation id="5618398258385745432">పాస్‌వర్డ్‌ల వీక్షణ పరిచయం పునఃప్రమాణీకరణకు ముందు అనుబంధించిన సెట్టింగ్ ఉపయోగించబడుతుంది. అప్పటి నుండి, సెట్టింగ్ మరియు ఈ విధానం Chrome ప్రవర్తనపై ఎలాంటి ప్రభావాన్ని కలిగి ఉండవు. Chrome ప్రస్తుత ప్రవర్తన అనేది పాస్‌వర్డ్ సెట్టింగ్‌ల పేజీలో స్పష్టమైన వచనంలా పాస్‌వర్డ్‌లను చూపడాన్ని నిలిపివేతకు సెట్ చేసినప్పటి ప్రవర్తన లాగే ఉంటుంది. సెట్టింగ్‌ల పేజీ ప్లేస్‌హోల్డర్‌ను మాత్రమే కలిగి ఉంటుంది మరియు వినియోగదారు "చూపు" (మరియు అవసరమైతే, పునఃప్రమాణీకరణ) క్లిక్ చేసినప్పుడు మాత్రమే Chrome పాస్‌వర్డ్‌ని చూపుతుంది. విధానం అసలైన వివరణ దిగువ ఉంది.
+<translation id="5618398258385745432">పాస్‌వర్డ్‌ల వీక్షణ కోసం పునఃప్రమాణీకరణ ఎంపికను అందించడానికి ముందు ఈ అనుబంధ సెట్టింగ్ ఉపయోగించబడేది. అప్పటి నుండి, సెట్టింగ్ మరియు ఈ విధానం Chrome ప్రవర్తనపై ఎలాంటి ప్రభావాన్ని కలిగి లేవు. Chrome ప్రస్తుత ప్రవర్తన అనేది పాస్‌వర్డ్ సెట్టింగ్‌ల పేజీలో స్పష్టమైన వచనంలా పాస్‌వర్డ్‌లను చూపడాన్ని నిలిపివేతకు సెట్ చేసినప్పటి ప్రవర్తన లాగే ఉంటుంది. సెట్టింగ్‌ల పేజీ ప్లేస్‌హోల్డర్‌ను మాత్రమే కలిగి ఉంటుంది మరియు వినియోగదారు "చూపు" క్లిక్ చేసినప్పుడు (మరియు అవసరమైతే, పునఃప్రమాణీకరణ చేసినప్పుడు) మాత్రమే Chrome పాస్‌వర్డ్‌ని చూపుతుంది. విధానం అసలైన వివరణ దిగువ ఉంది.
 
           పాస్‌వర్డ్ మేనేజర్‌లో స్పష్టమైన వచనంలా వినియోగదారు పాస్‌వర్డ్‌లను చూపవచ్చో లేదో అనేదాన్ని నియంత్రిస్తుంది.
 
@@ -2090,7 +2106,7 @@
 
           హోమ్ పేజీ అనేది హోమ్ బటన్ ద్వారా తెరవబడే పేజీ. ప్రారంభంలో తెరవబడే పేజీలు RestoreOnStartup విధానాల ద్వారా నియంత్రించబడతాయి.
 
-          హోమ్ పేజీ రకం మీరు ఇక్కడ పేర్కొనే URLకి సెట్ చేయబడుతుంది లేదా కొత్త ట్యాబ్ పేజీకి సెట్ చేయబడుతుంది. మీరు కొత్త ట్యాబ్ పేజీని ఎంచుకుంటే, ఆపై ఈ విధానం ప్రభావం చూపదు.
+          హోమ్ పేజీ రకం మీరు ఇక్కడ పేర్కొనే URLకి సెట్ చేయవచ్చు లేదా కొత్త ట్యాబ్ పేజీకి సెట్ చేయవచ్చు. మీరు కొత్త ట్యాబ్ పేజీని ఎంచుకుంటే, ఆపై ఈ విధానం ప్రభావం చూపదు.
 
           మీరు ఈ సెట్టింగ్‌ను ప్రారంభిస్తే, వినియోగదారులు <ph name="PRODUCT_NAME" />లో వారి హోమ్ పేజీ URLను మార్చలేరు, కానీ వారు కొత్త ట్యాబ్ పేజీని వారి హోమ్ పేజీగా ఇప్పటికీ ఎంచుకోగలరు.
 
@@ -2665,7 +2681,7 @@
 
           ఈ విధానం 'RestoreOnStartup' విధానాన్ని 'RestoreOnStartupIsURLs'కి సెట్ చేసినప్పుడు మాత్రమే పని చేస్తుంది.
 
-          ఈ విధానం Windowsని <ph name="MS_AD_NAME" /> డొమైన్‌కు చేరని సందర్భాలలో
+          ఈ విధానం <ph name="MS_AD_NAME" /> డొమైన్‌కు చేరని Windows సందర్భాలలో
           అందుబాటులో ఉండదు.</translation>
 <translation id="7593523670408385997">డిస్క్‌లో కాష్ చేసిన ఫైల్‌లను నిల్వ చేయడానికి <ph name="PRODUCT_NAME" /> ఉపయోగించే కాష్ పరిమాణాన్ని కాన్ఫిగర్ చేస్తుంది.
 
@@ -2732,7 +2748,7 @@
 
           కొత్త ట్యాబ్ పేజీ అనేది కొత్త ట్యాబ్‌లను సృష్టించినప్పుడు తెరవబడే పేజీ (కొత్త విండోలలో తెరిచిన దానితో సహా).
 
-          ఈ విధానం ప్రారంభంలో ఏ పేజీలను తెరవాలో నిర్ణయించదు. అవి <ph name="RESTORE_ON_STARTUP_POLICY_NAME" /> విధానాల ద్వారా నియంత్రించబడతాయి. అయినప్పటికీ ఈ విధానం కొత్త ట్యాబ్ పేజీని తెరవడానికి సెట్ చేయబడితే హోమ్ పేజీపై, అలాగే అది కొత్త ట్యాబ్ పేజీకి సెట్ చేయబడితే ప్రారంభ పేజీపై ప్రభావాన్ని చూపదు.
+          ఈ విధానం ప్రారంభంలో ఏ పేజీలను తెరవాలో నిర్ణయించదు. అవి <ph name="RESTORE_ON_STARTUP_POLICY_NAME" /> విధానాల ద్వారా నియంత్రించబడతాయి. అయినప్పటికీ, హోమ్ పేజీ అనేది కొత్త ట్యాబ్ పేజీని తెరిచేలా సెట్ చేయబడినట్లైతే, అలాగే ప్రారంభ పేజీ అనేది కొత్త ట్యాబ్ పేజీని తెరిచేలా సెట్ చేయబడినట్లైతే, ఆ హోమ్ పేజీ మరియు ప్రారంభ పేజీలపై ఈ విధానం ప్రభావితం చేస్తుంది.
 
           విధానాన్ని సెట్ చేయకపోతే లేదా ఖాళీగా వదిలివేస్తే డిఫాల్ట్ కొత్త ట్యాబ్ పేజీ ఉపయోగించబడుతుంది.
 
@@ -2855,6 +2871,9 @@
       విధానాన్ని నిలిపివేస్తే, ప్రత్యేకంగా సైట్‌ని వేరుపరిచే ప్రాసెస్ జరగదు మరియు IsolateOrigins మరియు SitePerProcess యొక్క ఫీల్డ్ ట్రయల్‌లు నిలిపివేయబడతాయి. వినియోగదారులు ఇప్పటికీ SitePerProcessను మాన్యువల్‌గా ప్రారంభించగలుగుతారు.
       విధానాన్ని కాన్ఫిగర్ చేయకపోతే, వినియోగదారు ఈ సెట్టింగ్‌ను మార్చగలుగుతారు.
       </translation>
+<translation id="7902255855035461275">ఈ జాబితాలోని ఆకృతులు అభ్యర్థిస్తున్న URL భద్రతా మూలాధారంతో సరిపోల్చబడతాయి. సరిపోలినది కనుగొనబడితే, వీడియోను కాప్చర్ చేసే పరికరాలకు ఎలాంటి ప్రేరేపణ లేకుండా యాక్సెస్ మంజూరు చేయబడుతుంది.
+
+గమనిక: వెర్షన్ 45 వరకు, ఈ విధానానికి కియోస్క్ మోడ్‌లో మాత్రమే మద్దతు ఇవ్వబడింది.</translation>
 <translation id="7912255076272890813">అనుమతించబడిన అనువర్తన/పొడిగింపు రకాలను కాన్ఫిగర్ చేయండి</translation>
 <translation id="7915236031252389808">మీరు ఇక్కడ ప్రాక్సీ .pac ఫైల్‌కు URLను పేర్కొనవచ్చు.
 
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb
index 88ca203..45db0f2 100644
--- a/components/policy/resources/policy_templates_th.xtb
+++ b/components/policy/resources/policy_templates_th.xtb
@@ -291,7 +291,7 @@
       หากไม่ได้ตั้งค่านโยบายนี้ ระบบจะใช้ค่าเริ่มต้นสำหรับการตั้งค่าทั้งหมด</translation>
 <translation id="1958138414749279167">เปิดใช้ฟีเจอร์ป้อนข้อความอัตโนมัติของ <ph name="PRODUCT_NAME" /> และอนุญาตให้ผู้ใช้ป้อนข้อมูลที่อยู่ในเว็บฟอร์มโดยอัตโนมัติด้วยข้อมูลที่เก็บไว้ก่อนหน้านี้
 
-      หากคุณปิดใช้การตั้งค่านี้ ฟีเจอร์ป้อนข้อความอัตโนมัติจะไม่แนะนำหรือกรอกข้อมูลที่อยู่ให้โดยอัตโนมัติ และจะไม่บันทึกข้อมูลที่อยู่ที่ผู้ใช้อาจส่งมาขณะเรียกดูเว็บ
+      หากคุณปิดใช้การตั้งค่านี้ ฟีเจอร์ป้อนข้อความอัตโนมัติจะไม่แนะนำหรือกรอกข้อมูลที่อยู่ให้โดยอัตโนมัติ และจะไม่บันทึกข้อมูลที่อยู่เพิ่มเติมที่ผู้ใช้อาจส่งมาขณะเรียกดูเว็บ
 
       หากคุณเปิดใช้การตั้งค่านี้หรือไม่ได้กำหนดค่าไว้ ผู้ใช้จะควบคุมฟีเจอร์ป้อนข้อความอัตโนมัติสำหรับที่อยู่ได้ใน UI</translation>
 <translation id="1960840544413786116">จะอนุญาตใบรับรองที่ออกโดย Trust Anchor ในพื้นที่ที่ไม่มีส่วนขยาย subjectAlternativeName หรือไม่</translation>
@@ -1847,7 +1847,7 @@
 <translation id="6440051664870270040">อนุญาตให้เว็บไซต์นำทางและเปิดป๊อปอัปพร้อมกันได้</translation>
 <translation id="6447948611083700881">การสำรองและกู้คืนข้อมูลปิดใช้อยู่</translation>
 <translation id="645425387487868471">เปิดใช้การบังคับลงชื่อเข้าใช้สำหรับ <ph name="PRODUCT_NAME" /></translation>
-<translation id="6464074037294098618">เปิดใช้ป้อนข้อความอัตโนมัติสำหรับที่อยู่</translation>
+<translation id="6464074037294098618">เปิดใช้ฟีเจอร์ป้อนข้อความอัตโนมัติสำหรับที่อยู่</translation>
 <translation id="6473623140202114570">กำหนดค่ารายการโดเมนที่ Safe Browsing จะไม่เรียกให้คำเตือนแสดง</translation>
 <translation id="6491139795995924304">อนุญาตบลูทูธบนอุปกรณ์</translation>
 <translation id="6520802717075138474">นำเข้าเครื่องมือค้นหาจากเบราว์เซอร์เริ่มต้นในการเรียกใช้งานครั้งแรก</translation>
diff --git a/components/policy/resources/policy_templates_vi.xtb b/components/policy/resources/policy_templates_vi.xtb
index 61a0d8a..1e189c7 100644
--- a/components/policy/resources/policy_templates_vi.xtb
+++ b/components/policy/resources/policy_templates_vi.xtb
@@ -296,7 +296,7 @@
       Nếu cài đặt không được chỉ định, giá trị mặc định sẽ được sử dụng.
 
       Nếu chính sách này không được thiết lập, các giá trị mặc định sẽ được sử dụng cho tất cả cài đặt.</translation>
-<translation id="1958138414749279167">Bật tính năng Tự động điền của <ph name="PRODUCT_NAME" /> và cho phép người dùng tự động hoàn thành thông tin địa chỉ trong biểu mẫu web bằng cách sử dụng thông tin đã lưu trữ trước đây.
+<translation id="1958138414749279167">Bật tính năng Tự động điền của <ph name="PRODUCT_NAME" /> và cho phép người dùng tự động hoàn thành thông tin địa chỉ trong các biểu mẫu web bằng thông tin đã lưu trữ trước đây.
 
       Nếu bạn tắt tùy chọn cài đặt này, thì tính năng Tự động điền sẽ không bao giờ gợi ý hoặc điền thông tin địa chỉ, đồng thời sẽ không lưu thông tin địa chỉ bổ sung mà người dùng có thể gửi trong khi duyệt web.
 
diff --git a/components/policy/resources/policy_templates_zh-CN.xtb b/components/policy/resources/policy_templates_zh-CN.xtb
index 19fa47e..aaf232d6 100644
--- a/components/policy/resources/policy_templates_zh-CN.xtb
+++ b/components/policy/resources/policy_templates_zh-CN.xtb
@@ -480,6 +480,11 @@
       如果此设置未指定,那么用户可以决定是否使用此功能。
 
       29 版及更高版本的 <ph name="PRODUCT_NAME" /> 中已取消此设置。</translation>
+<translation id="2433412232489478893">此政策可控制是否允许用户在 <ph name="PRODUCT_NAME" />使用网络文件共享功能。
+
+      如果未配置此政策或将其设为“True”,用户将能够使用网络文件共享功能。
+
+      如果将此政策设为“False”,用户将无法使用网络文件共享功能。</translation>
 <translation id="2438609638493026652">允许向 Google 报告 Android 应用安装过程中发生的重要事件。系统仅会针对通过政策触发安装的应用捕获相关事件。
 
       如果此政策设为 true,系统将会记录相关事件。
@@ -557,6 +562,7 @@
 <translation id="2598508021807251719">配置 <ph name="PRODUCT_OS_NAME" />可以使用哪些语言区域进行显示。
 
       如果已设置此政策,则用户只能将 <ph name="PRODUCT_OS_NAME" />配置为使用此政策中指定的语言区域之一进行显示。如果此政策设为空列表或未设置,则 <ph name="PRODUCT_OS_NAME" />可以使用所有受支持的界面语言区域进行显示。如果此政策设为一个包含无效值的列表,则系统会忽略所有无效值。如果用户曾将 <ph name="PRODUCT_OS_NAME" />配置为使用此政策所不允许的某种语言区域进行显示,那么当用户下次登录时,相应的显示语言区域将会切换到所允许的某种界面语言区域。如果用户已配置了首选语言区域,并且此政策允许其中的某一种首选语言区域,<ph name="PRODUCT_OS_NAME" />将会切换到此语言区域。否则,<ph name="PRODUCT_OS_NAME" />将会切换到此政策中指定的第一个有效值;如果此政策所含的条目都无效,就会切换到后备语言区域(目前为 en-US)。</translation>
+<translation id="2604182581880595781">配置网络文件共享功能相关政策。</translation>
 <translation id="2623014935069176671">等待首个用户活动</translation>
 <translation id="262740370354162807">允许将文档提交到 <ph name="CLOUD_PRINT_NAME" /></translation>
 <translation id="2627554163382448569">为企业打印机提供配置。
@@ -636,6 +642,7 @@
 <translation id="2823870601012066791"><ph name="PRODUCT_OS_NAME" />客户端的 Windows 注册表位置:</translation>
 <translation id="2824715612115726353">启用隐身模式</translation>
 <translation id="2838830882081735096">禁止数据迁移和 ARC</translation>
+<translation id="2839294585867804686">网络文件共享功能设置</translation>
 <translation id="2840269525054388612">指定用户可以使用的打印机。
 
       仅当为 <ph name="DEVICE_PRINTERS_ACCESS_MODE" /> 选择了 <ph name="PRINTERS_WHITELIST" /> 时,才可使用此政策
@@ -1106,6 +1113,7 @@
       如果未设置此政策,系统将启用包含网址的匿名化数据收集功能,但用户将能够更改此设置。</translation>
 <translation id="4250680216510889253">否</translation>
 <translation id="4261820385751181068">设备登录屏幕语言区域</translation>
+<translation id="4264607809747169568">控制是否允许在 Chrome 操作系统使用网络文件共享功能</translation>
 <translation id="427220754384423013">指定用户可以使用的打印机。
 
       仅当为 <ph name="BULK_PRINTERS_ACCESS_MODE" /> 选择了 <ph name="PRINTERS_WHITELIST" /> 时,才可使用此政策。
@@ -1503,6 +1511,15 @@
       该策略值应该以毫秒为单位。</translation>
 <translation id="5511702823008968136">启用书签栏</translation>
 <translation id="5512418063782665071">主页网址</translation>
+<translation id="551639594034811656">此政策可指定一个百分比列表,这些百分比用于界定组织单元中每天(从首次发现相应更新的那一天起算)要更新的那部分 <ph name="PRODUCT_OS_NAME" />设备。发现时间会晚于更新发布时间,这是因为设备可能要在更新发布一段时间之后才会检查是否有更新。
+
+      每个 (天数, 百分比) 对都包含自发现更新当天起的指定天数内,必须完成更新的设备百分比。例如,如果有以下对:[(4, 40), (10, 70), (15, 100)],则表示在发现更新后的 4 天内,应完成 40% 的设备更新,10 天内完成 70% 的设备更新,以此类推。
+
+      如果为此政策指定了值,相应更新将会忽略 <ph name="DEVICE_UPDATE_SCATTER_FACTOR_POLICY_NAME" /> 政策并改为遵守此政策。
+
+      如果此列表为空,系统将不会分阶段进行更新,而是会根据其他设备政策应用更新。
+
+      此政策不适用于版本切换。</translation>
 <translation id="5523812257194833591">延迟后的自动登录公用自助终端。
 
       如果设置了此政策,则用户未与登录屏幕互动的时间达到指定的时长后,将会自动登录指定的会话。此公用自助终端必须已配置(参阅 |DeviceLocalAccounts|)。
@@ -2386,6 +2403,9 @@
       如果停用了此政策,则不会发生明确的网站隔离,IsolateOrigins 和 SitePerProcess 的现场试验也将停用。用户仍可手动启用 SitePerProcess。
       如果未配置此政策,用户将能够更改此设置。
       </translation>
+<translation id="7902255855035461275">系统会将此列表中的网址格式与请求网址的安全来源进行比对。如果找到了匹配项,系统将允许相应网址使用视频捕获设备,并且不会进行提示。
+
+      请注意:在 45 版之前,只有在自助服务终端模式下此政策才受支持。</translation>
 <translation id="7912255076272890813">配置允许的应用/扩展程序类型</translation>
 <translation id="7915236031252389808">您可以在此指定代理 .pac 文件的网址。
 
diff --git a/components/prefs/json_pref_store.cc b/components/prefs/json_pref_store.cc
index c7a6e144..c4da4c2 100644
--- a/components/prefs/json_pref_store.cc
+++ b/components/prefs/json_pref_store.cc
@@ -104,6 +104,8 @@
   // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
   // macro adapted to allow for a dynamically suffixed histogram name.
   // Note: The factory creates and owns the histogram.
+  // This histogram is expired but the code was intentionally left behind so
+  // it can be re-enabled on Stable in a single config tweak if needed.
   base::HistogramBase* histogram = base::Histogram::FactoryGet(
       "Settings.JsonDataReadSizeKilobytes." + spaceless_basename, 1, 10000, 50,
       base::HistogramBase::kUmaTargetedHistogramFlag);
@@ -132,8 +134,8 @@
 
 JsonPrefStore::JsonPrefStore(
     const base::FilePath& pref_filename,
-    scoped_refptr<base::SequencedTaskRunner> file_task_runner,
-    std::unique_ptr<PrefFilter> pref_filter)
+    std::unique_ptr<PrefFilter> pref_filter,
+    scoped_refptr<base::SequencedTaskRunner> file_task_runner)
     : path_(pref_filename),
       file_task_runner_(std::move(file_task_runner)),
       prefs_(new base::DictionaryValue()),
@@ -272,7 +274,9 @@
       base::Bind(&JsonPrefStore::OnFileRead, AsWeakPtr()));
 }
 
-void JsonPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
+void JsonPrefStore::CommitPendingWrite(
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Schedule a write for any lossy writes that are outstanding to ensure that
@@ -282,13 +286,19 @@
   if (writer_.HasPendingWrite() && !read_only_)
     writer_.DoScheduledWrite();
 
-  if (done_callback) {
-    // Since disk operations occur on |file_task_runner_|, the reply of a task
-    // posted to |file_task_runner_| will run after currently pending disk
-    // operations. Also, by definition of PostTaskAndReply(), the reply will run
-    // on the current sequence.
+  // Since disk operations occur on |file_task_runner_|, the reply of a task
+  // posted to |file_task_runner_| will run after currently pending disk
+  // operations. Also, by definition of PostTaskAndReply(), the reply (in the
+  // |reply_callback| case will run on the current sequence.
+
+  if (synchronous_done_callback) {
+    file_task_runner_->PostTask(FROM_HERE,
+                                std::move(synchronous_done_callback));
+  }
+
+  if (reply_callback) {
     file_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
-                                        std::move(done_callback));
+                                        std::move(reply_callback));
   }
 }
 
@@ -444,7 +454,7 @@
 
 JsonPrefStore::~JsonPrefStore() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  CommitPendingWrite(base::OnceClosure());
+  CommitPendingWrite();
 }
 
 bool JsonPrefStore::SerializeData(std::string* output) {
diff --git a/components/prefs/json_pref_store.h b/components/prefs/json_pref_store.h
index 383a257f..c56c51f 100644
--- a/components/prefs/json_pref_store.h
+++ b/components/prefs/json_pref_store.h
@@ -62,12 +62,20 @@
   // have the base::TaskShutdownBehavior::BLOCK_SHUTDOWN and base::MayBlock()
   // traits. Unless external tasks need to run on the same sequence as
   // JsonPrefStore tasks, keep the default value.
+  // The initial read is done synchronously, the TaskPriority is thus only used
+  // for flushes to disks and BACKGROUND is therefore appropriate. Priority of
+  // remaining BACKGROUND+BLOCK_SHUTDOWN tasks is bumped by the TaskScheduler on
+  // shutdown. However, some shutdown use cases happen without
+  // TaskScheduler::Shutdown() (e.g. ChromeRestartRequest::Start() and
+  // BrowserProcessImpl::EndSession()) and we must thus unfortunately make this
+  // USER_VISIBLE until we solve https://crbug.com/747495 to allow bumping
+  // priority of a sequence on demand.
   JsonPrefStore(const base::FilePath& pref_filename,
+                std::unique_ptr<PrefFilter> pref_filter = nullptr,
                 scoped_refptr<base::SequencedTaskRunner> file_task_runner =
                     base::CreateSequencedTaskRunnerWithTraits(
-                        {base::MayBlock(),
-                         base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
-                std::unique_ptr<PrefFilter> pref_filter = nullptr);
+                        {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+                         base::TaskShutdownBehavior::BLOCK_SHUTDOWN}));
 
   // PrefStore overrides:
   bool GetValue(const std::string& key,
@@ -94,7 +102,10 @@
   // See details in pref_filter.h.
   PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
-  void CommitPendingWrite(base::OnceClosure done_callback) override;
+  void CommitPendingWrite(
+      base::OnceClosure reply_callback = base::OnceClosure(),
+      base::OnceClosure synchronous_done_callback =
+          base::OnceClosure()) override;
   void SchedulePendingLossyWrites() override;
   void ReportValueChanged(const std::string& key, uint32_t flags) override;
 
diff --git a/components/prefs/json_pref_store_unittest.cc b/components/prefs/json_pref_store_unittest.cc
index b084ebd..15e2872c 100644
--- a/components/prefs/json_pref_store_unittest.cc
+++ b/components/prefs/json_pref_store_unittest.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
@@ -22,6 +23,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
@@ -130,19 +132,50 @@
 };
 
 enum class CommitPendingWriteMode {
+  // Basic mode.
   WITHOUT_CALLBACK,
+  // With reply callback.
   WITH_CALLBACK,
+  // With synchronous notify callback (synchronous after the write -- shouldn't
+  // require pumping messages to observe).
+  WITH_SYNCHRONOUS_CALLBACK,
 };
 
+base::test::ScopedTaskEnvironment::ExecutionMode GetExecutionMode(
+    CommitPendingWriteMode commit_mode) {
+  switch (commit_mode) {
+    case CommitPendingWriteMode::WITHOUT_CALLBACK:
+      FALLTHROUGH;
+    case CommitPendingWriteMode::WITH_CALLBACK:
+      return base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED;
+    case CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK:
+      // Synchronous callbacks require async tasks to run on their own.
+      return base::test::ScopedTaskEnvironment::ExecutionMode::ASYNC;
+  }
+}
+
 void CommitPendingWrite(
     JsonPrefStore* pref_store,
     CommitPendingWriteMode commit_pending_write_mode,
     base::test::ScopedTaskEnvironment* scoped_task_environment) {
-  if (commit_pending_write_mode == CommitPendingWriteMode::WITHOUT_CALLBACK) {
-    pref_store->CommitPendingWrite(OnceClosure());
-    scoped_task_environment->RunUntilIdle();
-  } else {
-    TestCommitPendingWriteWithCallback(pref_store, scoped_task_environment);
+  switch (commit_pending_write_mode) {
+    case CommitPendingWriteMode::WITHOUT_CALLBACK: {
+      pref_store->CommitPendingWrite();
+      scoped_task_environment->RunUntilIdle();
+      break;
+    }
+    case CommitPendingWriteMode::WITH_CALLBACK: {
+      TestCommitPendingWriteWithCallback(pref_store, scoped_task_environment);
+      break;
+    }
+    case CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK: {
+      base::WaitableEvent written;
+      pref_store->CommitPendingWrite(
+          base::OnceClosure(),
+          base::BindOnce(&base::WaitableEvent::Signal, Unretained(&written)));
+      written.Wait();
+      break;
+    }
   }
 }
 
@@ -152,7 +185,7 @@
   JsonPrefStoreTest()
       : scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
-            base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
+            GetExecutionMode(GetParam())) {}
 
  protected:
   void SetUp() override {
@@ -170,7 +203,7 @@
 }  // namespace
 
 // Test fallback behavior for a nonexistent file.
-TEST_F(JsonPrefStoreTest, NonExistentFile) {
+TEST_P(JsonPrefStoreTest, NonExistentFile) {
   base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
   ASSERT_FALSE(PathExists(bogus_input_file));
   auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
@@ -180,7 +213,7 @@
 }
 
 // Test fallback behavior for an invalid file.
-TEST_F(JsonPrefStoreTest, InvalidFile) {
+TEST_P(JsonPrefStoreTest, InvalidFile) {
   base::FilePath invalid_file = temp_dir_.GetPath().AppendASCII("invalid.json");
   ASSERT_LT(0, base::WriteFile(invalid_file,
                                kInvalidJson, arraysize(kInvalidJson) - 1));
@@ -371,7 +404,7 @@
 
 // This test is just documenting some potentially non-obvious behavior. It
 // shouldn't be taken as normative.
-TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
+TEST_P(JsonPrefStoreTest, RemoveClearsEmptyParent) {
   FilePath pref_file = temp_dir_.GetPath().AppendASCII("empty_values.json");
 
   auto pref_store = base::MakeRefCounted<JsonPrefStore>(pref_file);
@@ -390,7 +423,7 @@
 }
 
 // Tests asynchronous reading of the file when there is no file.
-TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
+TEST_P(JsonPrefStoreTest, AsyncNonExistingFile) {
   base::FilePath bogus_input_file = temp_dir_.GetPath().AppendASCII("read.txt");
   ASSERT_FALSE(PathExists(bogus_input_file));
   auto pref_store = base::MakeRefCounted<JsonPrefStore>(bogus_input_file);
@@ -419,8 +452,7 @@
   InterceptingPrefFilter* raw_intercepting_pref_filter_ =
       intercepting_pref_filter.get();
   auto pref_store = base::MakeRefCounted<JsonPrefStore>(
-      input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
-      std::move(intercepting_pref_filter));
+      input_file, std::move(intercepting_pref_filter));
 
   ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
             pref_store->ReadPrefs());
@@ -462,8 +494,7 @@
   InterceptingPrefFilter* raw_intercepting_pref_filter_ =
       intercepting_pref_filter.get();
   auto pref_store = base::MakeRefCounted<JsonPrefStore>(
-      input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
-      std::move(intercepting_pref_filter));
+      input_file, std::move(intercepting_pref_filter));
 
   MockPrefStoreObserver mock_observer;
   pref_store->AddObserver(&mock_observer);
@@ -514,7 +545,7 @@
                             &scoped_task_environment_);
 }
 
-TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
+TEST_P(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
   base::HistogramTester histogram_tester;
 
   SimpleTestClock* test_clock = new SimpleTestClock;
@@ -542,7 +573,7 @@
   ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
 }
 
-TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
+TEST_P(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
   base::HistogramTester histogram_tester;
 
   SimpleTestClock* test_clock = new SimpleTestClock;
@@ -580,7 +611,7 @@
   histogram_tester.ExpectTotalCount(histogram_name, 1);
 }
 
-TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
+TEST_P(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
   base::HistogramTester histogram_tester;
 
   SimpleTestClock* test_clock = new SimpleTestClock;
@@ -620,7 +651,7 @@
   histogram_tester.ExpectTotalCount(histogram_name, 3);
 }
 
-TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
+TEST_P(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
   base::HistogramTester histogram_tester;
 
   SimpleTestClock* test_clock = new SimpleTestClock;
@@ -671,6 +702,10 @@
     WithCallback,
     JsonPrefStoreTest,
     ::testing::Values(CommitPendingWriteMode::WITH_CALLBACK));
+INSTANTIATE_TEST_CASE_P(
+    WithSynchronousCallback,
+    JsonPrefStoreTest,
+    ::testing::Values(CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK));
 
 class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
  public:
@@ -706,7 +741,7 @@
   DISALLOW_COPY_AND_ASSIGN(JsonPrefStoreLossyWriteTest);
 };
 
-TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
+TEST_P(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
   scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
 
@@ -751,7 +786,7 @@
             GetTestFileContents());
 }
 
-TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
+TEST_P(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
   scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
 
@@ -773,7 +808,7 @@
   ASSERT_FALSE(file_writer->HasPendingWrite());
 }
 
-TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
+TEST_P(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
   scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
 
@@ -795,7 +830,7 @@
   ASSERT_FALSE(file_writer->HasPendingWrite());
 }
 
-TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
+TEST_P(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
   scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
 
@@ -815,6 +850,19 @@
   ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
 }
 
+INSTANTIATE_TEST_CASE_P(
+    WithoutCallback,
+    JsonPrefStoreLossyWriteTest,
+    ::testing::Values(CommitPendingWriteMode::WITHOUT_CALLBACK));
+INSTANTIATE_TEST_CASE_P(
+    WithReply,
+    JsonPrefStoreLossyWriteTest,
+    ::testing::Values(CommitPendingWriteMode::WITH_CALLBACK));
+INSTANTIATE_TEST_CASE_P(
+    WithNotify,
+    JsonPrefStoreLossyWriteTest,
+    ::testing::Values(CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK));
+
 class SuccessfulWriteReplyObserver {
  public:
   SuccessfulWriteReplyObserver() = default;
@@ -912,13 +960,13 @@
   return state;
 }
 
-class JsonPrefStoreCallbackTest : public JsonPrefStoreTest {
+class JsonPrefStoreCallbackTest : public testing::Test {
  public:
   JsonPrefStoreCallbackTest() = default;
 
  protected:
   void SetUp() override {
-    JsonPrefStoreTest::SetUp();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     test_file_ = temp_dir_.GetPath().AppendASCII("test.json");
   }
 
@@ -943,6 +991,13 @@
   SuccessfulWriteReplyObserver successful_write_reply_observer_;
   WriteCallbacksObserver write_callback_observer_;
 
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+      base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED};
+
+  base::ScopedTempDir temp_dir_;
+
  private:
   base::FilePath test_file_;
 
@@ -957,8 +1012,7 @@
   std::unique_ptr<InterceptingPrefFilter> intercepting_pref_filter(
       new InterceptingPrefFilter(write_callback_observer_.GetCallbackPair()));
   auto pref_store = base::MakeRefCounted<JsonPrefStore>(
-      input_file, base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()}),
-      std::move(intercepting_pref_filter));
+      input_file, std::move(intercepting_pref_filter));
   ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store.get());
 
   EXPECT_EQ(NOT_CALLED,
diff --git a/components/prefs/overlay_user_pref_store.cc b/components/prefs/overlay_user_pref_store.cc
index 2b45d8c64..e5240ab 100644
--- a/components/prefs/overlay_user_pref_store.cc
+++ b/components/prefs/overlay_user_pref_store.cc
@@ -180,8 +180,11 @@
   OnInitializationCompleted(/* ephemeral */ false, true);
 }
 
-void OverlayUserPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
-  persistent_user_pref_store_->CommitPendingWrite(std::move(done_callback));
+void OverlayUserPrefStore::CommitPendingWrite(
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
+  persistent_user_pref_store_->CommitPendingWrite(
+      std::move(reply_callback), std::move(synchronous_done_callback));
   // We do not write our content intentionally.
 }
 
diff --git a/components/prefs/overlay_user_pref_store.h b/components/prefs/overlay_user_pref_store.h
index 0817aed..cf9d8677 100644
--- a/components/prefs/overlay_user_pref_store.h
+++ b/components/prefs/overlay_user_pref_store.h
@@ -57,7 +57,8 @@
   PrefReadError GetReadError() const override;
   PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* delegate) override;
-  void CommitPendingWrite(base::OnceClosure done_callback) override;
+  void CommitPendingWrite(base::OnceClosure reply_callback,
+                          base::OnceClosure synchronous_done_callback) override;
   void SchedulePendingLossyWrites() override;
   void ReportValueChanged(const std::string& key, uint32_t flags) override;
 
diff --git a/components/prefs/persistent_pref_store.cc b/components/prefs/persistent_pref_store.cc
index 9d3a42af..1dea8b7d 100644
--- a/components/prefs/persistent_pref_store.cc
+++ b/components/prefs/persistent_pref_store.cc
@@ -8,11 +8,20 @@
 
 #include "base/threading/sequenced_task_runner_handle.h"
 
-void PersistentPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
+void PersistentPrefStore::CommitPendingWrite(
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
   // Default behavior for PersistentPrefStore implementation that don't issue
   // disk operations: schedule the callback immediately.
-  if (done_callback) {
+  // |synchronous_done_callback| is allowed to be invoked synchronously (and
+  // must be here since we have no other way to post it which isn't the current
+  // sequence).
+
+  if (synchronous_done_callback)
+    std::move(synchronous_done_callback).Run();
+
+  if (reply_callback) {
     base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                     std::move(done_callback));
+                                                     std::move(reply_callback));
   }
 }
diff --git a/components/prefs/persistent_pref_store.h b/components/prefs/persistent_pref_store.h
index d2667b0..f3a5bbb3 100644
--- a/components/prefs/persistent_pref_store.h
+++ b/components/prefs/persistent_pref_store.h
@@ -62,10 +62,16 @@
   // Owns |error_delegate|.
   virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0;
 
-  // Starts an asynchronous attempt to commit pending writes to disk. Posts a
-  // task to run |done_callback| on the current sequence when disk operations,
-  // if any, are complete (even if they are unsuccessful).
-  virtual void CommitPendingWrite(base::OnceClosure done_callback);
+  // Lands pending writes to disk. |reply_callback| will be posted to the
+  // current sequence when changes have been written.
+  // |synchronous_done_callback| on the other hand will be invoked right away
+  // wherever the writes complete (could even be invoked synchronously if no
+  // writes need to occur); this is useful when the current thread cannot pump
+  // messages to observe the reply (e.g. nested loops banned on main thread
+  // during shutdown). |synchronous_done_callback| must be thread-safe.
+  virtual void CommitPendingWrite(
+      base::OnceClosure reply_callback = base::OnceClosure(),
+      base::OnceClosure synchronous_done_callback = base::OnceClosure());
 
   // Schedule a write if there is any lossy data pending. Unlike
   // CommitPendingWrite() this does not immediately sync to disk, instead it
diff --git a/components/prefs/pref_service.cc b/components/prefs/pref_service.cc
index 97e9a69..519221e9 100644
--- a/components/prefs/pref_service.cc
+++ b/components/prefs/pref_service.cc
@@ -97,13 +97,12 @@
   }
 }
 
-void PrefService::CommitPendingWrite() {
-  CommitPendingWrite(base::OnceClosure());
-}
-
-void PrefService::CommitPendingWrite(base::OnceClosure done_callback) {
+void PrefService::CommitPendingWrite(
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  user_pref_store_->CommitPendingWrite(std::move(done_callback));
+  user_pref_store_->CommitPendingWrite(std::move(reply_callback),
+                                       std::move(synchronous_done_callback));
 }
 
 void PrefService::SchedulePendingLossyWrites() {
diff --git a/components/prefs/pref_service.h b/components/prefs/pref_service.h
index 8ced3c9..c6ea3eb4f 100644
--- a/components/prefs/pref_service.h
+++ b/components/prefs/pref_service.h
@@ -176,13 +176,16 @@
   virtual ~PrefService();
 
   // Lands pending writes to disk. This should only be used if we need to save
-  // immediately (basically, during shutdown).
-  void CommitPendingWrite();
-
-  // Lands pending writes to disk. This should only be used if we need to save
-  // immediately. |done_callback| will be invoked when changes have been
-  // written.
-  void CommitPendingWrite(base::OnceClosure done_callback);
+  // immediately (basically, during shutdown). |reply_callback| will be posted
+  // to the current sequence when changes have been written.
+  // |synchronous_done_callback| on the other hand will be invoked right away
+  // wherever the writes complete (could even be invoked synchronously if no
+  // writes need to occur); this is useful when the current thread cannot pump
+  // messages to observe the reply (e.g. nested loops banned on main thread
+  // during shutdown). |synchronous_done_callback| must be thread-safe.
+  void CommitPendingWrite(
+      base::OnceClosure reply_callback = base::OnceClosure(),
+      base::OnceClosure synchronous_done_callback = base::OnceClosure());
 
   // Schedule a write if there is any lossy data pending. Unlike
   // CommitPendingWrite() this does not immediately sync to disk, instead it
diff --git a/components/prefs/pref_service_factory.cc b/components/prefs/pref_service_factory.cc
index 5d52eecd..f30e1e7 100644
--- a/components/prefs/pref_service_factory.cc
+++ b/components/prefs/pref_service_factory.cc
@@ -24,7 +24,7 @@
     const base::FilePath& prefs_file,
     base::SequencedTaskRunner* task_runner) {
   user_prefs_ =
-      base::MakeRefCounted<JsonPrefStore>(prefs_file, task_runner, nullptr);
+      base::MakeRefCounted<JsonPrefStore>(prefs_file, nullptr, task_runner);
 }
 
 std::unique_ptr<PrefService> PrefServiceFactory::Create(
diff --git a/components/prefs/testing_pref_store.cc b/components/prefs/testing_pref_store.cc
index 5dbc56af..94b86eeb 100644
--- a/components/prefs/testing_pref_store.cc
+++ b/components/prefs/testing_pref_store.cc
@@ -98,9 +98,12 @@
     NotifyInitializationCompleted();
 }
 
-void TestingPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
+void TestingPrefStore::CommitPendingWrite(
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
   committed_ = true;
-  PersistentPrefStore::CommitPendingWrite(std::move(done_callback));
+  PersistentPrefStore::CommitPendingWrite(std::move(reply_callback),
+                                          std::move(synchronous_done_callback));
 }
 
 void TestingPrefStore::SchedulePendingLossyWrites() {}
diff --git a/components/prefs/testing_pref_store.h b/components/prefs/testing_pref_store.h
index c011815d..ed67fbc 100644
--- a/components/prefs/testing_pref_store.h
+++ b/components/prefs/testing_pref_store.h
@@ -45,7 +45,8 @@
   PrefReadError GetReadError() const override;
   PersistentPrefStore::PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
-  void CommitPendingWrite(base::OnceClosure done_callback) override;
+  void CommitPendingWrite(base::OnceClosure reply_callback,
+                          base::OnceClosure synchronous_done_callback) override;
   void SchedulePendingLossyWrites() override;
 
   // Marks the store as having completed initialization.
diff --git a/components/storage_monitor/storage_monitor_chromeos_unittest.cc b/components/storage_monitor/storage_monitor_chromeos_unittest.cc
index d816031..05a4224 100644
--- a/components/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/components/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -31,6 +31,7 @@
 
 namespace {
 
+using chromeos::disks::Disk;
 using chromeos::disks::DiskMountManager;
 using testing::_;
 
@@ -549,24 +550,28 @@
 
   // Fixed storage (stateful partition) added.
   const std::string label = "fixed1";
-  const chromeos::disks::Disk disk("", mount_point, false, "", "", label, "",
-                                   "", "", "", "", uuid, "",
-                                   chromeos::DEVICE_TYPE_UNKNOWN, 0, false,
-                                   false, false, false, false, false, "", "");
+
+  std::unique_ptr<const Disk> disk = Disk::Builder()
+                                         .SetMountPath(mount_point)
+                                         .SetDeviceLabel(label)
+                                         .SetFileSystemUUID(uuid)
+                                         .Build();
   monitor_->OnBootDeviceDiskEvent(DiskMountManager::DiskEvent::DISK_ADDED,
-                                  disk);
+                                  *disk);
   std::vector<StorageInfo> disks = monitor_->GetAllAvailableStorages();
   ASSERT_EQ(1U, disks.size());
   EXPECT_EQ(mount_point, disks[0].location());
   EXPECT_EQ(base::ASCIIToUTF16(label), disks[0].storage_label());
 
   // Fixed storage (not stateful partition) added - ignore.
-  const chromeos::disks::Disk ignored_disk(
-      "", "usr/share/OEM", false, "", "", "fixed2", "", "", "", "", "",
-      "fixed2-uuid", "", chromeos::DEVICE_TYPE_UNKNOWN, 0, false, false, false,
-      false, false, false, "", "");
+  std::unique_ptr<const Disk> ignored_disk =
+      Disk::Builder()
+          .SetMountPath("usr/share/OEM")
+          .SetDeviceLabel("fixed2")
+          .SetFileSystemUUID("fixed2-uuid")
+          .Build();
   monitor_->OnBootDeviceDiskEvent(DiskMountManager::DiskEvent::DISK_ADDED,
-                                  ignored_disk);
+                                  *ignored_disk);
   disks = monitor_->GetAllAvailableStorages();
   ASSERT_EQ(1U, disks.size());
   EXPECT_EQ(mount_point, disks[0].location());
@@ -574,7 +579,7 @@
 
   // Fixed storage (stateful partition) removed.
   monitor_->OnBootDeviceDiskEvent(DiskMountManager::DiskEvent::DISK_REMOVED,
-                                  disk);
+                                  *disk);
   disks = monitor_->GetAllAvailableStorages();
   EXPECT_EQ(0U, disks.size());
 }
diff --git a/components/strings/components_strings_bn.xtb b/components/strings/components_strings_bn.xtb
index d3180dc..52184e72 100644
--- a/components/strings/components_strings_bn.xtb
+++ b/components/strings/components_strings_bn.xtb
@@ -490,6 +490,7 @@
 <translation id="4277028893293644418">পাসওয়ার্ড রিসেট করুন</translation>
 <translation id="4280429058323657511">, মেয়াদ শেষ <ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="4305817255990598646">পাল্টান</translation>
+<translation id="4308131620840579419">আপনার সমস্ত কার্ড এক জায়গায় সেভ করবেন?</translation>
 <translation id="4312866146174492540">অবরুদ্ধ করুন (ডিফল্ট)</translation>
 <translation id="4325863107915753736">নিবন্ধ খুঁজে পেতে ব্যর্থ হয়েছে</translation>
 <translation id="4326324639298822553">আপনার মেয়াদ শেষের তারিখ পরীক্ষা করে আবার চেষ্টা করুন</translation>
@@ -600,6 +601,7 @@
 <translation id="5190835502935405962">বুকমার্ক দণ্ড</translation>
 <translation id="5201306358585911203">এই পৃষ্ঠার এম্বেডেড করা একটি পৃষ্ঠায় এটি দেখানো হচ্ছে</translation>
 <translation id="5205222826937269299">নাম প্রয়োজন</translation>
+<translation id="5215116848420601511">Google Pay ব্যবহার করে এমন পেমেন্টের পদ্ধতি এবং ঠিকানা</translation>
 <translation id="5222812217790122047">ইমেল প্রয়োজন</translation>
 <translation id="5230733896359313003">শিপিংয়ের ঠিকানা</translation>
 <translation id="5250209940322997802">"নেটওয়ার্কে কানেক্ট করুন"</translation>
@@ -676,6 +678,7 @@
 <translation id="5689199277474810259">JSON এ রপ্তানি করুন</translation>
 <translation id="5689516760719285838">লোকেশন</translation>
 <translation id="570530837424789914">পরিচালনা করুন...</translation>
+<translation id="5705882733397021510">ফিরে যান</translation>
 <translation id="57094364128775171">শক্তিশালী পাসওয়ার্ড সাজেস্ট করুন…</translation>
 <translation id="5710435578057952990">এই ওয়েবসাইটির পরিচয় যাচাই করা হয় নি৷</translation>
 <translation id="5719499550583120431">প্রিপেড কার্ড গ্রহণ করা হয়।</translation>
@@ -693,6 +696,7 @@
 <translation id="5810442152076338065"><ph name="DOMAIN" />-এ আপনার সংযোগ একটি অপ্রচলিত সাইফার স্যুট ব্যবহার করে এনক্রিপ্ট করা হয়েছে৷</translation>
 <translation id="5813119285467412249">&amp;যোগ করাকে পুনরায় করুন</translation>
 <translation id="5838278095973806738">এই সাইটে আপনার কোনো সংবেদনশীল তথ্য দেওয়া উচিত হবে না (উদাহরণস্বরূপ, পাসওয়ার্ড বা ক্রেডিট কার্ড) কারণ আক্রমণকারীরা এগুলি চুরি করতে পারে।</translation>
+<translation id="5863847714970149516">পরের পৃষ্ঠাতে আপনাকে চার্জ করা হতে পারে</translation>
 <translation id="5866257070973731571">ফোন নম্বর যোগ করুন</translation>
 <translation id="5869405914158311789">এই সাইটটিতে পৌছানো যাচ্ছে না</translation>
 <translation id="5869522115854928033">সংরক্ষিত পাসওয়ার্ড</translation>
@@ -822,6 +826,7 @@
 <translation id="6973656660372572881">স্থির প্রক্সি সার্ভার এবং .pac স্ক্রিপ্ট URL-এর উভয়ই নির্দিষ্ট আছে৷</translation>
 <translation id="6989763994942163495">উন্নত সেটিংস দেখান ...</translation>
 <translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7016992613359344582">এই চার্জটি একবার করা হতে পারে অথবা বারবার করা হতে পারে এবং স্পষ্টভাবে তথ্য নাও থাকতে পারে।</translation>
 <translation id="7029809446516969842">পাসওয়ার্ড</translation>
 <translation id="7050187094878475250">আমি <ph name="DOMAIN" />-এ সংযোগ করার চেষ্টা করেছেন, কিন্তু সার্ভার একটি শংসাপত্র উপস্থাপন করেছে যার বৈধতার সময়সীমা এত বেশী যে বিশ্বাসযোগ্য নয়।</translation>
 <translation id="7053983685419859001">ব্লক করুন</translation>
@@ -1086,6 +1091,7 @@
 <translation id="8957210676456822347">ক্যাপটিভ পোর্টাল অনুমোদন</translation>
 <translation id="8971063699422889582">সার্ভারের শংসাপত্রের মেয়াদ ফুরিয়েছে৷</translation>
 <translation id="8978053250194585037">Google Safe Browsing সম্প্রতি <ph name="SITE" /> এ <ph name="BEGIN_LINK" />ফিশিং শনাক্ত করেছে<ph name="END_LINK" />। ফিশিং সাইটগুলি আপনাকে প্রতারিত করার জন্য অন্যান্য সাইট যেমন হয় সেইরকম ভান করে।</translation>
+<translation id="8983003182662520383">Google Pay ব্যবহার করে এমন পেমেন্টের পদ্ধতি এবং ঠিকানা</translation>
 <translation id="8987927404178983737">মাস</translation>
 <translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
 <translation id="8996941253935762404">সামনের সাইটটিতে ক্ষতিকর প্রোগ্রামগুলি রয়েছে</translation>
diff --git a/components/strings/components_strings_es-419.xtb b/components/strings/components_strings_es-419.xtb
index 11390786..36f7768 100644
--- a/components/strings/components_strings_es-419.xtb
+++ b/components/strings/components_strings_es-419.xtb
@@ -490,6 +490,7 @@
 <translation id="4277028893293644418">Restablecer contraseña</translation>
 <translation id="4280429058323657511">, exp <ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="4305817255990598646">Cambiar</translation>
+<translation id="4308131620840579419">¿Quieres guardar todas las tarjetas en un solo lugar?</translation>
 <translation id="4312866146174492540">Bloquear (predeterminado)</translation>
 <translation id="4325863107915753736">No se pudo encontrar el artículo</translation>
 <translation id="4326324639298822553">Comprueba la fecha de vencimiento y vuelve a intentarlo</translation>
@@ -600,6 +601,7 @@
 <translation id="5190835502935405962">Barra de favoritos</translation>
 <translation id="5201306358585911203">Una página incorporada en esta página dice</translation>
 <translation id="5205222826937269299">Nombre (obligatorio)</translation>
+<translation id="5215116848420601511">Formas de pago y direcciones con Google Pay</translation>
 <translation id="5222812217790122047">Correo electrónico (obligatorio)</translation>
 <translation id="5230733896359313003">Dirección de envío</translation>
 <translation id="5250209940322997802">"Conectarse a una red"</translation>
@@ -676,6 +678,7 @@
 <translation id="5689199277474810259">Exportar a JSON</translation>
 <translation id="5689516760719285838">Ubicación</translation>
 <translation id="570530837424789914">Administrar…</translation>
+<translation id="5705882733397021510">Volver</translation>
 <translation id="57094364128775171">Sugerir contraseña segura…</translation>
 <translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
 <translation id="5719499550583120431">Se aceptan tarjetas de prepago.</translation>
@@ -693,6 +696,7 @@
 <translation id="5810442152076338065">Tu conexión a <ph name="DOMAIN" /> está encriptada con un conjunto de cifrado obsoleto.</translation>
 <translation id="5813119285467412249">&amp;Rehacer Agregar</translation>
 <translation id="5838278095973806738">No debes ingresar información confidencial en este sitio (p. ej., contraseñas o tarjetas de crédito), ya que los atacantes podrían robarla.</translation>
+<translation id="5863847714970149516">Es posible que la página siguiente intente cobrarte dinero</translation>
 <translation id="5866257070973731571">Agregar número de teléfono</translation>
 <translation id="5869405914158311789">No se puede acceder a este sitio</translation>
 <translation id="5869522115854928033">Contraseñas almacenadas</translation>
@@ -823,6 +827,7 @@
 <translation id="6973656660372572881">Se especifican servidores proxy fijos y URL de secuencias de comandos .pac.</translation>
 <translation id="6989763994942163495">Mostrar configuración avanzada...</translation>
 <translation id="7012363358306927923">China UnionPay</translation>
+<translation id="7016992613359344582">Estos cargos pueden ser únicos o recurrentes, y es posible que no sean evidentes.</translation>
 <translation id="7029809446516969842">Contraseñas</translation>
 <translation id="7050187094878475250">Intentaste acceder a <ph name="DOMAIN" />, pero el certificado de servidor tenía un período de validez demasiado extenso para ser fiable.</translation>
 <translation id="7053983685419859001">Bloquear</translation>
@@ -1088,6 +1093,7 @@
 <translation id="8957210676456822347">Autorización de portal cautivo</translation>
 <translation id="8971063699422889582">El certificado del servidor ha caducado.</translation>
 <translation id="8978053250194585037">Recientemente, la navegación segura de Google <ph name="BEGIN_LINK" />detectó un intento de suplantación de identidad (phishing)<ph name="END_LINK" /> en <ph name="SITE" />. Los sitios de suplantación de identidad imitan a otros sitios web para engañarte.</translation>
+<translation id="8983003182662520383">Formas de pago y direcciones con Google Pay</translation>
 <translation id="8987927404178983737">Mes</translation>
 <translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
 <translation id="8996941253935762404">El siguiente sitio contiene programas peligrosos</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index b1c9028..7095e29 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -489,6 +489,7 @@
 <translation id="4277028893293644418">పాస్‌వర్డ్‌ను రీసెట్ చేయి</translation>
 <translation id="4280429058323657511">, గడువు ముగింపు <ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="4305817255990598646">స్విచ్</translation>
+<translation id="4308131620840579419">మీ అన్ని కార్డ్‌లను ఒకే చోట సేవ్ చేయమంటారా?</translation>
 <translation id="4312866146174492540">బ్లాక్ చేయి (డిఫాల్ట్)</translation>
 <translation id="4325863107915753736">కథనాన్ని కనుగొనడం విఫలమైంది</translation>
 <translation id="4326324639298822553">మీ గడువు ముగింపు తేదీని తనిఖీ చేసి, ఆపై మళ్లీ ప్రయత్నించండి</translation>
@@ -599,6 +600,7 @@
 <translation id="5190835502935405962">బుక్‌మార్క్‌ల బార్</translation>
 <translation id="5201306358585911203">ఈ పేజీలోని పొందుపరిచిన పేజీ ఇలా చెబుతోంది</translation>
 <translation id="5205222826937269299">పేరు ఆవశ్యకం</translation>
+<translation id="5215116848420601511">Google Payని ఉపయోగిస్తున్న చెల్లింపు పద్ధతులు మరియు చిరునామాలు</translation>
 <translation id="5222812217790122047">ఇమెయిల్ ఆవశ్యకం</translation>
 <translation id="5230733896359313003">బట్వాడా చిరునామా</translation>
 <translation id="5250209940322997802">"నెట్‌వర్క్‌కు కనెక్ట్ చేయండి"</translation>
@@ -675,6 +677,7 @@
 <translation id="5689199277474810259">JSONకు ఎగుమతి చేయి</translation>
 <translation id="5689516760719285838">స్థానం</translation>
 <translation id="570530837424789914">నిర్వహించండి...</translation>
+<translation id="5705882733397021510">వెనుకకు వెళ్లు</translation>
 <translation id="57094364128775171">బలమైన పాస్‌వర్డ్‌ను సూచించండి…</translation>
 <translation id="5710435578057952990">ఈ వెబ్‍‌సైట్ యొక్క గుర్తింపు నిర్థారించబడలేదు.</translation>
 <translation id="5719499550583120431">ప్రీపెయిడ్ కార్డ్‌లు ఆమోదించబడతాయి.</translation>
@@ -692,6 +695,7 @@
 <translation id="5810442152076338065"><ph name="DOMAIN" />కి గల మీ కనెక్షన్ వాడుకలో లేని సైఫర్ సూట్ ఉపయోగించి గుప్తీకరించబడింది.</translation>
 <translation id="5813119285467412249">&amp;జోడించడాన్ని పునరావృతం చేయి</translation>
 <translation id="5838278095973806738">మీరు ఈ సైట్‌లో ఎలాంటి గోప్యమైన సమాచారాన్ని నమోదు చేయకూడదు (ఉదాహరణకు, పాస్‌వర్డ్‌లు లేదా క్రెడిట్ కార్డ్‌లు), దాడికి పాల్పడేవారు ఆ సమాచారం దొంగిలించే అవకాశం ఉంటుంది.</translation>
+<translation id="5863847714970149516">మీరు చూడబోతున్న పేజీ మీకు డబ్బులు ఛార్జ్ చేయడానికి ప్రయత్నించవచ్చు</translation>
 <translation id="5866257070973731571">ఫోన్ నంబర్‌ను జోడించండి</translation>
 <translation id="5869405914158311789">ఈ సైట్‌ను చేరుకోలేకపోయాము</translation>
 <translation id="5869522115854928033">సేవ్  చేసిన పాస్‌వర్డ్‌లు</translation>
@@ -822,6 +826,7 @@
 <translation id="6973656660372572881">రెండు స్థిర ప్రాక్సీ సర్వర్లు మరియు ఒక .pac స్క్రిప్ట్ URL పేర్కొనబడ్డాయి.</translation>
 <translation id="6989763994942163495">అధునాతన సెట్టింగ్‌లను చూపించు...</translation>
 <translation id="7012363358306927923">చైనా యూనియన్ పే</translation>
+<translation id="7016992613359344582">ఈ ఛార్జ్‌లు ఒకే సారి చెల్లించేవి లేదా పునరావృతంగా చెల్లించాల్సినవి కావచ్చు మరియు స్పష్టంగా పేర్కొనబడకపోవచ్చు.</translation>
 <translation id="7029809446516969842">పాస్‌వర్డ్‌లు</translation>
 <translation id="7050187094878475250">మీరు <ph name="DOMAIN" />ని చేరుకోవడానికి ప్రయత్నించారు, కానీ సర్వర్ అందించిన ప్రమాణపత్రం విశ్వసించలేనంత ఎక్కువ చెల్లుబాటు వ్యవధిని కలిగి ఉంది.</translation>
 <translation id="7053983685419859001">నిరోధించు</translation>
@@ -1087,6 +1092,7 @@
 <translation id="8957210676456822347">క్యాప్టివ్ పోర్టల్ ప్రామాణీకరణ</translation>
 <translation id="8971063699422889582">సర్వర్ యొక్క ప్రమాణపత్రం గడువు ముగిసింది.</translation>
 <translation id="8978053250194585037">Google సురక్షిత బ్రౌజింగ్ ఇటీవల <ph name="SITE" />లో <ph name="BEGIN_LINK" />ఫిషింగ్‌ని గుర్తించింది<ph name="END_LINK" />. ఫిషింగ్ సైట్‌లు వేరే వెబ్‌సైట్‌ల వలె ప్రవర్తించడం ద్వారా మిమ్మల్ని మాయ చేయవచ్చు.</translation>
+<translation id="8983003182662520383">Google Payని ఉపయోగిస్తున్న చెల్లింపు పద్ధతులు మరియు చిరునామాలు</translation>
 <translation id="8987927404178983737">నెల</translation>
 <translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
 <translation id="8996941253935762404">ఈ సైట్ హానికర ప్రోగ్రామ్‌లను కలిగి ఉంది</translation>
diff --git a/components/strings/components_strings_zh-CN.xtb b/components/strings/components_strings_zh-CN.xtb
index ea7daf0..d2c5f01 100644
--- a/components/strings/components_strings_zh-CN.xtb
+++ b/components/strings/components_strings_zh-CN.xtb
@@ -486,6 +486,7 @@
 <translation id="4277028893293644418">重置密码</translation>
 <translation id="4280429058323657511">,到期日期:<ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="4305817255990598646">切换</translation>
+<translation id="4308131620840579419">想集中保存您的所有卡片吗?</translation>
 <translation id="4312866146174492540">屏蔽(默认)</translation>
 <translation id="4325863107915753736">找不到文章</translation>
 <translation id="4326324639298822553">请检查您的信用卡到期日期,然后重试</translation>
@@ -596,6 +597,7 @@
 <translation id="5190835502935405962">书签栏</translation>
 <translation id="5201306358585911203">此网页上的嵌入式页面显示</translation>
 <translation id="5205222826937269299">需要提供名称</translation>
+<translation id="5215116848420601511">Google Pay 中存储的付款方式和地址信息</translation>
 <translation id="5222812217790122047">需要提供电子邮件地址</translation>
 <translation id="5230733896359313003">送货地址</translation>
 <translation id="5250209940322997802">“连接到网络”</translation>
@@ -672,6 +674,7 @@
 <translation id="5689199277474810259">导出为 JSON 格式</translation>
 <translation id="5689516760719285838">位置</translation>
 <translation id="570530837424789914">管理…</translation>
+<translation id="5705882733397021510">返回</translation>
 <translation id="57094364128775171">建议安全系数高的密码…</translation>
 <translation id="5710435578057952990">此网站尚未经过身份验证。</translation>
 <translation id="5719499550583120431">接受预付卡。</translation>
@@ -689,6 +692,7 @@
 <translation id="5810442152076338065">您与 <ph name="DOMAIN" /> 之间的连接采用过时的加密套件进行了加密。</translation>
 <translation id="5813119285467412249">恢复添加(&amp;R)</translation>
 <translation id="5838278095973806738">请勿在此网站上输入任何敏感信息(例如密码或信用卡信息),因为攻击者可能会盗取这些信息。</translation>
+<translation id="5863847714970149516">进入接下来的页面后,系统可能会向您收取费用</translation>
 <translation id="5866257070973731571">添加电话号码</translation>
 <translation id="5869405914158311789">无法访问此网站</translation>
 <translation id="5869522115854928033">已保存的密码</translation>
@@ -818,6 +822,7 @@
 <translation id="6973656660372572881">固定代理服务器和 .pac 脚本网址均已指定。</translation>
 <translation id="6989763994942163495">显示高级设置...</translation>
 <translation id="7012363358306927923">中国银联</translation>
+<translation id="7016992613359344582">这些费用可能只收取一次,也可能会周期性收取,而且可能不易察觉。</translation>
 <translation id="7029809446516969842">密码</translation>
 <translation id="7050187094878475250">您尝试访问 <ph name="DOMAIN" />,但服务器提供的证书不可信(有效期过长)。</translation>
 <translation id="7053983685419859001">禁止</translation>
@@ -1083,6 +1088,7 @@
 <translation id="8957210676456822347">强制门户授权</translation>
 <translation id="8971063699422889582">服务器的证书已过期。</translation>
 <translation id="8978053250194585037">Google 安全浏览功能最近在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />检测到网上诱骗行为<ph name="END_LINK" />。网上诱骗网站会假冒其他网站来欺骗您。</translation>
+<translation id="8983003182662520383">Google Pay 中存储的付款方式和地址信息</translation>
 <translation id="8987927404178983737">月</translation>
 <translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
 <translation id="8996941253935762404">您要访问的网站包含有害程序</translation>
diff --git a/components/task_scheduler_util/OWNERS b/components/task_scheduler_util/OWNERS
index ffc802c1..495a17c 100644
--- a/components/task_scheduler_util/OWNERS
+++ b/components/task_scheduler_util/OWNERS
@@ -1 +1 @@
-file://base/task_scheduler/OWNERS
+file://base/task/task_scheduler/OWNERS
diff --git a/components/viz/common/gl_helper_unittest.cc b/components/viz/common/gl_helper_unittest.cc
index 2b3ee2a3..5395980 100644
--- a/components/viz/common/gl_helper_unittest.cc
+++ b/components/viz/common/gl_helper_unittest.cc
@@ -1313,7 +1313,8 @@
   }
 }
 
-TEST_P(GLHelperPixelReadbackTest, ScalePatching) {
+// FLAKY: https://crbug.com/871799
+TEST_P(GLHelperPixelReadbackTest, DISABLED_ScalePatching) {
   for (int flipped_source = 0; flipped_source <= 1; ++flipped_source) {
     for (int pattern = 0; pattern < 3; ++pattern) {
       TestScalePatching(
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc
index f97496e..f155aa6 100644
--- a/components/viz/service/display/display_scheduler.cc
+++ b/components/viz/service/display/display_scheduler.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/auto_reset.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
 #include "components/viz/common/surfaces/surface_info.h"
@@ -291,7 +292,7 @@
   }
 }
 
-bool DisplayScheduler::ShouldDraw() {
+bool DisplayScheduler::ShouldDraw() const {
   // Note: When any of these cases becomes true, MaybeStartObservingBeginFrames
   // must be called to ensure the draw will happen.
   return needs_draw_ && !output_surface_lost_ && visible_ &&
@@ -483,6 +484,7 @@
     if (pending_swaps_ < max_pending_swaps_)
       return DrawAndSwap();
   } else {
+    ReportNotDrawReason();
     // We are going idle, so reset expectations.
     // TODO(eseckler): Should we avoid going idle if
     // |expecting_root_surface_damage_because_of_resize_| is true?
@@ -522,4 +524,15 @@
   ScheduleBeginFrameDeadline();
 }
 
+void DisplayScheduler::ReportNotDrawReason() {
+  DCHECK(!ShouldDraw());
+  UMA_HISTOGRAM_BOOLEAN("DisplayScheduler.ShouldNotDraw.DrawNotNeeded",
+                        !needs_draw_);
+  UMA_HISTOGRAM_BOOLEAN("DisplayScheduler.ShouldNotDraw.OutputSurfaceLost",
+                        output_surface_lost_);
+  UMA_HISTOGRAM_BOOLEAN("DisplayScheduler.ShouldNotDraw.NotVisible", !visible_);
+  UMA_HISTOGRAM_BOOLEAN("DisplayScheduler.ShouldNotDraw.RootFrameMissing",
+                        root_frame_missing_);
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/display_scheduler.h b/components/viz/service/display/display_scheduler.h
index c88ab358..e2609c8 100644
--- a/components/viz/service/display/display_scheduler.h
+++ b/components/viz/service/display/display_scheduler.h
@@ -123,10 +123,11 @@
   void MaybeStartObservingBeginFrames();
   void StartObservingBeginFrames();
   void StopObservingBeginFrames();
-  bool ShouldDraw();
+  bool ShouldDraw() const;
   void DidFinishFrame(bool did_draw);
   // Updates |has_pending_surfaces_| and returns whether its value changed.
   bool UpdateHasPendingSurfaces();
+  void ReportNotDrawReason();
 
   DisplaySchedulerClient* client_;
   BeginFrameSource* begin_frame_source_;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index f9633cf..66ce09d1 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -17,6 +17,7 @@
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
 #include "gpu/command_buffer/service/scheduler.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_gl_api_implementation.h"
@@ -324,18 +325,8 @@
         *metadata.backend_format.getGLTarget());
   } else {
 #if BUILDFLAG(ENABLE_VULKAN)
-    VkFormat format = VK_FORMAT_UNDEFINED;
-    switch (metadata.color_type) {
-      case kRGBA_8888_SkColorType:
-        format = VK_FORMAT_R8G8B8A8_UNORM;
-        break;
-      case kBGRA_8888_SkColorType:
-        format = VK_FORMAT_B8G8R8A8_UNORM;
-        break;
-      default:
-        NOTREACHED();
-    }
-    metadata.backend_format = GrBackendFormat::MakeVk(format);
+    metadata.backend_format = GrBackendFormat::MakeVk(
+        gfx::SkColorTypeToVkFormat(metadata.color_type));
 #else
     NOTREACHED();
 #endif
@@ -414,7 +405,7 @@
   SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
   int msaa_sample_count = 0;
   SkColorType color_type =
-      ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format);
+      ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
   SkImageInfo image_info =
       SkImageInfo::Make(surface_size.width(), surface_size.height(), color_type,
                         kPremul_SkAlphaType, nullptr /* color_space */);
@@ -431,7 +422,8 @@
         GL_TEXTURE_2D);
   } else {
 #if BUILDFLAG(ENABLE_VULKAN)
-    backend_format = GrBackendFormat::MakeVk(VK_FORMAT_B8G8R8A8_UNORM);
+    backend_format =
+        GrBackendFormat::MakeVk(gfx::SkColorTypeToVkFormat(color_type));
 #else
     NOTREACHED();
 #endif
@@ -479,7 +471,8 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(recorder_);
 
-  SkColorType color_type = kBGRA_8888_SkColorType;
+  SkColorType color_type =
+      ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
   GrBackendFormat backend_format;
 
   if (!gpu_service_->is_using_vulkan()) {
@@ -489,11 +482,10 @@
     backend_format = GrBackendFormat::MakeGL(
         gl::GetInternalFormat(version_info, texture_storage_format),
         GL_TEXTURE_2D);
-    color_type =
-        ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format);
   } else {
 #if BUILDFLAG(ENABLE_VULKAN)
-    backend_format = GrBackendFormat::MakeVk(VK_FORMAT_B8G8R8A8_UNORM);
+    backend_format =
+        GrBackendFormat::MakeVk(gfx::SkColorTypeToVkFormat(color_type));
 #else
     NOTREACHED();
 #endif
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc
index 5c30c26..b991c8e3 100644
--- a/components/webdata_services/web_data_service_wrapper.cc
+++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -176,6 +176,9 @@
   profile_autofill_web_data_->GetAutofillBackend(base::Bind(
       &InitSyncableProfileServicesOnDBSequence, db_task_runner, flare,
       profile_autofill_web_data_, context_path, application_locale));
+  profile_autofill_web_data_->GetAutofillBackend(base::Bind(
+      &InitSyncableAccountServicesOnDBSequence, db_task_runner, flare,
+      profile_autofill_web_data_, context_path, application_locale));
 
   if (base::FeatureList::IsEnabled(
           autofill::features::kAutofillEnableAccountWalletStorage)) {
@@ -192,12 +195,6 @@
     account_autofill_web_data_->GetAutofillBackend(base::Bind(
         &InitSyncableAccountServicesOnDBSequence, db_task_runner, flare,
         account_autofill_web_data_, context_path, application_locale));
-
-  } else {
-    account_autofill_web_data_ = nullptr;
-    profile_autofill_web_data_->GetAutofillBackend(base::Bind(
-        &InitSyncableAccountServicesOnDBSequence, db_task_runner, flare,
-        profile_autofill_web_data_, context_path, application_locale));
   }
 }
 
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 7d1f767d..58e5e03 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -43,6 +43,7 @@
 #include "content/app/mojo/mojo_init.h"
 #include "content/browser/browser_process_sub_thread.h"
 #include "content/browser/startup_data_impl.h"
+#include "content/common/content_constants_internal.h"
 #include "content/common/url_schemes.h"
 #include "content/public/app/content_main_delegate.h"
 #include "content/public/common/content_constants.h"
@@ -73,8 +74,8 @@
 #include "base/trace_event/trace_event_etw_export_win.h"
 #include "ui/display/win/dpi.h"
 #elif defined(OS_MACOSX)
+#include "base/mac/mach_port_broker.h"
 #include "base/power_monitor/power_monitor_device_source.h"
-#include "content/browser/mach_broker_mac.h"
 #include "sandbox/mac/seatbelt_exec.h"
 #endif  // OS_WIN
 
@@ -718,7 +719,7 @@
     }
 
     if (!process_type.empty() && delegate_->ShouldSendMachPort(process_type)) {
-      MachBroker::ChildSendTaskPortToParent();
+      base::MachPortBroker::ChildSendTaskPortToParent(kMachBootstrapName);
     }
 #endif
 
diff --git a/content/app/strings/translations/content_strings_iw.xtb b/content/app/strings/translations/content_strings_iw.xtb
index c13b61d..e0a2ae5 100644
--- a/content/app/strings/translations/content_strings_iw.xtb
+++ b/content/app/strings/translations/content_strings_iw.xtb
@@ -44,7 +44,7 @@
 <translation id="2311842470354187719">מעבר דף</translation>
 <translation id="2335594187091864976">בוחר תאריך ושעה</translation>
 <translation id="248395913932153421">יום</translation>
-<translation id="2507943997699731163">מלא שדה זה.</translation>
+<translation id="2507943997699731163">זהו שדה חובה.</translation>
 <translation id="2508569020611168319">רשימת כרטיסיות</translation>
 <translation id="2561842179657104141">הצג עוד פקדי מדיה</translation>
 <translation id="2572483411312390101">הפעל</translation>
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 440979ab..62a0273c 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -874,10 +874,13 @@
     "geolocation/geolocation_service_impl.h",
     "gpu/browser_gpu_channel_host_factory.cc",
     "gpu/browser_gpu_channel_host_factory.h",
+    "gpu/browser_gpu_client_delegate.cc",
+    "gpu/browser_gpu_client_delegate.h",
     "gpu/browser_gpu_memory_buffer_manager.cc",
     "gpu/browser_gpu_memory_buffer_manager.h",
     "gpu/compositor_util.cc",
     "gpu/compositor_util.h",
+    "gpu/gpu_client_delegate.h",
     "gpu/gpu_client_impl.cc",
     "gpu/gpu_client_impl.h",
     "gpu/gpu_data_manager_impl.cc",
@@ -983,6 +986,10 @@
     "indexed_db/leveldb/leveldb_write_batch.cc",
     "indexed_db/leveldb/leveldb_write_batch.h",
     "indexed_db/list_set.h",
+    "indexed_db/scopes/disjoint_range_lock_manager.cc",
+    "indexed_db/scopes/disjoint_range_lock_manager.h",
+    "indexed_db/scopes/scopes_lock_manager.cc",
+    "indexed_db/scopes/scopes_lock_manager.h",
     "initiator_csp_context.cc",
     "initiator_csp_context.h",
     "installedapp/installed_app_provider_impl_default.cc",
@@ -2091,7 +2098,10 @@
 
   if (use_x11) {
     configs += [ "//build/config/linux:x11" ]
-    deps += [ "//ui/gfx/x" ]
+    deps += [
+      "//ui/events/platform/x11",
+      "//ui/gfx/x",
+    ]
   }
 
   if (use_pangocairo) {
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index f0281d08..c698fe8 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -127,7 +127,7 @@
     if (fetch_request.mode == network::mojom::FetchRequestMode::kCORS ||
         fetch_request.mode ==
             network::mojom::FetchRequestMode::kCORSWithForcedPreflight ||
-        (fetch_request.method != "GET" && fetch_request.method != "POST")) {
+        (fetch_request.method != "GET" && fetch_request.method != "HEAD")) {
       headers.SetHeader("Origin", origin.Serialize());
     }
 
diff --git a/content/browser/background_fetch/storage/database_task.cc b/content/browser/background_fetch/storage/database_task.cc
index 62a5a758..77d9f4e 100644
--- a/content/browser/background_fetch/storage/database_task.cc
+++ b/content/browser/background_fetch/storage/database_task.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/metrics/histogram_functions.h"
 #include "content/browser/background_fetch/background_fetch_data_manager.h"
 #include "content/browser/background_fetch/background_fetch_data_manager_observer.h"
 #include "content/browser/background_fetch/storage/database_helpers.h"
@@ -61,6 +62,42 @@
     observer.OnServiceWorkerDatabaseCorrupted(service_worker_registration_id);
 }
 
+void DatabaseTask::SetStorageError(BackgroundFetchStorageError error) {
+  DCHECK_NE(BackgroundFetchStorageError::kNone, error);
+  switch (storage_error_) {
+    case BackgroundFetchStorageError::kNone:
+      storage_error_ = error;
+      break;
+    case BackgroundFetchStorageError::kServiceWorkerStorageError:
+    case BackgroundFetchStorageError::kCacheStorageError:
+      DCHECK(error == BackgroundFetchStorageError::kServiceWorkerStorageError ||
+             error == BackgroundFetchStorageError::kCacheStorageError);
+      if (storage_error_ != error)
+        storage_error_ = BackgroundFetchStorageError::kStorageError;
+      break;
+    case BackgroundFetchStorageError::kStorageError:
+      break;
+  }
+}
+
+void DatabaseTask::SetStorageErrorAndFinish(BackgroundFetchStorageError error) {
+  SetStorageError(error);
+  FinishWithError(blink::mojom::BackgroundFetchError::STORAGE_ERROR);
+}
+
+void DatabaseTask::ReportStorageError() {
+  if (host_ != data_manager())
+    return;  // This is a SubTask.
+
+  base::UmaHistogramEnumeration("BackgroundFetch.Storage." + HistogramName(),
+                                storage_error_);
+}
+
+std::string DatabaseTask::HistogramName() const {
+  NOTREACHED() << "HistogramName needs to be provided.";
+  return "GeneralDatabaseTask";
+}
+
 ServiceWorkerContextWrapper* DatabaseTask::service_worker_context() {
   DCHECK(data_manager()->service_worker_context());
   return data_manager()->service_worker_context();
diff --git a/content/browser/background_fetch/storage/database_task.h b/content/browser/background_fetch/storage/database_task.h
index 3d5742c..62d32979 100644
--- a/content/browser/background_fetch/storage/database_task.h
+++ b/content/browser/background_fetch/storage/database_task.h
@@ -67,6 +67,15 @@
   virtual void Start() = 0;
 
  protected:
+  // This enum is append-only since it is used by UMA.
+  enum class BackgroundFetchStorageError {
+    kNone,
+    kServiceWorkerStorageError,
+    kCacheStorageError,
+    kStorageError,
+    kMaxValue = kStorageError
+  };
+
   explicit DatabaseTask(DatabaseTaskHost* host);
 
   // Each task MUST call this once finished, even if exceptions occur, to
@@ -80,25 +89,31 @@
   // Abandon all fetches for a given service worker.
   void AbandonFetches(int64_t service_worker_registration_id);
 
+  // Getters.
   ServiceWorkerContextWrapper* service_worker_context();
-
   CacheStorageManager* cache_manager();
-
   std::set<std::string>& ref_counted_unique_ids();
-
   ChromeBlobStorageContext* blob_storage_context();
 
   // DatabaseTaskHost implementation.
   void OnTaskFinished(DatabaseTask* finished_subtask) override;
   BackgroundFetchDataManager* data_manager() override;
 
+  // UMA reporting.
+  void SetStorageError(BackgroundFetchStorageError error);
+  void SetStorageErrorAndFinish(BackgroundFetchStorageError error);
+  void ReportStorageError();
+
  private:
   // Each task must override this function and perform the following steps:
-  // 1) Report error (UMA) if applicable.
+  // 1) Report storage error (UMA) if applicable.
   // 2) Run the provided callback.
   // 3) Call Finished().
   virtual void FinishWithError(blink::mojom::BackgroundFetchError error) = 0;
 
+  // The Histogram name to report with the Error.
+  virtual std::string HistogramName() const;
+
   DatabaseTaskHost* host_;
 
   // Owns a reference to the CacheStorageManager in case Shutdown was
@@ -108,6 +123,10 @@
   // Map the raw pointer to its unique_ptr, to make lookups easier.
   std::map<DatabaseTask*, std::unique_ptr<DatabaseTask>> active_subtasks_;
 
+  // The storage error to report.
+  BackgroundFetchStorageError storage_error_ =
+      BackgroundFetchStorageError::kNone;
+
   DISALLOW_COPY_AND_ASSIGN(DatabaseTask);
 };
 
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index aea8bf88..51c63a9 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -642,8 +642,7 @@
   // Up the priority of the UI thread unless it was already high (since recent
   // versions of Android (O+) do this automatically).
   if (base::PlatformThread::GetCurrentThreadPriority() <
-          base::ThreadPriority::DISPLAY ||
-      base::FeatureList::IsEnabled(features::kOverrideUIThreadPriority)) {
+      base::ThreadPriority::DISPLAY) {
     base::PlatformThread::SetCurrentThreadPriority(
         base::ThreadPriority::DISPLAY);
   }
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc
index 8d4b1bf1..bd13825 100644
--- a/content/browser/child_process_launcher_helper_mac.cc
+++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -22,6 +22,7 @@
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "sandbox/mac/seatbelt_exec.h"
 #include "services/service_manager/embedder/result_codes.h"
+#include "services/service_manager/sandbox/mac/audio.sb.h"
 #include "services/service_manager/sandbox/mac/cdm.sb.h"
 #include "services/service_manager/sandbox/mac/common_v2.sb.h"
 #include "services/service_manager/sandbox/mac/gpu_v2.sb.h"
@@ -73,7 +74,8 @@
       service_manager::IsUnsandboxedSandboxType(sandbox_type);
 
   // TODO(kerrnel): Delete this switch once the V2 sandbox is always enabled.
-  bool v2_process = false;
+  bool use_v2 = base::FeatureList::IsEnabled(features::kMacV2Sandbox);
+
   switch (sandbox_type) {
     case service_manager::SANDBOX_TYPE_NO_SANDBOX:
       break;
@@ -84,18 +86,22 @@
     case service_manager::SANDBOX_TYPE_NACL_LOADER:
     case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR:
     case service_manager::SANDBOX_TYPE_PROFILING:
-      v2_process = true;
+      // If the feature experiment is enabled and this process type supports
+      // the v2 sandbox, use it.
+      use_v2 &= true;
+      break;
+    case service_manager::SANDBOX_TYPE_AUDIO:
+      // The audio service only exists with the v2 sandbox.
+      use_v2 |= true;
       break;
     default:
       // This is a 'break' because the V2 sandbox is not enabled for all
       // processes yet, and so there are sandbox types like NETWORK that
       // should not be run under the V2 sandbox.
+      use_v2 = false;
       break;
   }
 
-  bool use_v2 =
-      v2_process && base::FeatureList::IsEnabled(features::kMacV2Sandbox);
-
   if (use_v2 && !no_sandbox) {
     // Generate the profile string.
     std::string profile =
@@ -120,6 +126,9 @@
       case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR:
         profile += service_manager::kSeatbeltPolicyString_pdf_compositor;
         break;
+      case service_manager::SANDBOX_TYPE_AUDIO:
+        profile += service_manager::kSeatbeltPolicyString_audio;
+        break;
       case service_manager::SANDBOX_TYPE_UTILITY:
       case service_manager::SANDBOX_TYPE_PROFILING:
         profile += service_manager::kSeatbeltPolicyString_utility;
@@ -143,6 +152,7 @@
       case service_manager::SANDBOX_TYPE_NACL_LOADER:
       case service_manager::SANDBOX_TYPE_RENDERER:
       case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR:
+      case service_manager::SANDBOX_TYPE_AUDIO:
         SetupCommonSandboxParameters(seatbelt_exec_client_.get());
         break;
       case service_manager::SANDBOX_TYPE_PPAPI:
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index fe8a7cc..ef2d56f4 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -26,7 +26,6 @@
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
-#include "components/viz/common/gl_helper.h"
 #include "components/viz/common/switches.h"
 #include "components/viz/host/host_display_client.h"
 #include "components/viz/host/host_frame_sink_manager.h"
@@ -731,21 +730,10 @@
   }
   per_compositor_data_.erase(it);
   if (per_compositor_data_.empty()) {
-    // Destroying the GLHelper may cause some async actions to be cancelled,
-    // causing things to request a new GLHelper. Due to crbug.com/176091 the
-    // GLHelper created in this case would be lost/leaked if we just reset()
-    // on the |gl_helper_| variable directly. So instead we call reset() on a
-    // local std::unique_ptr.
-    std::unique_ptr<viz::GLHelper> helper = std::move(gl_helper_);
-
-    // If there are any observer left at this point, make sure they clean up
-    // before we destroy the GLHelper.
+    // If there are any observers left at this point, notify them that the
+    // context has been lost.
     for (auto& observer : observer_list_)
       observer.OnLostSharedContext();
-
-    helper.reset();
-    DCHECK(!gl_helper_) << "Destroying the GLHelper should not cause a new "
-                           "GLHelper to be created.";
   }
 #if defined(OS_WIN)
   gfx::RenderingWindowManager::GetInstance()->UnregisterParent(
@@ -927,16 +915,6 @@
   return BrowserMainLoop::GetInstance()->GetFrameSinkManager();
 }
 
-viz::GLHelper* GpuProcessTransportFactory::GetGLHelper() {
-  if (!gl_helper_ && !per_compositor_data_.empty()) {
-    scoped_refptr<ContextProvider> provider = SharedMainThreadContextProvider();
-    if (provider.get())
-      gl_helper_.reset(
-          new viz::GLHelper(provider->ContextGL(), provider->ContextSupport()));
-  }
-  return gl_helper_.get();
-}
-
 scoped_refptr<ContextProvider>
 GpuProcessTransportFactory::SharedMainThreadContextProvider() {
   if (is_gpu_compositing_disabled_)
@@ -957,8 +935,6 @@
     return nullptr;
   }
 
-  // We need a separate context from the compositor's so that skia and gl_helper
-  // don't step on each other.
   bool need_alpha_channel = false;
   bool support_locking = false;
   bool support_gles2_interface = true;
@@ -1016,13 +992,10 @@
       shared_main_thread_contexts_;
   shared_main_thread_contexts_ = nullptr;
 
-  std::unique_ptr<viz::GLHelper> lost_gl_helper = std::move(gl_helper_);
-
   for (auto& observer : observer_list_)
     observer.OnLostSharedContext();
 
   // Kill things that use the shared context before killing the shared context.
-  lost_gl_helper.reset();
   lost_shared_main_thread_contexts = nullptr;
 }
 
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index 6704fa4b..0802fe3 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -111,7 +111,6 @@
   ui::ContextFactory* GetContextFactory() override;
   ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
   viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
-  viz::GLHelper* GetGLHelper() override;
 
  private:
   struct PerCompositorData;
@@ -166,7 +165,6 @@
 
   const viz::RendererSettings renderer_settings_;
   scoped_refptr<ui::ContextProviderCommandBuffer> shared_main_thread_contexts_;
-  std::unique_ptr<viz::GLHelper> gl_helper_;
   base::ObserverList<ui::ContextFactoryObserver> observer_list_;
   scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner_;
   std::unique_ptr<cc::SingleThreadTaskGraphRunner> task_graph_runner_;
diff --git a/content/browser/compositor/image_transport_factory.h b/content/browser/compositor/image_transport_factory.h
index 9dba97f..2d093e6 100644
--- a/content/browser/compositor/image_transport_factory.h
+++ b/content/browser/compositor/image_transport_factory.h
@@ -15,10 +15,6 @@
 class ContextFactoryPrivate;
 }
 
-namespace viz {
-class GLHelper;
-}
-
 namespace content {
 
 // This class provides the interface for creating the support for the
@@ -54,11 +50,6 @@
   // compositor. TODO(fsamuel): This interface should eventually go away once
   // Mus subsumes this functionality.
   virtual ui::ContextFactoryPrivate* GetContextFactoryPrivate() = 0;
-
-  // Gets a GLHelper instance, associated with the shared context. This
-  // GLHelper will get destroyed whenever the shared context is lost
-  // (ImageTransportFactoryObserver::OnLostResources is called).
-  virtual viz::GLHelper* GetGLHelper() = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/compositor/image_transport_factory_browsertest.cc b/content/browser/compositor/image_transport_factory_browsertest.cc
index c9ae05f..91e6d9e 100644
--- a/content/browser/compositor/image_transport_factory_browsertest.cc
+++ b/content/browser/compositor/image_transport_factory_browsertest.cc
@@ -82,8 +82,8 @@
                        LoseOnTearDown) {
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
 
-  // TODO(crbug.com/844469): Delete after OOP-D is launched because GLHelper
-  // and OwnedMailbox aren't used.
+  // TODO(crbug.com/844469): Delete after OOP-D is launched because OwnedMailbox
+  // isn't used.
   if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
     return;
 
diff --git a/content/browser/compositor/test/test_image_transport_factory.cc b/content/browser/compositor/test/test_image_transport_factory.cc
index 0e74486..6db6e01f 100644
--- a/content/browser/compositor/test/test_image_transport_factory.cc
+++ b/content/browser/compositor/test/test_image_transport_factory.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "components/viz/common/features.h"
-#include "components/viz/common/gl_helper.h"
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/test/test_frame_sink_manager.h"
@@ -71,8 +70,6 @@
 }
 
 TestImageTransportFactory::~TestImageTransportFactory() {
-  std::unique_ptr<viz::GLHelper> lost_gl_helper = std::move(gl_helper_);
-
   for (auto& observer : observer_list_)
     observer.OnLostSharedContext();
 }
@@ -176,19 +173,4 @@
   return this;
 }
 
-viz::GLHelper* TestImageTransportFactory::GetGLHelper() {
-  if (enable_viz_) {
-    // Nothing should use GLHelper with VizDisplayCompositor enabled.
-    NOTREACHED();
-    return nullptr;
-  }
-
-  if (!gl_helper_) {
-    auto context_provider = SharedMainThreadContextProvider();
-    gl_helper_ = std::make_unique<viz::GLHelper>(
-        context_provider->ContextGL(), context_provider->ContextSupport());
-  }
-  return gl_helper_.get();
-}
-
 }  // namespace content
diff --git a/content/browser/compositor/test/test_image_transport_factory.h b/content/browser/compositor/test/test_image_transport_factory.h
index bf83381..deb5d19 100644
--- a/content/browser/compositor/test/test_image_transport_factory.h
+++ b/content/browser/compositor/test/test_image_transport_factory.h
@@ -21,7 +21,6 @@
 #include "ui/compositor/compositor.h"
 
 namespace viz {
-class GLHelper;
 class FrameSinkManagerImpl;
 class ServerSharedBitmapManager;
 class TestFrameSinkManagerImpl;
@@ -87,7 +86,6 @@
   bool IsGpuCompositingDisabled() override;
   ui::ContextFactory* GetContextFactory() override;
   ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
-  viz::GLHelper* GetGLHelper() override;
 
  private:
   const bool enable_viz_;
@@ -104,7 +102,6 @@
   // Objects that exist if |enable_viz_| is false.
   std::unique_ptr<viz::ServerSharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_impl_;
-  std::unique_ptr<viz::GLHelper> gl_helper_;
 
   // Objects that exist if |enable_viz_| is true.
   std::unique_ptr<viz::TestFrameSinkManagerImpl> test_frame_sink_manager_impl_;
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc
index af692ae..f02da8e 100644
--- a/content/browser/compositor/viz_process_transport_factory.cc
+++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -285,11 +285,6 @@
   return this;
 }
 
-viz::GLHelper* VizProcessTransportFactory::GetGLHelper() {
-  NOTREACHED();  // Readback happens in the GPU process and this isn't used.
-  return nullptr;
-}
-
 void VizProcessTransportFactory::OnContextLost() {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
diff --git a/content/browser/compositor/viz_process_transport_factory.h b/content/browser/compositor/viz_process_transport_factory.h
index 731a309d..40a8109 100644
--- a/content/browser/compositor/viz_process_transport_factory.h
+++ b/content/browser/compositor/viz_process_transport_factory.h
@@ -78,7 +78,6 @@
   bool IsGpuCompositingDisabled() override;
   ui::ContextFactory* GetContextFactory() override;
   ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
-  viz::GLHelper* GetGLHelper() override;
 
   // viz::ContextLostObserver implementation.
   void OnContextLost() override;
diff --git a/content/browser/cross_site_transfer_browsertest.cc b/content/browser/cross_site_transfer_browsertest.cc
index bc1b974f..104842f 100644
--- a/content/browser/cross_site_transfer_browsertest.cc
+++ b/content/browser/cross_site_transfer_browsertest.cc
@@ -472,24 +472,4 @@
       << "Request should have been cancelled before reaching the renderer.";
 }
 
-// Ensure that we don't send a referrer if a site tries to trigger the forking
-// heuristic, even if we would have forked anyways.
-IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, NoReferrerOnFork) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kContentShellAlwaysFork);
-
-  GURL start_url(embedded_test_server()->GetURL("a.com", "/fork-popup.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), start_url));
-  EXPECT_EQ(2u, shell()->windows().size());
-  Shell* popup = shell()->windows().back();
-  EXPECT_NE(popup, shell());
-
-  base::string16 expected_title = base::ASCIIToUTF16("Referrer = ''");
-  base::string16 failed_title = base::ASCIIToUTF16(
-      base::StringPrintf("Referrer = '%s'", start_url.spec().c_str()));
-  TitleWatcher watcher(popup->web_contents(), expected_title);
-  watcher.AlsoWaitForTitle(failed_title);
-  EXPECT_EQ(expected_title, watcher.WaitAndGetTitle());
-}
-
 }  // namespace content
diff --git a/content/browser/devtools/devtools_frame_trace_recorder.cc b/content/browser/devtools/devtools_frame_trace_recorder.cc
index 9f8da6cf..4c8f6b24 100644
--- a/content/browser/devtools/devtools_frame_trace_recorder.cc
+++ b/content/browser/devtools/devtools_frame_trace_recorder.cc
@@ -80,14 +80,6 @@
 
 DevToolsFrameTraceRecorder::~DevToolsFrameTraceRecorder() { }
 
-void DevToolsFrameTraceRecorder::OnSwapCompositorFrame(
-    RenderFrameHostImpl* host,
-    const viz::CompositorFrameMetadata& frame_metadata) {
-  if (!host || !ScreenshotCategoryEnabled())
-    return;
-  CaptureFrame(host, frame_metadata);
-}
-
 void DevToolsFrameTraceRecorder::OnSynchronousSwapCompositorFrame(
     RenderFrameHostImpl* host,
     const viz::CompositorFrameMetadata& frame_metadata) {
diff --git a/content/browser/devtools/devtools_frame_trace_recorder.h b/content/browser/devtools/devtools_frame_trace_recorder.h
index a80afc02..ed1d52f 100644
--- a/content/browser/devtools/devtools_frame_trace_recorder.h
+++ b/content/browser/devtools/devtools_frame_trace_recorder.h
@@ -24,10 +24,6 @@
   DevToolsFrameTraceRecorder();
   ~DevToolsFrameTraceRecorder();
 
-  void OnSwapCompositorFrame(
-      RenderFrameHostImpl* host,
-      const viz::CompositorFrameMetadata& frame_metadata);
-
   void OnSynchronousSwapCompositorFrame(
       RenderFrameHostImpl* host,
       const viz::CompositorFrameMetadata& frame_metadata);
diff --git a/content/browser/devtools/protocol/memory_handler.cc b/content/browser/devtools/protocol/memory_handler.cc
index 06a5638..8af23aa 100644
--- a/content/browser/devtools/protocol/memory_handler.cc
+++ b/content/browser/devtools/protocol/memory_handler.cc
@@ -4,7 +4,10 @@
 
 #include "content/browser/devtools/protocol/memory_handler.h"
 
+#include <cinttypes>
+
 #include "base/memory/memory_pressure_listener.h"
+#include "base/sampling_heap_profiler/module_cache.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/render_process_host.h"
@@ -33,6 +36,7 @@
 
 Response MemoryHandler::GetBrowserSamplingProfile(
     std::unique_ptr<Memory::SamplingProfile>* out_profile) {
+  base::ModuleCache module_cache;
   std::unique_ptr<Array<Memory::SamplingProfileNode>> samples =
       Array<Memory::SamplingProfileNode>::create();
   std::vector<base::SamplingHeapProfiler::Sample> raw_samples =
@@ -40,8 +44,11 @@
 
   for (auto& sample : raw_samples) {
     std::unique_ptr<Array<String>> stack = Array<String>::create();
-    for (auto* frame : sample.stack)
-      stack->addItem(base::StringPrintf("%p", frame));
+    for (const void* frame : sample.stack) {
+      uintptr_t address = reinterpret_cast<uintptr_t>(frame);
+      module_cache.GetModuleForAddress(address);  // Populates module_cache.
+      stack->addItem(base::StringPrintf("0x%" PRIxPTR, address));
+    }
     samples->addItem(Memory::SamplingProfileNode::Create()
                          .SetSize(sample.size)
                          .SetTotal(sample.total)
@@ -49,8 +56,23 @@
                          .Build());
   }
 
-  *out_profile =
-      Memory::SamplingProfile::Create().SetSamples(std::move(samples)).Build();
+  std::unique_ptr<Array<Memory::Module>> modules =
+      Array<Memory::Module>::create();
+  for (const auto* module : module_cache.GetModules()) {
+    modules->addItem(Memory::Module::Create()
+                         .SetName(base::StringPrintf(
+                             "%" PRIsFP, module->filename.value().c_str()))
+                         .SetUuid(module->id)
+                         .SetBaseAddress(base::StringPrintf(
+                             "0x%" PRIxPTR, module->base_address))
+                         .SetSize(static_cast<double>(module->size))
+                         .Build());
+  }
+
+  *out_profile = Memory::SamplingProfile::Create()
+                     .SetSamples(std::move(samples))
+                     .SetModules(std::move(modules))
+                     .Build();
   return Response::OK();
 }
 
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 7a9b40cc..d2b16c63 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -23,7 +23,6 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "components/viz/common/features.h"
 #include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
 #include "content/browser/devtools/protocol/devtools_download_manager_helper.h"
@@ -47,7 +46,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/browser_side_navigation_policy.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/common/use_zoom_for_dsf_policy.h"
@@ -206,10 +204,7 @@
       emulation_handler_(emulation_handler),
       observer_(this),
       weak_factory_(this) {
-  bool create_video_consumer =
-      base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
-      base::FeatureList::IsEnabled(
-          features::kUseVideoCaptureApiForDevToolsSnapshots);
+  bool create_video_consumer = true;
 #ifdef OS_ANDROID
   // Video capture doesn't work on Android WebView. Use CopyFromSurface instead.
   if (!CompositorImpl::IsInitialized())
@@ -275,18 +270,6 @@
   Page::Dispatcher::wire(dispatcher, this);
 }
 
-void PageHandler::OnSwapCompositorFrame(
-    viz::CompositorFrameMetadata frame_metadata) {
-  if (video_consumer_)
-    return;
-
-  last_compositor_frame_metadata_ = std::move(frame_metadata);
-  has_compositor_frame_metadata_ = true;
-
-  if (screencast_enabled_)
-    InnerSwapCompositorFrame();
-}
-
 void PageHandler::OnSynchronousSwapCompositorFrame(
     viz::CompositorFrameMetadata frame_metadata) {
   if (has_compositor_frame_metadata_) {
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index 4cf049c..ea8e3b1 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -68,7 +68,6 @@
   void Wire(UberDispatcher* dispatcher) override;
   void SetRenderer(int process_host_id,
                    RenderFrameHostImpl* frame_host) override;
-  void OnSwapCompositorFrame(viz::CompositorFrameMetadata frame_metadata);
   void OnSynchronousSwapCompositorFrame(
       viz::CompositorFrameMetadata frame_metadata);
   void DidAttachInterstitialPage();
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 9546e5d..7fe66cd 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -24,7 +24,6 @@
 #include "base/trace_event/trace_event_impl.h"
 #include "base/trace_event/tracing_agent.h"
 #include "components/tracing/common/trace_startup_config.h"
-#include "components/viz/common/features.h"
 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
 #include "content/browser/devtools/devtools_io_context.h"
 #include "content/browser/devtools/devtools_session.h"
@@ -38,7 +37,6 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_features.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
 #include "services/tracing/public/mojom/constants.mojom.h"
 
@@ -218,10 +216,7 @@
       return_as_stream_(false),
       gzip_compression_(false),
       weak_factory_(this) {
-  bool use_video_capture_api =
-      base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
-      base::FeatureList::IsEnabled(
-          features::kUseVideoCaptureApiForDevToolsSnapshots);
+  bool use_video_capture_api = true;
 #ifdef OS_ANDROID
   // Video capture API cannot be used on Android WebView.
   if (!CompositorImpl::IsInitialized())
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 9493103..700c766 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -12,7 +12,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "components/viz/common/features.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
@@ -51,7 +50,6 @@
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/browser_side_navigation_policy.h"
-#include "content/public/common/content_features.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_request_headers.h"
@@ -477,10 +475,7 @@
     session->AttachToAgent(agent_ptr_);
 
   if (sessions().size() == 1) {
-    bool use_video_capture_api =
-        base::FeatureList::IsEnabled(features::kVizDisplayCompositor) ||
-        base::FeatureList::IsEnabled(
-            features::kUseVideoCaptureApiForDevToolsSnapshots);
+    bool use_video_capture_api = true;
 #ifdef OS_ANDROID
     // Video capture API cannot be used on Android WebView.
     if (!CompositorImpl::IsInitialized())
@@ -786,23 +781,6 @@
 #endif
 }
 
-void RenderFrameDevToolsAgentHost::DidReceiveCompositorFrame() {
-  const viz::CompositorFrameMetadata& metadata =
-      RenderWidgetHostImpl::From(
-          web_contents()->GetRenderViewHost()->GetWidget())
-          ->last_frame_metadata();
-  for (auto* page : protocol::PageHandler::ForAgentHost(this))
-    page->OnSwapCompositorFrame(metadata.Clone());
-
-  if (!frame_trace_recorder_)
-    return;
-  bool did_initiate_recording = false;
-  for (auto* tracing : protocol::TracingHandler::ForAgentHost(this))
-    did_initiate_recording |= tracing->did_initiate_recording();
-  if (did_initiate_recording)
-    frame_trace_recorder_->OnSwapCompositorFrame(frame_host_, metadata);
-}
-
 void RenderFrameDevToolsAgentHost::OnPageScaleFactorChanged(
     float page_scale_factor) {
   for (auto* input : protocol::InputHandler::ForAgentHost(this))
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index b4184bb..a0867d1 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -178,7 +178,6 @@
   void DidAttachInterstitialPage() override;
   void DidDetachInterstitialPage() override;
   void OnVisibilityChanged(content::Visibility visibility) override;
-  void DidReceiveCompositorFrame() override;
   void OnPageScaleFactorChanged(float page_scale_factor) override;
 
   bool IsChildFrame();
diff --git a/content/browser/dom_storage/storage_area_impl_unittest.cc b/content/browser/dom_storage/storage_area_impl_unittest.cc
index 1d311f1..b858637c 100644
--- a/content/browser/dom_storage/storage_area_impl_unittest.cc
+++ b/content/browser/dom_storage/storage_area_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/services/leveldb/public/interfaces/leveldb.mojom.h"
 #include "content/browser/dom_storage/test/storage_area_test_util.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/barrier_builder.h"
 #include "content/test/fake_leveldb_database.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
@@ -26,9 +27,9 @@
 
 namespace content {
 namespace {
-using test::MakeSuccessCallback;
-using test::MakeGetAllCallback;
 using test::GetAllCallback;
+using test::MakeGetAllCallback;
+using test::MakeSuccessCallback;
 using CacheMode = StorageAreaImpl::CacheMode;
 using DatabaseError = leveldb::mojom::DatabaseError;
 
@@ -43,53 +44,6 @@
   return leveldb::StdStringToUint8Vector(input);
 }
 
-class InternalIncrementalBarrier {
- public:
-  InternalIncrementalBarrier(base::OnceClosure done_closure)
-      : num_callbacks_left_(1), done_closure_(std::move(done_closure)) {}
-
-  void Dec() {
-    // This is the same as in BarrierClosure.
-    DCHECK(!num_callbacks_left_.IsZero());
-    if (!num_callbacks_left_.Decrement()) {
-      base::OnceClosure done = std::move(done_closure_);
-      delete this;
-      std::move(done).Run();
-    }
-  }
-
-  base::OnceClosure Inc() {
-    num_callbacks_left_.Increment();
-    return base::BindOnce(&InternalIncrementalBarrier::Dec,
-                          base::Unretained(this));
-  }
-
- private:
-  base::AtomicRefCount num_callbacks_left_;
-  base::OnceClosure done_closure_;
-
-  DISALLOW_COPY_AND_ASSIGN(InternalIncrementalBarrier);
-};
-
-// The callbacks returned by Get might get called after destruction of this
-// class (and thus the done_closure), so there needs to be an internal class
-// to hold the final callback & manage the refcount.
-class IncrementalBarrier {
- public:
-  explicit IncrementalBarrier(base::OnceClosure done_closure)
-      : internal_barrier_(
-            new InternalIncrementalBarrier(std::move(done_closure))) {}
-
-  ~IncrementalBarrier() { internal_barrier_->Dec(); }
-
-  base::OnceClosure Get() { return internal_barrier_->Inc(); }
-
- private:
-  InternalIncrementalBarrier* internal_barrier_;  // self-deleting
-
-  DISALLOW_COPY_AND_ASSIGN(IncrementalBarrier);
-};
-
 class MockDelegate : public StorageAreaImpl::Delegate {
  public:
   MockDelegate() {}
@@ -382,11 +336,12 @@
   std::vector<uint8_t> result;
   bool get_success = false;
   {
-    IncrementalBarrier barrier(loop.QuitClosure());
-    storage_area()->Put(key, value, test_value2_bytes_, test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_success));
-    storage_area()->Get(key,
-                        MakeGetCallback(barrier.Get(), &get_success, &result));
+    BarrierBuilder barrier(loop.QuitClosure());
+    storage_area()->Put(
+        key, value, test_value2_bytes_, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_success));
+    storage_area()->Get(
+        key, MakeGetCallback(barrier.AddClosure(), &get_success, &result));
   }
 
   loop.Run();
@@ -454,17 +409,17 @@
   bool put_success2 = false;
   bool put_success3 = false;
   {
-    IncrementalBarrier barrier(loop.QuitClosure());
+    BarrierBuilder barrier(loop.QuitClosure());
 
-    storage_area()->Put(ToBytes(key1), ToBytes(value1), test_value2_bytes_,
-                        test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_success1));
-    storage_area()->Put(ToBytes(key2), ToBytes("old value"), base::nullopt,
-                        test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_success2));
-    storage_area()->Put(ToBytes(key2), ToBytes(value2), ToBytes("old value"),
-                        test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_success3));
+    storage_area()->Put(
+        ToBytes(key1), ToBytes(value1), test_value2_bytes_, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_success1));
+    storage_area()->Put(
+        ToBytes(key2), ToBytes("old value"), base::nullopt, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_success2));
+    storage_area()->Put(
+        ToBytes(key2), ToBytes(value2), ToBytes("old value"), test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_success3));
   }
 
   loop.Run();
@@ -877,16 +832,18 @@
   bool put_result1 = false;
   bool put_result2 = false;
   {
-    IncrementalBarrier barrier(loop.QuitClosure());
+    BarrierBuilder barrier(loop.QuitClosure());
 
-    storage_area()->Put(key, value, value2, test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_result1));
+    storage_area()->Put(
+        key, value, value2, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_result1));
 
     storage_area()->GetAll(
-        GetAllCallback::CreateAndBind(&result, barrier.Get()),
+        GetAllCallback::CreateAndBind(&result, barrier.AddClosure()),
         MakeGetAllCallback(&get_all_success, &data));
-    storage_area()->Put(key, value2, value, test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_result2));
+    storage_area()->Put(
+        key, value2, value, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_result2));
     FlushAreaBinding();
   }
 
@@ -946,10 +903,11 @@
   bool get_all_callback_success = false;
   bool delete_success = false;
   {
-    IncrementalBarrier barrier(loop.QuitClosure());
+    BarrierBuilder barrier(loop.QuitClosure());
 
-    storage_area()->Put(key, value, value2, test_source_,
-                        MakeSuccessCallback(barrier.Get(), &put_success));
+    storage_area()->Put(
+        key, value, value2, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_success));
 
     // Put task triggers database upgrade, so there are no more changes
     // to commit.
@@ -958,12 +916,13 @@
     EXPECT_TRUE(storage_area_impl()->has_pending_load_tasks());
 
     storage_area()->GetAll(
-        GetAllCallback::CreateAndBind(&get_all_success, barrier.Get()),
+        GetAllCallback::CreateAndBind(&get_all_success, barrier.AddClosure()),
         MakeGetAllCallback(&get_all_callback_success, &data));
 
     // This Delete() should not affect the value returned by GetAll().
-    storage_area()->Delete(key, value, test_source_,
-                           MakeSuccessCallback(barrier.Get(), &delete_success));
+    storage_area()->Delete(
+        key, value, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &delete_success));
   }
   loop.Run();
 
@@ -1093,7 +1052,7 @@
   bool put_success3 = false;
   base::RunLoop loop;
   {
-    IncrementalBarrier barrier(loop.QuitClosure());
+    BarrierBuilder barrier(loop.QuitClosure());
 
     // Create fork 1.
     fork1 = storage_area_impl()->ForkToNewPrefix(test_copy_prefix1_,
@@ -1103,16 +1062,17 @@
     // Note - these are 'skipping' the mojo layer, which is why the fork isn't
     // scheduled.
     fork1->Put(test_key2_bytes_, ToBytes(value4), test_value2_bytes_,
-               test_source_, MakeSuccessCallback(barrier.Get(), &put_success1));
+               test_source_,
+               MakeSuccessCallback(barrier.AddClosure(), &put_success1));
     fork2 =
         fork1->ForkToNewPrefix(test_copy_prefix2_, &fork2_delegate, options);
     fork1->Put(test_key2_bytes_, ToBytes(value5), ToBytes(value4), test_source_,
-               MakeSuccessCallback(barrier.Get(), &put_success2));
+               MakeSuccessCallback(barrier.AddClosure(), &put_success2));
 
     // Do a put on original and create fork 3, which is key-only.
-    storage_area_impl()->Put(test_key1_bytes_, ToBytes(value3),
-                             test_value1_bytes_, test_source_,
-                             MakeSuccessCallback(barrier.Get(), &put_success3));
+    storage_area_impl()->Put(
+        test_key1_bytes_, ToBytes(value3), test_value1_bytes_, test_source_,
+        MakeSuccessCallback(barrier.AddClosure(), &put_success3));
     fork3 = storage_area_impl()->ForkToNewPrefix(
         test_copy_prefix3_, &fork3_delegate,
         GetDefaultTestingOptions(CacheMode::KEYS_ONLY_WHEN_POSSIBLE));
@@ -1203,7 +1163,7 @@
 
   base::RunLoop loop;
   {
-    IncrementalBarrier barrier(loop.QuitClosure());
+    BarrierBuilder barrier(loop.QuitClosure());
     for (int64_t i = 0; i < kTotalAreas; i++) {
       FuzzState& state = states[i];
       if (!areas[i]) {
@@ -1223,26 +1183,27 @@
         FuzzState old_state = state;
         state.val1 = base::nullopt;
         successes.push_back(false);
-        areas[i]->Delete(kKey1Vec, old_state.val1, test_source_,
-                         MakeSuccessCallback(barrier.Get(), &successes.back()));
+        areas[i]->Delete(
+            kKey1Vec, old_state.val1, test_source_,
+            MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
       }
       if (i % 4 == 0) {
         FuzzState old_state = state;
         state.val2 = base::make_optional<std::vector<uint8_t>>(
             {static_cast<uint8_t>(i)});
         successes.push_back(false);
-        areas[i]->Put(kKey2Vec, state.val2.value(), old_state.val2,
-                      test_source_,
-                      MakeSuccessCallback(barrier.Get(), &successes.back()));
+        areas[i]->Put(
+            kKey2Vec, state.val2.value(), old_state.val2, test_source_,
+            MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
       }
       if (i % 3 == 0) {
         FuzzState old_state = state;
         state.val1 = base::make_optional<std::vector<uint8_t>>(
             {static_cast<uint8_t>(i + 5)});
         successes.push_back(false);
-        areas[i]->Put(kKey1Vec, state.val1.value(), old_state.val1,
-                      test_source_,
-                      MakeSuccessCallback(barrier.Get(), &successes.back()));
+        areas[i]->Put(
+            kKey1Vec, state.val1.value(), old_state.val1, test_source_,
+            MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
       }
       if (i % 11 == 0) {
         state.val1 = base::nullopt;
@@ -1250,7 +1211,7 @@
         successes.push_back(false);
         areas[i]->DeleteAll(
             test_source_,
-            MakeSuccessCallback(barrier.Get(), &successes.back()));
+            MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
       }
       if (i % 2 == 0 && forks + 1 < kTotalAreas) {
         CacheMode mode = i % 3 == 0 ? CacheMode::KEYS_AND_VALUES
@@ -1266,9 +1227,9 @@
         state.val1 = base::make_optional<std::vector<uint8_t>>(
             {static_cast<uint8_t>(i + 9)});
         successes.push_back(false);
-        areas[i]->Put(kKey1Vec, state.val1.value(), old_state.val1,
-                      test_source_,
-                      MakeSuccessCallback(barrier.Get(), &successes.back()));
+        areas[i]->Put(
+            kKey1Vec, state.val1.value(), old_state.val1, test_source_,
+            MakeSuccessCallback(barrier.AddClosure(), &successes.back()));
       }
     }
   }
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 04c9a1d..37cabf2c9 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -23,8 +23,8 @@
 #include "build/build_config.h"
 #include "components/download/database/in_progress/download_entry.h"
 #include "components/download/database/in_progress/in_progress_cache_impl.h"
-#include "components/download/database/switches.h"
 #include "components/download/public/common/download_create_info.h"
+#include "components/download/public/common/download_features.h"
 #include "components/download/public/common/download_file.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
 #include "components/download/public/common/download_item_factory.h"
@@ -626,8 +626,8 @@
 void DownloadManagerImpl::OnHistoryQueryComplete(
     base::OnceClosure load_history_downloads_cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          download::switches::kEnableDownloadDB) &&
+  if (base::FeatureList::IsEnabled(
+          download::features::kDownloadDBForNewDownloads) &&
       !in_progress_cache_initialized_) {
     load_history_downloads_cb_ = std::move(load_history_downloads_cb);
   } else {
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 836668c..201f23b 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -6,10 +6,8 @@
 
 #include <iterator>
 
-#include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/appcache/appcache_service_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -27,7 +25,6 @@
 #include "content/browser/frame_host/origin_policy_throttle.h"
 #include "content/browser/frame_host/webui_navigation_throttle.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
 #include "content/common/child_process_host_impl.h"
@@ -49,15 +46,6 @@
 
 namespace {
 
-// Default timeout for the READY_TO_COMMIT -> COMMIT transition.
-// Chosen based on the Navigation.ReadyToCommitUntilCommit UMA.
-constexpr base::TimeDelta kDefaultCommitTimeout =
-    base::TimeDelta::FromSeconds(10);
-
-// Timeout for the READY_TO_COMMIT -> COMMIT transition.
-// Overrideable via SetCommitTimeoutForTesting.
-base::TimeDelta g_commit_timeout = kDefaultCommitTimeout;
-
 // Use this to get a new unique ID for a NavigationHandle during construction.
 // The returned ID is guaranteed to be nonzero (zero is the "no ID" indicator).
 int64_t CreateUniqueHandleID() {
@@ -834,7 +822,6 @@
   render_frame_host_ = render_frame_host;
   state_ = READY_TO_COMMIT;
   ready_to_commit_time_ = base::TimeTicks::Now();
-  RestartCommitTimeout();
 
   // Record metrics for the time it takes to get to this state from the
   // beginning of the navigation.
@@ -910,8 +897,6 @@
                                  "DidCommitNavigation");
     state_ = DID_COMMIT;
   }
-  commit_timeout_timer_.Stop();
-  GetRenderFrameHost()->GetRenderWidgetHost()->RendererIsResponsive();
 
   // Record metrics for the time it took to commit the navigation if it was to
   // another document without error.
@@ -1396,31 +1381,4 @@
   return throttles_[next_index_ - 1].get();
 }
 
-void NavigationHandleImpl::RestartCommitTimeout() {
-  commit_timeout_timer_.Stop();
-  if (state_ >= DID_COMMIT)
-    return;
-
-  commit_timeout_timer_.Start(
-      FROM_HERE, g_commit_timeout,
-      base::BindRepeating(&NavigationHandleImpl::OnCommitTimeout,
-                          weak_factory_.GetWeakPtr()));
-}
-
-void NavigationHandleImpl::OnCommitTimeout() {
-  DCHECK_EQ(READY_TO_COMMIT, state_);
-  GetRenderFrameHost()->GetRenderWidgetHost()->RendererIsUnresponsive(
-      base::BindRepeating(&NavigationHandleImpl::RestartCommitTimeout,
-                          weak_factory_.GetWeakPtr()));
-}
-
-// static
-void NavigationHandleImpl::SetCommitTimeoutForTesting(
-    const base::TimeDelta& timeout) {
-  if (timeout.is_zero())
-    g_commit_timeout = kDefaultCommitTimeout;
-  else
-    g_commit_timeout = timeout;
-}
-
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 29e2978..fe477a94 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -18,8 +18,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/common/content_export.h"
@@ -379,10 +377,6 @@
     return GetDeferringThrottle();
   }
 
-  // Sets the READY_TO_COMMIT -> DID_COMMIT timeout.  Resets the timeout to the
-  // default value if |timeout| is zero.
-  static void SetCommitTimeoutForTesting(const base::TimeDelta& timeout);
-
  private:
   friend class NavigationHandleImplTest;
 
@@ -446,12 +440,6 @@
   // nullptr;
   NavigationThrottle* GetDeferringThrottle() const;
 
-  // Called if READY_TO_COMMIT -> COMMIT state transition takes an unusually
-  // long time.
-  void OnCommitTimeout();
-
-  void RestartCommitTimeout();
-
   // See NavigationHandle for a description of those member variables.
   GURL url_;
   scoped_refptr<SiteInstance> starting_site_instance_;
@@ -507,9 +495,6 @@
   // The time this naviagtion was ready to commit.
   base::TimeTicks ready_to_commit_time_;
 
-  // Timer for detecting an unexpectedly long time to commit a navigation.
-  base::OneShotTimer commit_timeout_timer_;
-
   // The unique id of the corresponding NavigationEntry.
   int pending_nav_entry_id_;
 
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 4b14d65a..69713b84 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -136,13 +136,10 @@
     return;
   }
 
-  bool preempts = true;
-  bool allow_view_command_buffers = true;
-  bool allow_real_time_streams = true;
+  bool is_gpu_host = true;
   host->EstablishGpuChannel(
-      gpu_client_id_, gpu_client_tracing_id_, preempts,
-      allow_view_command_buffers, allow_real_time_streams,
-      base::Bind(
+      gpu_client_id_, gpu_client_tracing_id_, is_gpu_host,
+      base::BindOnce(
           &BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
           this));
 }
diff --git a/content/browser/gpu/browser_gpu_client_delegate.cc b/content/browser/gpu/browser_gpu_client_delegate.cc
new file mode 100644
index 0000000..4c34ad9
--- /dev/null
+++ b/content/browser/gpu/browser_gpu_client_delegate.cc
@@ -0,0 +1,69 @@
+// 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 "content/browser/gpu/browser_gpu_client_delegate.h"
+
+#include "gpu/config/gpu_feature_info.h"
+#include "gpu/config/gpu_info.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace content {
+
+BrowserGpuClientDelegate::BrowserGpuClientDelegate() = default;
+
+BrowserGpuClientDelegate::~BrowserGpuClientDelegate() = default;
+
+viz::mojom::GpuService* BrowserGpuClientDelegate::EnsureGpuService() {
+  if (auto* host = GpuProcessHost::Get())
+    return host->gpu_service();
+  return nullptr;
+}
+
+void BrowserGpuClientDelegate::EstablishGpuChannel(
+    int client_id,
+    uint64_t client_tracing_id,
+    EstablishGpuChannelCallback callback) {
+  auto* host = GpuProcessHost::Get();
+  if (!host) {
+    std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
+                            gpu::GpuFeatureInfo(),
+                            EstablishGpuChannelStatus::kGpuAccessDenied);
+    return;
+  }
+
+  const bool is_gpu_host = false;
+  host->EstablishGpuChannel(
+      client_id, client_tracing_id, is_gpu_host,
+      base::BindOnce(&BrowserGpuClientDelegate::OnEstablishGpuChannel,
+                     base::Unretained(this), std::move(callback)));
+}
+
+void BrowserGpuClientDelegate::OnEstablishGpuChannel(
+    GpuClientDelegate::EstablishGpuChannelCallback callback,
+    mojo::ScopedMessagePipeHandle channel_handle,
+    const gpu::GPUInfo& gpu_info,
+    const gpu::GpuFeatureInfo& gpu_feature_info,
+    GpuProcessHost::EstablishChannelStatus status) {
+  if (!callback)
+    return;
+
+  GpuClientDelegate::EstablishGpuChannelStatus delegate_status;
+  switch (status) {
+    case GpuProcessHost::EstablishChannelStatus::GPU_ACCESS_DENIED:
+      delegate_status =
+          GpuClientDelegate::EstablishGpuChannelStatus::kGpuAccessDenied;
+      break;
+    case GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID:
+      delegate_status =
+          GpuClientDelegate::EstablishGpuChannelStatus::kGpuHostInvalid;
+      break;
+    case GpuProcessHost::EstablishChannelStatus::SUCCESS:
+      delegate_status = GpuClientDelegate::EstablishGpuChannelStatus::kSuccess;
+      break;
+  }
+  std::move(callback).Run(std::move(channel_handle), gpu_info, gpu_feature_info,
+                          delegate_status);
+}
+
+}  // namespace content
diff --git a/content/browser/gpu/browser_gpu_client_delegate.h b/content/browser/gpu/browser_gpu_client_delegate.h
new file mode 100644
index 0000000..4b3f8557
--- /dev/null
+++ b/content/browser/gpu/browser_gpu_client_delegate.h
@@ -0,0 +1,37 @@
+// 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 CONTENT_BROWSER_GPU_BROWSER_GPU_CLIENT_DELEGATE_H_
+#define CONTENT_BROWSER_GPU_BROWSER_GPU_CLIENT_DELEGATE_H_
+
+#include "content/browser/gpu/gpu_client_delegate.h"
+#include "content/browser/gpu/gpu_process_host.h"
+
+namespace content {
+
+class BrowserGpuClientDelegate : public GpuClientDelegate {
+ public:
+  BrowserGpuClientDelegate();
+  ~BrowserGpuClientDelegate() override;
+
+  // GpuClientDelegate:
+  viz::mojom::GpuService* EnsureGpuService() override;
+  void EstablishGpuChannel(int client_id,
+                           uint64_t client_tracing_id,
+                           EstablishGpuChannelCallback callback) override;
+
+ private:
+  void OnEstablishGpuChannel(
+      GpuClientDelegate::EstablishGpuChannelCallback callback,
+      mojo::ScopedMessagePipeHandle channel_handle,
+      const gpu::GPUInfo& gpu_info,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
+      GpuProcessHost::EstablishChannelStatus status);
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserGpuClientDelegate);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_GPU_BROWSER_GPU_CLIENT_DELEGATE_H_
diff --git a/content/browser/gpu/gpu_client_delegate.h b/content/browser/gpu/gpu_client_delegate.h
new file mode 100644
index 0000000..670de4cb
--- /dev/null
+++ b/content/browser/gpu/gpu_client_delegate.h
@@ -0,0 +1,60 @@
+// 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 CONTENT_BROWSER_GPU_GPU_CLIENT_DELEGATE_H_
+#define CONTENT_BROWSER_GPU_GPU_CLIENT_DELEGATE_H_
+
+#include "base/callback_forward.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace gpu {
+struct GPUInfo;
+struct GpuFeatureInfo;
+}  // namespace gpu
+
+namespace viz {
+namespace mojom {
+class GpuService;
+}
+}  // namespace viz
+
+namespace content {
+
+// Delegate interface that GpuClientImpl uses to get the current GpuService
+// instance and establish GPU channel for a client. These functions are
+// guaranteed to be called on the thread corresponding to GpuClientImpl's task
+// runner.
+class GpuClientDelegate {
+ public:
+  enum class EstablishGpuChannelStatus {
+    kGpuAccessDenied,  // GPU access was not allowed.
+    kGpuHostInvalid,   // Request failed because the gpu host became invalid
+                       // while processing the request (e.g. the gpu process may
+                       // have been killed). The caller should normally make
+                       // another request to establish a new channel.
+    kSuccess,
+  };
+
+  using EstablishGpuChannelCallback =
+      base::OnceCallback<void(mojo::ScopedMessagePipeHandle channel_handle,
+                              const gpu::GPUInfo&,
+                              const gpu::GpuFeatureInfo&,
+                              EstablishGpuChannelStatus status)>;
+
+  virtual ~GpuClientDelegate() {}
+
+  // Returns the current instance of GPU service. If GPU service is not running,
+  // tries to launch it. If the launch is unsuccessful, returns nullptr.
+  virtual viz::mojom::GpuService* EnsureGpuService() = 0;
+
+  // Sends a request to establish a GPU channel for a client to the GPU service.
+  // If GPU service is not running, tries to launch it and send the request.
+  virtual void EstablishGpuChannel(int client_id,
+                                   uint64_t client_tracing_id,
+                                   EstablishGpuChannelCallback callback) = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_GPU_GPU_CLIENT_DELEGATE_H_
diff --git a/content/browser/gpu/gpu_client_impl.cc b/content/browser/gpu/gpu_client_impl.cc
index c2ef959..944a4f6 100644
--- a/content/browser/gpu/gpu_client_impl.cc
+++ b/content/browser/gpu/gpu_client_impl.cc
@@ -4,12 +4,13 @@
 
 #include "content/browser/gpu/gpu_client_impl.h"
 
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-#include "content/browser/gpu/gpu_process_host.h"
 #include "content/common/child_process_host_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
+#include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
 
 namespace content {
 
@@ -22,7 +23,8 @@
   const uint64_t client_tracing_id =
       ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(client_id);
   std::unique_ptr<GpuClientImpl, base::OnTaskRunnerDeleter> gpu_client(
-      new GpuClientImpl(client_id, client_tracing_id, task_runner),
+      new GpuClientImpl(std::make_unique<BrowserGpuClientDelegate>(), client_id,
+                        client_tracing_id, task_runner),
       base::OnTaskRunnerDeleter(task_runner));
   gpu_client->SetConnectionErrorHandler(std::move(connection_error_handler));
   gpu_client->Add(std::move(request));
@@ -30,13 +32,16 @@
 }
 
 GpuClientImpl::GpuClientImpl(
+    std::unique_ptr<GpuClientDelegate> delegate,
     int client_id,
     uint64_t client_tracing_id,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : client_id_(client_id),
+    : delegate_(std::move(delegate)),
+      client_id_(client_id),
       client_tracing_id_(client_tracing_id),
       task_runner_(std::move(task_runner)),
       weak_factory_(this) {
+  DCHECK(delegate_);
   gpu_bindings_.set_connection_error_handler(
       base::BindRepeating(&GpuClientImpl::OnError, base::Unretained(this),
                           ErrorReason::kConnectionLost));
@@ -86,14 +91,14 @@
     mojo::ScopedMessagePipeHandle channel_handle,
     const gpu::GPUInfo& gpu_info,
     const gpu::GpuFeatureInfo& gpu_feature_info,
-    GpuProcessHost::EstablishChannelStatus status) {
+    GpuClientDelegate::EstablishGpuChannelStatus status) {
   DCHECK_EQ(channel_handle.is_valid(),
-            status == GpuProcessHost::EstablishChannelStatus::SUCCESS);
+            status == GpuClientDelegate::EstablishGpuChannelStatus::kSuccess);
   gpu_channel_requested_ = false;
   EstablishGpuChannelCallback callback = std::move(callback_);
   DCHECK(!callback_);
 
-  if (status == GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID) {
+  if (status == GpuClientDelegate::EstablishGpuChannelStatus::kGpuHostInvalid) {
     // GPU process may have crashed or been killed. Try again.
     EstablishGpuChannel(std::move(callback));
     return;
@@ -104,7 +109,7 @@
                             gpu_feature_info);
     return;
   }
-  if (status == GpuProcessHost::EstablishChannelStatus::SUCCESS) {
+  if (status == GpuClientDelegate::EstablishGpuChannelStatus::kSuccess) {
     // This is the case we pre-establish a channel before a request arrives.
     // Cache the channel for a future request.
     channel_handle_ = std::move(channel_handle);
@@ -144,42 +149,28 @@
     }
     return;
   }
-  GpuProcessHost* host = GpuProcessHost::Get();
-  if (!host) {
-    if (callback) {
-      std::move(callback).Run(client_id_, mojo::ScopedMessagePipeHandle(),
-                              gpu::GPUInfo(), gpu::GpuFeatureInfo());
-    }
-    return;
-  }
   callback_ = std::move(callback);
   if (gpu_channel_requested_)
     return;
   gpu_channel_requested_ = true;
-  bool preempts = false;
-  bool allow_view_command_buffers = false;
-  bool allow_real_time_streams = false;
-  host->EstablishGpuChannel(
-      client_id_, client_tracing_id_, preempts, allow_view_command_buffers,
-      allow_real_time_streams,
-      base::BindRepeating(&GpuClientImpl::OnEstablishGpuChannel,
-                          weak_factory_.GetWeakPtr()));
+  delegate_->EstablishGpuChannel(
+      client_id_, client_tracing_id_,
+      base::BindOnce(&GpuClientImpl::OnEstablishGpuChannel,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void GpuClientImpl::CreateJpegDecodeAccelerator(
     media::mojom::JpegDecodeAcceleratorRequest jda_request) {
-  GpuProcessHost* host = GpuProcessHost::Get();
-  if (host)
-    host->gpu_service()->CreateJpegDecodeAccelerator(std::move(jda_request));
+  if (auto* gpu_service = delegate_->EnsureGpuService())
+    gpu_service->CreateJpegDecodeAccelerator(std::move(jda_request));
 }
 
 void GpuClientImpl::CreateVideoEncodeAcceleratorProvider(
     media::mojom::VideoEncodeAcceleratorProviderRequest vea_provider_request) {
-  GpuProcessHost* host = GpuProcessHost::Get();
-  if (!host)
-    return;
-  host->gpu_service()->CreateVideoEncodeAcceleratorProvider(
-      std::move(vea_provider_request));
+  if (auto* gpu_service = delegate_->EnsureGpuService()) {
+    gpu_service->CreateVideoEncodeAcceleratorProvider(
+        std::move(vea_provider_request));
+  }
 }
 
 void GpuClientImpl::CreateGpuMemoryBuffer(
diff --git a/content/browser/gpu/gpu_client_impl.h b/content/browser/gpu/gpu_client_impl.h
index 70e684a..0b91dc926 100644
--- a/content/browser/gpu/gpu_client_impl.h
+++ b/content/browser/gpu/gpu_client_impl.h
@@ -7,7 +7,7 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
-#include "content/browser/gpu/gpu_process_host.h"
+#include "content/browser/gpu/gpu_client_delegate.h"
 #include "content/public/browser/gpu_client.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 
@@ -19,9 +19,10 @@
  public:
   // GpuClientImpl must be destroyed on the thread associated with
   // |task_runner|.
-  GpuClientImpl(int client_id,
+  GpuClientImpl(std::unique_ptr<GpuClientDelegate> delegate,
+                int client_id,
                 uint64_t client_tracing_id,
-                scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+                scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   ~GpuClientImpl() override;
 
@@ -62,14 +63,16 @@
     kConnectionLost
   };
   void OnError(ErrorReason reason);
-  void OnEstablishGpuChannel(mojo::ScopedMessagePipeHandle channel_handle,
-                             const gpu::GPUInfo& gpu_info,
-                             const gpu::GpuFeatureInfo& gpu_feature_info,
-                             GpuProcessHost::EstablishChannelStatus status);
+  void OnEstablishGpuChannel(
+      mojo::ScopedMessagePipeHandle channel_handle,
+      const gpu::GPUInfo& gpu_info,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
+      GpuClientDelegate::EstablishGpuChannelStatus status);
   void OnCreateGpuMemoryBuffer(CreateGpuMemoryBufferCallback callback,
                                gfx::GpuMemoryBufferHandle handle);
   void ClearCallback();
 
+  std::unique_ptr<GpuClientDelegate> delegate_;
   const int client_id_;
   const uint64_t client_tracing_id_;
   mojo::BindingSet<ui::mojom::GpuMemoryBufferFactory>
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 2be1a07d..29ee919 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -731,7 +731,7 @@
   if (in_process_gpu_thread_)
     DCHECK(process_);
 
-  SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
+  SendOutstandingReplies();
 
 #if defined(OS_MACOSX)
   if (ca_transaction_gpu_coordinator_) {
@@ -953,7 +953,7 @@
     // Channel is hosed, but we may not get destroyed for a while. Send
     // outstanding channel creation failures now so that the caller can restart
     // with a new process/channel without waiting.
-    SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
+    SendOutstandingReplies();
   }
   return result;
 }
@@ -977,45 +977,39 @@
   }
 }
 
-void GpuProcessHost::EstablishGpuChannel(
-    int client_id,
-    uint64_t client_tracing_id,
-    bool preempts,
-    bool allow_view_command_buffers,
-    bool allow_real_time_streams,
-    const EstablishChannelCallback& callback) {
+void GpuProcessHost::EstablishGpuChannel(int client_id,
+                                         uint64_t client_tracing_id,
+                                         bool is_gpu_host,
+                                         EstablishChannelCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel");
 
   // If GPU features are already blacklisted, no need to establish the channel.
   if (!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(nullptr)) {
     DVLOG(1) << "GPU blacklisted, refusing to open a GPU channel.";
-    callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
-                 gpu::GpuFeatureInfo(),
-                 EstablishChannelStatus::GPU_ACCESS_DENIED);
+    std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
+                            gpu::GpuFeatureInfo(),
+                            EstablishChannelStatus::GPU_ACCESS_DENIED);
     return;
   }
 
   if (gpu::IsReservedClientId(client_id)) {
     // The display-compositor/GrShaderCache in the gpu process uses these
     // special client ids.
-    callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
-                 gpu::GpuFeatureInfo(),
-                 EstablishChannelStatus::GPU_ACCESS_DENIED);
+    std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
+                            gpu::GpuFeatureInfo(),
+                            EstablishChannelStatus::GPU_ACCESS_DENIED);
     return;
   }
 
-  DCHECK_EQ(preempts, allow_view_command_buffers);
-  DCHECK_EQ(preempts, allow_real_time_streams);
-  bool is_gpu_host = preempts;
   bool cache_shaders_on_disk =
       GetShaderCacheFactorySingleton()->Get(client_id) != nullptr;
 
-  channel_requests_.push(callback);
+  channel_requests_.push(std::move(callback));
   gpu_service_ptr_->EstablishGpuChannel(
       client_id, client_tracing_id, is_gpu_host, cache_shaders_on_disk,
       base::BindOnce(&GpuProcessHost::OnChannelEstablished,
-                     weak_ptr_factory_.GetWeakPtr(), client_id, callback));
+                     weak_ptr_factory_.GetWeakPtr(), client_id));
 
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kDisableGpuShaderDiskCache)) {
@@ -1090,11 +1084,10 @@
 
 void GpuProcessHost::OnChannelEstablished(
     int client_id,
-    const EstablishChannelCallback& callback,
     mojo::ScopedMessagePipeHandle channel_handle) {
   TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished");
   DCHECK(!channel_requests_.empty());
-  DCHECK(channel_requests_.front().Equals(callback));
+  auto callback = std::move(channel_requests_.front());
   channel_requests_.pop();
 
   auto* gpu_data_manager = GpuDataManagerImpl::GetInstance();
@@ -1103,17 +1096,17 @@
   if (channel_handle.is_valid() &&
       !gpu_data_manager->GpuAccessAllowed(nullptr)) {
     gpu_service_ptr_->CloseChannel(client_id);
-    callback.Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
-                 gpu::GpuFeatureInfo(),
-                 EstablishChannelStatus::GPU_ACCESS_DENIED);
+    std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
+                            gpu::GpuFeatureInfo(),
+                            EstablishChannelStatus::GPU_ACCESS_DENIED);
     RecordLogMessage(logging::LOG_WARNING, "WARNING",
                      "Hardware acceleration is unavailable.");
     return;
   }
 
-  callback.Run(std::move(channel_handle), gpu_data_manager->GetGPUInfo(),
-               gpu_data_manager->GetGpuFeatureInfo(),
-               EstablishChannelStatus::SUCCESS);
+  std::move(callback).Run(
+      std::move(channel_handle), gpu_data_manager->GetGPUInfo(),
+      gpu_data_manager->GetGpuFeatureInfo(), EstablishChannelStatus::SUCCESS);
 }
 
 void GpuProcessHost::OnGpuMemoryBufferCreated(
@@ -1179,7 +1172,7 @@
           cache_key.first, base::Time(), base::Time::Max(), base::Bind([] {}));
     }
   }
-  SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
+  SendOutstandingReplies();
 
   ChildProcessTerminationInfo info =
       process_->GetTerminationInfo(true /* known_dead */);
@@ -1469,17 +1462,16 @@
   return true;
 }
 
-void GpuProcessHost::SendOutstandingReplies(
-    EstablishChannelStatus failure_status) {
-  DCHECK_NE(failure_status, EstablishChannelStatus::SUCCESS);
+void GpuProcessHost::SendOutstandingReplies() {
   valid_ = false;
 
   // First send empty channel handles for all EstablishChannel requests.
   while (!channel_requests_.empty()) {
-    auto callback = channel_requests_.front();
+    auto callback = std::move(channel_requests_.front());
     channel_requests_.pop();
     std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(),
-                            gpu::GpuFeatureInfo(), failure_status);
+                            gpu::GpuFeatureInfo(),
+                            EstablishChannelStatus::GPU_HOST_INVALID);
   }
 
   while (!create_gpu_memory_buffer_requests_.empty()) {
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 5b3188180..7187e92b 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -79,10 +79,10 @@
     SUCCESS
   };
   using EstablishChannelCallback =
-      base::Callback<void(mojo::ScopedMessagePipeHandle channel_handle,
-                          const gpu::GPUInfo&,
-                          const gpu::GpuFeatureInfo&,
-                          EstablishChannelStatus status)>;
+      base::OnceCallback<void(mojo::ScopedMessagePipeHandle channel_handle,
+                              const gpu::GPUInfo&,
+                              const gpu::GpuFeatureInfo&,
+                              EstablishChannelStatus status)>;
 
   enum class BufferCreationStatus {
     GPU_HOST_INVALID,
@@ -137,10 +137,8 @@
   // and GPUInfo, we call the callback.
   void EstablishGpuChannel(int client_id,
                            uint64_t client_tracing_id,
-                           bool preempts,
-                           bool allow_view_command_buffers,
-                           bool allow_real_time_streams,
-                           const EstablishChannelCallback& callback);
+                           bool is_gpu_host,
+                           EstablishChannelCallback callback);
 
   // Tells the GPU process to create a new GPU memory buffer.
   void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
@@ -238,7 +236,6 @@
                         const std::string& message) override;
 
   void OnChannelEstablished(int client_id,
-                            const EstablishChannelCallback& callback,
                             mojo::ScopedMessagePipeHandle channel_handle);
   void OnGpuMemoryBufferCreated(gfx::GpuMemoryBufferHandle handle);
 
@@ -252,7 +249,7 @@
 
   bool LaunchGpuProcess();
 
-  void SendOutstandingReplies(EstablishChannelStatus failure_status);
+  void SendOutstandingReplies();
 
   void RunRequestGPUInfoCallbacks(const gpu::GPUInfo& gpu_info);
 
diff --git a/content/browser/indexed_db/scopes/README.md b/content/browser/indexed_db/scopes/README.md
new file mode 100644
index 0000000..75982fe42
--- /dev/null
+++ b/content/browser/indexed_db/scopes/README.md
@@ -0,0 +1,184 @@
+# LevelDB Scopes Implementation Design
+
+This document is the implementation plan and design for LevelDB Scopes. It serves to both document the current state and the future plans for implementing LevelDB Scopes.
+
+See LevelDB Scopes general design doc [here](https://docs.google.com/document/d/16_igCI15Gfzb6UYqeuJTmJPrzEtawz6Y1tVOKNtYgiU/edit).
+
+# Status / Current State
+
+The only thing implemented so far is the lock manager interface & descrete implementation.
+
+# Vocabulary
+
+**Scope**
+
+A scope encompases a group of changes that can be reverted. It is basically synonymous with a transaction, and would be used for readwrite and versionchange transactions in LevelDB. The scope has a defined list of key ranges where the changes can occur. It operates by keeping an undo log, which is either discarded on commit, or replayed on revert.
+
+**Undo Log**
+
+Each scope saves an undo log, which has all the information needed to undo all changes performed in the scope.
+
+**Scope Number (scope#)**
+
+Each scope has an identifier unique to the backing store that is auto-incrementing. During recovery, it is set to the minimum unused scope (see more in the recovery section).
+
+**Sequence Number (seq#)**
+
+Every undo log entry has a unique sequence number within the scope. These should start at <max int> (using Fixed64) and decrement. The sequence number '0' is reserved for the commit point
+
+**Commit Point**
+
+This signifies that a scope has been committed. It also means that a specific sequence number was written for a scope.
+
+**Key Range**
+
+Represents a range of LevelDB keys. Every operation has a key or a key range associated with it. Sometimes key ranges are expected to be re-used or modified again by subsequent operations, and sometimes key ranges are known to be never used again.
+
+**Lock**
+
+To prevent reading uncommitted data, IndexedDB 'locks' objects stores when there are (readwrite) transactions operating on them.
+
+## New LevelDB Table Data
+
+|Purpose|Key |Final format|Value (protobufs)|
+|---|---|---|---|
+|Metadata|undo-metadata|`prefix-0`|`{version: 1}`|
+|Scope Metadata|undo-scopes-<scope#>|`prefix-1-<scope#>`|key ranges if scope is active, or \<empty\> if committed.|
+|Undo log operations|undo-log-<scope#>-<seq#>|`prefix-2-<scope#>-<seq#>`|undo operation|
+|Commit point|undo-log-<scope#>-0|`prefix-2-<scope#>-0`| \<empty\> OR \<ranges to delete\> |
+
+
+### Key Format
+
+* Allow the 'user' of the scopes system to choose the key prefix (`prefix`).
+* Scope # is a varint
+* Sequence # is a Fixed64
+
+### Value Format
+
+All values will be protobufs
+
+# Operation Flows
+
+## Creating & Using a Scope
+IndexedDB Sequence
+
+* Input - key ranges for the scope. Eg - the applicable object stores (and indexes) for a readwrite txn, or a whole database for a versionchange txn.
+* If any of the key ranges are currently locked, then wait until they are free. This would replace the IDB transaction sequencing logic.
+* Create the scope 
+    * Use the next available scope # (and increment the next scope #)
+    * Signal the locks service that the key ranges for this scope are now locked
+    * Write undo-scopes-scope# -> key_ranges to LevelDB
+* Enable operations on the scope (probably eventually by binding it using mojo)
+* For every operation, the scope must read the database to generate the undo log
+    * See the [Undo Operation Generation](#undo-operations) section below
+* Output - a Scope
+
+## Committing a Scope
+**IndexedDB Sequence**
+
+* Input - a Scope
+* The scope is marked as 'committed', the commit point is written to the undo log (undo-scope#-0), and the metadatais updated to remove the key ranges (undo-scopes-scope# -> <empty>). This change is flushed to disk.
+* The Cleanup & Revert Sequence is signalled for cleaning up the committed scope #.
+* Output - Scope is committed, and lock is released.
+
+## Reverting a Scope
+**Cleanup & Revert Sequence**
+
+* Input - revert a given scope number.
+* Opens a cursor to undo-<scope#>-0
+    * Cursor should be at the first undo entry
+    * If sequence #0 exists (this key exists), then error - reverting a committed scope is an invalid state in this design
+* Iterate through undo log, commiting operations and deleting each undo entry.
+* Delete the lock entry at undo-scopes-<scope#>, and flush this change to disk.
+* Output - Scope was successfully reverted, and lock released.
+
+## Startup & Recovery
+**IndexedDB Sequence**
+
+* Input - the database
+* Reads undo-metadata (fail for unknown version)
+* Opens a cursor to undo-scopes- & iterates to read in all scopes
+    * If the scope metadata has key ranges, then those are considered locked
+    * The maximum scope # is found and used to determine the next scope number (used in scope creation)
+* Signals the lock system which locks are held
+* Signals IndexedDB that it can start accepting operations (IndexedDB can now start running)
+* For every undo-scopes- metadata that is empty
+    * Kick off an [Undo Log Cleanup](#undo-log-cleanup) task to eventually clean this up.
+* For every undo-scopes- metadata with key ranges
+    * If there is a commit point for any of these scopes, then that is an invalid state / corruption (as the scopes value should have been emptied in the same writebatch that wrote the commit point).
+    * Kick off a [Reverting a Scope](#reverting-a-scope) task. This state indicates a shutdown while a revert was in progress.
+* Output - nothing, done
+
+## Undo Log Cleanup
+**Cleanup & Revert Sequence**
+
+* Input - nothing
+* Scan the undo- namespace for commit points. If a undo-scope#-0 is found, then start deleting that undo log
+    * This can happen in multiple write batches
+* If ranges are found in the undo-scope#-0 (commit point), then
+    * Those ranges are also deleted, in batches.
+    * Possibly compact these ranges at the end.
+* The undo-scope#-0 and undo-scopes-scope# entries must be deleted last, in the last deletion write batch, so this scope isn't mistaken later as something to be reverted.
+* Output - nothing
+
+# Lock Manager
+
+The scopes feature needs a fairly generic lock manager. This lock manager needs two levels, because versionchange transactions need to lock a whole database, where other transactions will lock smaller ranges within the level one range.
+
+### API Methods
+
+#### AcquireLock
+
+Accepts a lock type (shared or exclusive), a level number, a key range, and a callback which is given a moveable-only lock object, which releases its lock on destruction. The levels are totally independent from the perspective of the lock manager. IF an application wants to use multiple levels, they should employ an acquisition order (like, always acquire locks in increasing level order) so they don't deadlock.
+
+### Internal Data Structure
+
+The lock manager basically holds ranges, and needs to know if a new range intersects any old ranges. A good data structure for this is an Interval Tree.
+
+# Undo Operations
+
+## Types
+
+* `Put(key, value)`
+* `Delete(key)`
+* `DeleteRange(key_range)`
+
+## Generation
+
+### Normal Cases
+
+Note - all cases where "old_value" is used requires reading the current value from the database.
+
+**`Put(key, value)`**
+
+* `Delete(key)` if an old value doesn't exist,
+* `Put(key, old_value)` if an old value does exist, or
+* Nothing if the old value and new value matches
+
+**`Add(key, value)`**
+
+* Delete(key), trusting the client that there wasn't a value here before.
+
+**`Delete(key)`**
+
+* `Put(key, old_value)` if the old_value exists, or
+* Nothing if no old_value exists.
+
+**`DeleteRange(key_range)`**
+
+* `Put(key, old_value)` for every entry in that key range. This requires iterating the database using the key_range to find all entries.
+
+### Special Case - Empty Unique Key Range
+
+#### Creation - key range is empty initially
+
+If the values being created are in a key range that is initially empty (we trust the API caller here - there is no verification), and if the key range will never be reused if it is reverted, then the undo log can consist of a single:
+
+`DeleteRange(key_range)`
+
+Examples of this are creating new databases or indexes in a versionchange transaction. The scopes system can check to make sure it's range is empty before doing operations. This can either be done as a hint (per-range, per-scope), or always.
+
+#### Deletion - key range will never be used again.
+
+This is done by having commit ranges in the value of the commit point. A new scope is created, and commited, with the key ranges never-to-be-used-again will be the value of the commit point record.
diff --git a/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc b/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc
new file mode 100644
index 0000000..be075a7
--- /dev/null
+++ b/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc
@@ -0,0 +1,165 @@
+// 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 "content/browser/indexed_db/scopes/disjoint_range_lock_manager.h"
+
+namespace content {
+
+DisjointRangeLockManager::LockRequest::LockRequest() = default;
+DisjointRangeLockManager::LockRequest::LockRequest(LockType type,
+                                                   LockAquiredCallback callback)
+    : requested_type(type), callback(std::move(callback)) {}
+DisjointRangeLockManager::LockRequest::LockRequest(LockRequest&&) = default;
+DisjointRangeLockManager::LockRequest::~LockRequest() = default;
+DisjointRangeLockManager::Lock::Lock() = default;
+DisjointRangeLockManager::Lock::Lock(Lock&&) = default;
+DisjointRangeLockManager::Lock::~Lock() = default;
+DisjointRangeLockManager::Lock& DisjointRangeLockManager::Lock::operator=(
+    DisjointRangeLockManager::Lock&&) = default;
+
+DisjointRangeLockManager::DisjointRangeLockManager(
+    int level_count,
+    const leveldb::Comparator* comparator,
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : comparator_(comparator), task_runner_(task_runner), weak_factory_(this) {
+  for (int level = 0; level < level_count; ++level) {
+    locks_.emplace_back(RangeLessThan(comparator));
+  }
+}
+
+DisjointRangeLockManager::~DisjointRangeLockManager() = default;
+
+int64_t DisjointRangeLockManager::LocksHeldForTesting() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  int64_t locks = 0;
+  for (const LockLevelMap& map : locks_) {
+    for (const auto& pair : map) {
+      locks += pair.second.acquired_count;
+    }
+  }
+  return locks;
+}
+int64_t DisjointRangeLockManager::RequestsWaitingForTesting() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  int64_t requests = 0;
+  for (const LockLevelMap& map : locks_) {
+    for (const auto& pair : map) {
+      requests += pair.second.queue.size();
+    }
+  }
+  return requests;
+}
+
+void DisjointRangeLockManager::AcquireLock(int level,
+                                           const LockRange& range,
+                                           LockType type,
+                                           LockAquiredCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_LT(level, static_cast<int>(locks_.size()));
+  DCHECK_LT(comparator_->Compare(leveldb::Slice(range.begin),
+                                 leveldb::Slice(range.end)),
+            0)
+      << "Range is invalid: " << range;
+
+  auto& level_locks = locks_[level];
+
+  auto it = level_locks.find(range);
+  if (it == level_locks.end()) {
+    it = level_locks
+             .emplace(std::piecewise_construct, std::forward_as_tuple(range),
+                      std::forward_as_tuple())
+             .first;
+  }
+
+  DCHECK_EQ(it->first, range)
+      << range << " does not match what is in the lock map " << it->first;
+#if DCHECK_IS_ON()
+  DCHECK(IsRangeDisjointFromNeighbors(level_locks, range, comparator_))
+      << "Range not discrete: " << range;
+#endif
+  Lock& lock = it->second;
+
+  if (lock.CanBeAcquired(type)) {
+    ++lock.acquired_count;
+    lock.lock_mode = type;
+    std::move(callback).Run(
+        ScopeLock(range, level,
+                  base::BindOnce(&DisjointRangeLockManager::LockReleased,
+                                 weak_factory_.GetWeakPtr(), level, range)));
+  } else {
+    lock.queue.emplace_back(type, std::move(callback));
+  }
+}
+
+void DisjointRangeLockManager::RemoveLockRange(int level,
+                                               const LockRange& range) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_LT(level, static_cast<int>(locks_.size()));
+  auto& level_locks = locks_[level];
+  auto it = level_locks.find(range);
+  if (it != level_locks.end()) {
+    DCHECK_EQ(0, it->second.acquired_count);
+    level_locks.erase(it);
+  }
+}
+
+void DisjointRangeLockManager::LockReleased(int level, LockRange range) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_LT(level, static_cast<int>(locks_.size()));
+  auto& level_locks = locks_[level];
+  auto it = level_locks.find(range);
+  DCHECK(it != level_locks.end());
+  Lock& lock = it->second;
+
+  DCHECK_GT(lock.acquired_count, 0);
+  --(lock.acquired_count);
+  if (lock.acquired_count == 0) {
+    // Either the lock isn't acquired yet or more shared locks can be granted.
+    while (!lock.queue.empty() &&
+           (lock.acquired_count == 0 ||
+            lock.queue.front().requested_type == LockType::kShared)) {
+      LockRequest requester = std::move(lock.queue.front());
+      lock.queue.pop_front();
+      ++lock.acquired_count;
+      lock.lock_mode = requester.requested_type;
+      task_runner_->PostTask(
+          FROM_HERE,
+          base::BindOnce(
+              std::move(requester.callback),
+              ScopeLock(range, level,
+                        base::BindOnce(&DisjointRangeLockManager::LockReleased,
+                                       weak_factory_.GetWeakPtr(), level,
+                                       std::move(range)))));
+      // This can only happen if acquired_count was 0.
+      if (requester.requested_type == LockType::kExclusive)
+        return;
+    }
+  }
+}
+
+#if DCHECK_IS_ON()
+// static
+bool DisjointRangeLockManager::IsRangeDisjointFromNeighbors(
+    const LockLevelMap& map,
+    const LockRange& range,
+    const leveldb::Comparator* const comparator) {
+  DCHECK_EQ(map.count(range), 1ull);
+  auto it = map.find(range);
+  auto next_it = it;
+  ++next_it;
+  if (next_it != map.end()) {
+    return comparator->Compare(leveldb::Slice(range.end),
+                               leveldb::Slice(next_it->first.begin)) <= 0;
+  }
+  auto last_it = it;
+  if (last_it != map.begin()) {
+    --last_it;
+    return comparator->Compare(leveldb::Slice(last_it->first.end),
+                               leveldb::Slice(range.begin)) <= 0;
+  }
+  return true;
+}
+#endif
+
+}  // namespace content
diff --git a/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h b/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h
new file mode 100644
index 0000000..f01a5ab
--- /dev/null
+++ b/content/browser/indexed_db/scopes/disjoint_range_lock_manager.h
@@ -0,0 +1,127 @@
+// 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 CONTENT_BROWSER_INDEXED_DB_SCOPES_DISJOINT_RANGE_LOCK_MANAGER_H_
+#define CONTENT_BROWSER_INDEXED_DB_SCOPES_DISJOINT_RANGE_LOCK_MANAGER_H_
+
+#include <list>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
+#include "content/common/content_export.h"
+#include "third_party/leveldatabase/src/include/leveldb/comparator.h"
+#include "third_party/leveldatabase/src/include/leveldb/slice.h"
+
+namespace content {
+
+// Holds locks of the scopes system. To be performant without an Interval Tree,
+// this implementation has the following invariants:
+// * All lock range requests at a level must be disjoint - they cannot overlap.
+// * Lock ranges are remembered for future performance - remove them using
+//   RemoveLockRange.
+// * All calls must happen from the same sequenced task runner.
+class CONTENT_EXPORT DisjointRangeLockManager : public ScopesLockManager {
+ public:
+  // Creates a lock manager with the given number of levels, the comparator for
+  // leveldb keys, and the current task runner that we are running on. The task
+  // runner will be used for the lock acquisition callbacks.
+  DisjointRangeLockManager(
+      int level_count,
+      const leveldb::Comparator* comparator,
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+  ~DisjointRangeLockManager() override;
+
+  int64_t LocksHeldForTesting() const override;
+  int64_t RequestsWaitingForTesting() const override;
+
+  void AcquireLock(int level,
+                   const LockRange& range,
+                   LockType type,
+                   LockAquiredCallback callback) override;
+
+  // Remove the given lock range at the given level. The lock range must not be
+  // in use. Use this if the lock will never be used again.
+  void RemoveLockRange(int level, const LockRange& range);
+
+ private:
+  struct LockRequest {
+   public:
+    LockRequest();
+    LockRequest(LockRequest&&) noexcept;
+    LockRequest(LockType type, LockAquiredCallback callback);
+    ~LockRequest();
+
+    LockType requested_type = LockType::kShared;
+    LockAquiredCallback callback;
+  };
+
+  // Represents a lock, which has a range and a level. To support shared access,
+  // there can be multiple acquisitions of this lock, represented in
+  // |acquired_count|. Also holds the pending requests for this lock.
+  struct Lock {
+   public:
+    Lock();
+    Lock(Lock&&) noexcept;
+    ~Lock();
+    Lock& operator=(Lock&&) noexcept;
+
+    bool CanBeAcquired(LockType lock_type) {
+      return acquired_count == 0 ||
+             (queue.empty() && this->lock_mode == LockType::kShared &&
+              lock_type == LockType::kShared);
+    }
+
+    int acquired_count = 0;
+    LockType lock_mode = LockType::kShared;
+    std::list<LockRequest> queue;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Lock);
+  };
+
+  // This is a proxy between a LevelDB Comparator and the interface expected by
+  // std::map. It sorts using the |begin| entry of the ranges.
+  class RangeLessThan {
+   public:
+    explicit RangeLessThan(const leveldb::Comparator* comparator)
+        : comparator_(comparator) {}
+    bool operator()(const LockRange& a, const LockRange& b) const {
+      return comparator_->Compare(leveldb::Slice(a.begin),
+                                  leveldb::Slice(b.begin)) < 0;
+    }
+
+   private:
+    const leveldb::Comparator* const comparator_;
+  };
+
+  using LockLevelMap = base::flat_map<LockRange, Lock, RangeLessThan>;
+
+  void LockReleased(int level, LockRange range);
+
+#if DCHECK_IS_ON()
+  static bool IsRangeDisjointFromNeighbors(
+      const LockLevelMap& map,
+      const LockRange& range,
+      const leveldb::Comparator* const comparator_);
+#endif
+
+  const leveldb::Comparator* const comparator_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  // This vector should never be modified after construction.
+  std::vector<LockLevelMap> locks_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  base::WeakPtrFactory<DisjointRangeLockManager> weak_factory_;
+  DISALLOW_COPY_AND_ASSIGN(DisjointRangeLockManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_SCOPES_DISJOINT_RANGE_LOCK_MANAGER_H_
diff --git a/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc b/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
new file mode 100644
index 0000000..1e952f51
--- /dev/null
+++ b/content/browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc
@@ -0,0 +1,221 @@
+// 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 <content/browser/indexed_db/scopes/disjoint_range_lock_manager.h>
+#include <content/test/barrier_builder.h>
+
+#include "base/barrier_closure.h"
+#include "base/bind_helpers.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+using ScopeLock = ScopesLockManager::ScopeLock;
+using LockRange = ScopesLockManager::LockRange;
+
+template <typename T>
+void SetValue(T* out, T value) {
+  *out = value;
+}
+
+std::string IntegerKey(size_t num) {
+  return base::StringPrintf("%010zd", num);
+}
+
+void StoreLock(ScopeLock* lock_out, base::OnceClosure done, ScopeLock lock) {
+  (*lock_out) = std::move(lock);
+  std::move(done).Run();
+}
+
+class DisjointRangeLockManagerTest : public testing::Test {
+ public:
+  DisjointRangeLockManagerTest() = default;
+  ~DisjointRangeLockManagerTest() override = default;
+
+ private:
+  base::test::ScopedTaskEnvironment task_env_;
+};
+
+TEST_F(DisjointRangeLockManagerTest, BasicAcquisition) {
+  const size_t kTotalLocks = 1000;
+  DisjointRangeLockManager lock_manager(1, leveldb::BytewiseComparator(),
+                                        base::SequencedTaskRunnerHandle::Get());
+
+  EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+
+  base::RunLoop loop;
+  std::vector<ScopeLock> locks;
+  locks.resize(kTotalLocks);
+  {
+    BarrierBuilder barrier(loop.QuitClosure());
+
+    for (size_t i = 0; i < kTotalLocks / 2; ++i) {
+      LockRange range = {IntegerKey(i), IntegerKey(i + 1)};
+      lock_manager.AcquireLock(
+          0, range, ScopesLockManager::LockType::kExclusive,
+          base::BindOnce(&StoreLock, &locks[i], barrier.AddClosure()));
+    }
+
+    for (size_t i = kTotalLocks - 1; i >= kTotalLocks / 2; --i) {
+      LockRange range = {IntegerKey(i), IntegerKey(i + 1)};
+      lock_manager.AcquireLock(
+          0, range, ScopesLockManager::LockType::kExclusive,
+          base::BindOnce(&StoreLock, &locks[i], barrier.AddClosure()));
+    }
+  }
+  loop.Run();
+  EXPECT_EQ(static_cast<int64_t>(kTotalLocks),
+            lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+  // All locks should be acquired.
+  for (const auto& lock : locks) {
+    EXPECT_TRUE(lock.is_locked());
+  }
+
+  locks.clear();
+  EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+}
+
+TEST_F(DisjointRangeLockManagerTest, Shared) {
+  DisjointRangeLockManager lock_manager(1, leveldb::BytewiseComparator(),
+                                        base::SequencedTaskRunnerHandle::Get());
+  EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+
+  LockRange range = {IntegerKey(0), IntegerKey(1)};
+
+  ScopeLock lock1;
+  ScopeLock lock2;
+  base::RunLoop loop;
+  {
+    BarrierBuilder barrier(loop.QuitClosure());
+    lock_manager.AcquireLock(
+        0, range, ScopesLockManager::LockType::kShared,
+        base::BindOnce(&StoreLock, &lock1, barrier.AddClosure()));
+    lock_manager.AcquireLock(
+        0, range, ScopesLockManager::LockType::kShared,
+        base::BindOnce(&StoreLock, &lock2, barrier.AddClosure()));
+  }
+  loop.Run();
+  EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
+
+  EXPECT_TRUE(lock1.is_locked());
+  EXPECT_TRUE(lock2.is_locked());
+}
+
+TEST_F(DisjointRangeLockManagerTest, SharedAndExclusiveQueuing) {
+  DisjointRangeLockManager lock_manager(1, leveldb::BytewiseComparator(),
+                                        base::SequencedTaskRunnerHandle::Get());
+  EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+
+  LockRange range = {IntegerKey(0), IntegerKey(1)};
+
+  ScopeLock shared_lock1;
+  ScopeLock shared_lock2;
+  ScopeLock exclusive_lock3;
+  ScopeLock shared_lock4;
+
+  {
+    base::RunLoop loop;
+    base::RepeatingClosure barrier =
+        base::BarrierClosure(2, loop.QuitClosure());
+    lock_manager.AcquireLock(
+        0, range, ScopesLockManager::LockType::kShared,
+        base::BindOnce(&StoreLock, &shared_lock1, barrier));
+    lock_manager.AcquireLock(
+        0, range, ScopesLockManager::LockType::kShared,
+        base::BindOnce(&StoreLock, &shared_lock2, barrier));
+    loop.Run();
+  }
+
+  // Both of the following locks should be queued - the exclusive is next in
+  // line, then the shared lock will come after it.
+  lock_manager.AcquireLock(
+      0, range, ScopesLockManager::LockType::kExclusive,
+      base::BindOnce(&StoreLock, &exclusive_lock3, base::DoNothing::Once()));
+  lock_manager.AcquireLock(
+      0, range, ScopesLockManager::LockType::kShared,
+      base::BindOnce(&StoreLock, &shared_lock4, base::DoNothing::Once()));
+  // Flush the task queue.
+  {
+    base::RunLoop loop;
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     loop.QuitClosure());
+    loop.Run();
+  }
+  EXPECT_FALSE(exclusive_lock3.is_locked());
+  EXPECT_FALSE(shared_lock4.is_locked());
+  EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(2ll, lock_manager.RequestsWaitingForTesting());
+
+  // Release the shared locks.
+  shared_lock1.Release();
+  shared_lock2.Release();
+  EXPECT_FALSE(shared_lock1.is_locked());
+  EXPECT_FALSE(shared_lock2.is_locked());
+
+  // Flush the task queue to propagate the lock releases and grant the exclusive
+  // lock.
+  {
+    base::RunLoop loop;
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     loop.QuitClosure());
+    loop.Run();
+  }
+  EXPECT_TRUE(exclusive_lock3.is_locked());
+  EXPECT_FALSE(shared_lock4.is_locked());
+  EXPECT_EQ(1ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(1ll, lock_manager.RequestsWaitingForTesting());
+
+  exclusive_lock3.Release();
+  EXPECT_FALSE(exclusive_lock3.is_locked());
+
+  // Flush the task queue to propagate the lock releases and grant the exclusive
+  // lock.
+  {
+    base::RunLoop loop;
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     loop.QuitClosure());
+    loop.Run();
+  }
+  EXPECT_TRUE(shared_lock4.is_locked());
+  EXPECT_EQ(1ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+}
+
+TEST_F(DisjointRangeLockManagerTest, LevelsOperateSeparately) {
+  DisjointRangeLockManager lock_manager(2, leveldb::BytewiseComparator(),
+                                        base::SequencedTaskRunnerHandle::Get());
+  base::RunLoop loop;
+  ScopeLock l0_lock;
+  ScopeLock l1_lock;
+  {
+    BarrierBuilder barrier(loop.QuitClosure());
+    LockRange range = {IntegerKey(0), IntegerKey(1)};
+    lock_manager.AcquireLock(
+        0, range, ScopesLockManager::LockType::kExclusive,
+        base::BindOnce(&StoreLock, &l0_lock, barrier.AddClosure()));
+    lock_manager.AcquireLock(
+        1, range, ScopesLockManager::LockType::kExclusive,
+        base::BindOnce(&StoreLock, &l1_lock, barrier.AddClosure()));
+  }
+  loop.Run();
+  EXPECT_TRUE(l0_lock.is_locked());
+  EXPECT_TRUE(l1_lock.is_locked());
+  EXPECT_EQ(2ll, lock_manager.LocksHeldForTesting());
+  EXPECT_EQ(0ll, lock_manager.RequestsWaitingForTesting());
+  l0_lock.Release();
+  l1_lock.Release();
+  EXPECT_EQ(0ll, lock_manager.LocksHeldForTesting());
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/browser/indexed_db/scopes/scopes_lock_manager.cc b/content/browser/indexed_db/scopes/scopes_lock_manager.cc
new file mode 100644
index 0000000..98a3580
--- /dev/null
+++ b/content/browser/indexed_db/scopes/scopes_lock_manager.cc
@@ -0,0 +1,61 @@
+// 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 "content/browser/indexed_db/scopes/scopes_lock_manager.h"
+
+#include <ostream>
+
+namespace content {
+
+ScopesLockManager::LockRange::LockRange(std::string begin, std::string end)
+    : begin(std::move(begin)), end(std::move(end)) {}
+
+ScopesLockManager::ScopeLock::ScopeLock() = default;
+ScopesLockManager::ScopeLock::ScopeLock(ScopeLock&& other) {
+  DCHECK(!this->is_locked_) << "Cannot move a lock onto an active lock.";
+  this->is_locked_ = other.is_locked_;
+  this->range_ = std::move(other.range_);
+  this->level_ = other.level_;
+  this->closure_runner_ = std::move(other.closure_runner_);
+  other.is_locked_ = false;
+}
+ScopesLockManager::ScopeLock::ScopeLock(LockRange range,
+                                        int level,
+                                        base::OnceClosure closure)
+    : is_locked_(!closure.is_null()),
+      range_(std::move(range)),
+      level_(level),
+      closure_runner_(std::move(closure)) {}
+
+ScopesLockManager::ScopeLock& ScopesLockManager::ScopeLock::operator=(
+    ScopesLockManager::ScopeLock&& other) {
+  DCHECK(!this->is_locked_);
+  this->is_locked_ = other.is_locked_;
+  this->range_ = std::move(other.range_);
+  this->level_ = other.level_;
+  this->closure_runner_ = std::move(other.closure_runner_);
+  other.is_locked_ = false;
+  return *this;
+};
+
+void ScopesLockManager::ScopeLock::Release() {
+  is_locked_ = false;
+  closure_runner_.RunAndReset();
+}
+
+std::ostream& operator<<(std::ostream& out,
+                         const ScopesLockManager::LockRange& range) {
+  return out << "<ScopesLockManager::ScopeLock>{begin: " << range.begin
+             << ", end: " << range.end << "}";
+}
+
+bool operator==(const ScopesLockManager::LockRange& x,
+                const ScopesLockManager::LockRange& y) {
+  return x.begin == y.begin && x.end == y.end;
+}
+bool operator!=(const ScopesLockManager::LockRange& x,
+                const ScopesLockManager::LockRange& y) {
+  return !(x == y);
+}
+}  // namespace content
diff --git a/content/browser/indexed_db/scopes/scopes_lock_manager.h b/content/browser/indexed_db/scopes/scopes_lock_manager.h
new file mode 100644
index 0000000..075da81
--- /dev/null
+++ b/content/browser/indexed_db/scopes/scopes_lock_manager.h
@@ -0,0 +1,103 @@
+// 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 CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_
+#define CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Generic two-level lock management system based on ranges. Granted locks are
+// represented by the |ScopeLock| class.
+class CONTENT_EXPORT ScopesLockManager {
+ public:
+  // Shared locks can share access to a lock range, while exclusive locks
+  // require that they are the only lock for their range.
+  enum class LockType { kShared, kExclusive };
+
+  // The range is [begin, end).
+  struct CONTENT_EXPORT LockRange {
+    LockRange(std::string begin, std::string end);
+    LockRange() = default;
+    ~LockRange() = default;
+    std::string begin;
+    std::string end;
+  };
+
+  // Represents a granted lock in the ScopesLockManager. When this object is
+  // destroyed, the lock is released. Since default construction is supported,
+  // |is_locked()| can be used to inquire locked status. Also, |Release()| can
+  // be called to manually release the lock, which appropriately updates the
+  // |is_locked()| result.
+  class CONTENT_EXPORT ScopeLock {
+   public:
+    ScopeLock();
+    ScopeLock(ScopeLock&&) noexcept;
+    // The |closure| is called when the lock is released, either by destruction
+    // of this object or by the |Released()| call. It will be called
+    // synchronously on the sequence runner this lock is released on.
+    ScopeLock(LockRange range, int level, base::OnceClosure closure);
+    ~ScopeLock() = default;
+    // This does NOT release the lock if one is being held.
+    ScopeLock& operator=(ScopeLock&&) noexcept;
+
+    // Returns true if this object is holding a lock.
+    bool is_locked() const { return is_locked_; }
+
+    // Releases this lock.
+    void Release();
+
+    int level() const { return level_; }
+    const LockRange& range() const { return range_; }
+
+   private:
+    bool is_locked_ = false;
+    LockRange range_;
+    int level_ = 0;
+    base::ScopedClosureRunner closure_runner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopeLock);
+  };
+
+  using LockAquiredCallback = base::OnceCallback<void(ScopeLock)>;
+
+  ScopesLockManager() = default;
+
+  virtual ~ScopesLockManager() = default;
+
+  virtual int64_t LocksHeldForTesting() const = 0;
+  virtual int64_t RequestsWaitingForTesting() const = 0;
+
+  // Acquires a lock for a given lock level. Lock levels are treated as
+  // completely independent domains. The lock levels start at zero.
+  virtual void AcquireLock(int level,
+                           const LockRange& range,
+                           LockType type,
+                           LockAquiredCallback callback) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopesLockManager);
+};
+
+// Stream operator so lock range can be used in log statements.
+CONTENT_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const ScopesLockManager::LockRange& range);
+
+CONTENT_EXPORT bool operator==(const ScopesLockManager::LockRange& x,
+                               const ScopesLockManager::LockRange& y);
+CONTENT_EXPORT bool operator!=(const ScopesLockManager::LockRange& x,
+                               const ScopesLockManager::LockRange& y);
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_SCOPES_SCOPES_LOCK_MANAGER_H_
diff --git a/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc b/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc
new file mode 100644
index 0000000..a4240c6
--- /dev/null
+++ b/content/browser/indexed_db/scopes/scopes_lock_manager_unittest.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/scopes/scopes_lock_manager.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+TEST(ScopesLockManager, TestRangePopulation) {
+  ScopesLockManager::LockRange range("a", "b");
+  EXPECT_EQ("a", range.begin);
+  EXPECT_EQ("b", range.end);
+}
+
+}  // namespace content
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index fb25e603..0d54e74 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -221,6 +221,16 @@
     std::unique_ptr<ResourceController> controller) {
   has_response_started_ = true;
 
+  if (request()->initiator().has_value()) {
+    const char* initiator_scheme_exception =
+        GetContentClient()
+            ->browser()
+            ->GetInitiatorSchemeBypassingDocumentBlocking();
+    is_initiator_scheme_excluded_ =
+        initiator_scheme_exception &&
+        request()->initiator().value().scheme() == initiator_scheme_exception;
+  }
+
   network::CrossOriginReadBlocking::LogAction(
       network::CrossOriginReadBlocking::Action::kResponseStarted);
 
@@ -358,6 +368,12 @@
     return;
   }
 
+  // If |next_handler_->OnReadCompleted(...)| was not called above, then the
+  // response bytes are being accumulated in the local buffer we've allocated in
+  // ResumeOnWillRead.
+  const size_t new_data_offset = local_buffer_bytes_read_;
+  local_buffer_bytes_read_ += bytes_read;
+
   // If we intended to block the response and haven't sniffed yet, try to
   // confirm that we should block it.  If sniffing is needed, look at the local
   // buffer and either report that zero bytes were read (to indicate the
@@ -377,8 +393,6 @@
     // JSONP, or another allowable data type and we should let it through.
     // Record how many bytes were read to see how often it's too small.  (This
     // will typically be under 100,000.)
-    const size_t new_data_offset = local_buffer_bytes_read_;
-    local_buffer_bytes_read_ += bytes_read;
     DCHECK_LE(local_buffer_bytes_read_, next_handler_buffer_size_);
     const bool more_data_possible =
         bytes_read != 0 && local_buffer_bytes_read_ < net::kMaxBytesToSniff &&
@@ -406,6 +420,16 @@
     }
   }
 
+  // At this point the block-vs-allow decision was made, but might be still
+  // suppressed because of |is_initiator_scheme_excluded_|.  We perform the
+  // suppression at such a late point, because we want to ensure we only call
+  // LogInitiatorSchemeBypassingDocumentBlocking for cases that actuall matter
+  // in practice.
+  if (confirmed_blockable && is_initiator_scheme_excluded_) {
+    initiator_scheme_prevented_blocking_ = true;
+    confirmed_blockable = false;
+  }
+
   // At this point we have already made a block-vs-allow decision and we know
   // that we can wake the |next_handler_| and let it catch-up with our
   // processing of the response.  The first step will always be calling
@@ -534,8 +558,20 @@
   } else {
     // Only report CORB status for successful (i.e. non-aborted,
     // non-errored-out) requests.
-    if (status.is_success())
+    if (status.is_success()) {
       analyzer_->LogAllowedResponse();
+      if (initiator_scheme_prevented_blocking_ &&
+          analyzer_->ShouldReportBlockedResponse() && GetRequestInfo()) {
+        BrowserThread::PostTask(
+            BrowserThread::UI, FROM_HERE,
+            base::BindOnce(&ContentBrowserClient::
+                               LogInitiatorSchemeBypassingDocumentBlocking,
+                           base::Unretained(GetContentClient()->browser()),
+                           request()->initiator().value(),
+                           GetRequestInfo()->GetChildID(),
+                           GetRequestInfo()->GetResourceType()));
+      }
+    }
 
     next_handler_->OnResponseCompleted(status, std::move(controller));
   }
@@ -543,16 +579,10 @@
 
 bool CrossSiteDocumentResourceHandler::ShouldBlockBasedOnHeaders(
     const network::ResourceResponse& response) {
-  // Give embedder a chance to skip document blocking for this response.
-  const char* initiator_scheme_exception =
-      GetContentClient()
-          ->browser()
-          ->GetInitiatorSchemeBypassingDocumentBlocking();
-
   // Delegate most decisions to CrossOriginReadBlocking::ResponseAnalyzer.
   analyzer_ =
       std::make_unique<network::CrossOriginReadBlocking::ResponseAnalyzer>(
-          *request(), response, initiator_scheme_exception);
+          *request(), response);
   if (analyzer_->ShouldAllow())
     return false;
 
diff --git a/content/browser/loader/cross_site_document_resource_handler.h b/content/browser/loader/cross_site_document_resource_handler.h
index 1598fb0..5f11dc70 100644
--- a/content/browser/loader/cross_site_document_resource_handler.h
+++ b/content/browser/loader/cross_site_document_resource_handler.h
@@ -164,6 +164,14 @@
   // completed, and thus it is safe to cancel or detach on the next read.
   bool blocked_read_completed_ = false;
 
+  // Whether the request should be allowed because of
+  // ContentBrowserClient::GetInitatorSchemeBypassingDocumentBlocking
+  bool is_initiator_scheme_excluded_ = false;
+
+  // Whether |is_initiator_scheme_excluded_| actually prevented blocking from
+  // happening.
+  bool initiator_scheme_prevented_blocking_ = false;
+
   base::WeakPtrFactory<CrossSiteDocumentResourceHandler> weak_this_;
 
   DISALLOW_COPY_AND_ASSIGN(CrossSiteDocumentResourceHandler);
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 5f651b6a..c0948b6 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -313,10 +313,11 @@
 
 // Determines whether it is safe to redirect to |url|.
 bool IsSafeRedirectTarget(const GURL& url, ResourceContext* resource_context) {
-  static base::NoDestructor<std::set<std::string>> kUnsafeSchemes({
-      url::kAboutScheme, url::kDataScheme, url::kFileScheme,
-      url::kFileSystemScheme,
-  });
+  static base::NoDestructor<std::set<std::string>> kUnsafeSchemes(
+      std::set<std::string>({
+          url::kAboutScheme, url::kDataScheme, url::kFileScheme,
+          url::kFileSystemScheme,
+      }));
   return !HasWebUIScheme(url) &&
          kUnsafeSchemes->find(url.scheme()) == kUnsafeSchemes->end() &&
          GetContentClient()->browser()->IsSafeRedirectTarget(url,
diff --git a/content/browser/mach_broker_mac.mm b/content/browser/mach_broker_mac.mm
index 9b0da7da..21d1a5c 100644
--- a/content/browser/mach_broker_mac.mm
+++ b/content/browser/mach_broker_mac.mm
@@ -8,6 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "content/common/content_constants_internal.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/render_process_host.h"
@@ -15,15 +16,6 @@
 
 namespace content {
 
-namespace {
-const char kBootstrapName[] = "rohitfork";
-}
-
-// static
-bool MachBroker::ChildSendTaskPortToParent() {
-  return base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapName);
-}
-
 MachBroker* MachBroker::GetInstance() {
   return base::Singleton<MachBroker,
                          base::LeakySingletonTraits<MachBroker>>::get();
@@ -88,10 +80,10 @@
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
   const bool is_child = command_line->HasSwitch(switches::kProcessType);
-  return base::MachPortBroker::GetMachPortName(kBootstrapName, is_child);
+  return base::MachPortBroker::GetMachPortName(kMachBootstrapName, is_child);
 }
 
-MachBroker::MachBroker() : initialized_(false), broker_(kBootstrapName) {
+MachBroker::MachBroker() : initialized_(false), broker_(kMachBootstrapName) {
   broker_.AddObserver(this);
 }
 
diff --git a/content/browser/mach_broker_mac_unittest.cc b/content/browser/mach_broker_mac_unittest.cc
index 261f500..329ae49 100644
--- a/content/browser/mach_broker_mac_unittest.cc
+++ b/content/browser/mach_broker_mac_unittest.cc
@@ -5,10 +5,12 @@
 #include "content/browser/mach_broker_mac.h"
 
 #include "base/command_line.h"
+#include "base/mac/mach_port_broker.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/multiprocess_test.h"
 #include "base/test/test_timeouts.h"
+#include "content/common/content_constants_internal.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
@@ -77,7 +79,7 @@
 };
 
 MULTIPROCESS_TEST_MAIN(MachBrokerTestChild) {
-  CHECK(MachBroker::ChildSendTaskPortToParent());
+  CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kMachBootstrapName));
   return 0;
 }
 
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h
index 46be85e..254be13 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -148,7 +148,7 @@
 
   bool ForceNewSurfaceForTesting();
 
-  ui::Compositor* GetCompositorForTesting() const;
+  ui::Compositor* GetCompositor() const;
 
  private:
   // ui::LayerObserver implementation:
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 92afcc7..9df94c2b 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -496,7 +496,9 @@
   SetParentUiLayer(nullptr);
 }
 
-ui::Compositor* BrowserCompositorMac::GetCompositorForTesting() const {
+ui::Compositor* BrowserCompositorMac::GetCompositor() const {
+  if (parent_ui_layer_)
+    return parent_ui_layer_->GetCompositor();
   if (recyclable_compositor_)
     return recyclable_compositor_->compositor();
   return nullptr;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 26f7761..4ca6c42 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -43,7 +43,6 @@
 #include "components/viz/client/hit_test_data_provider_draw_quad.h"
 #include "components/viz/client/local_surface_id_provider.h"
 #include "components/viz/common/features.h"
-#include "components/viz/common/gl_helper.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
 #include "components/viz/common/quads/compositor_frame.h"
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc
index a3d18b8..14981ee1 100644
--- a/content/browser/renderer_host/input/fling_browsertest.cc
+++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/viz/common/features.h"
 #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/test/browser_test_utils.h"
@@ -84,13 +83,6 @@
 };
 
 IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchscreenFling) {
-#if defined(OS_MACOSX)
-  // TODO(jonross): Re-enable once fling on Mac works with Viz.
-  // https://crbug.com/842325
-  if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
-    return;
-#endif  // defined(OS_MACOSX)
-
   LoadURL(kBrowserFlingDataURL);
 
   // Send a GSB to start scrolling sequence.
@@ -124,13 +116,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchpadFling) {
-#if defined(OS_MACOSX)
-  // TODO(jonross): Re-enable once fling on Mac works with Viz.
-  // https://crbug.com/842325
-  if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
-    return;
-#endif  // defined(OS_MACOSX)
-
   LoadURL(kBrowserFlingDataURL);
 
   // Send a wheel event to start scrolling sequence.
diff --git a/content/browser/renderer_host/input/fling_scheduler_mac.mm b/content/browser/renderer_host/input/fling_scheduler_mac.mm
index f2ac740b..83959b3e 100644
--- a/content/browser/renderer_host/input/fling_scheduler_mac.mm
+++ b/content/browser/renderer_host/input/fling_scheduler_mac.mm
@@ -21,14 +21,10 @@
   // RWHV_child_frame doesn't have DelegatedFrameHost with ui::Compositor.
   if (host_->GetView()->IsRenderWidgetHostViewChildFrame())
     return nullptr;
-
-  // TODO(sahel): Uncomment this once Viz is ready on Mac.
-  // https://crbug.com/833985
-  /* RenderWidgetHostViewMac* view =
+  RenderWidgetHostViewMac* view =
       static_cast<RenderWidgetHostViewMac*>(host_->GetView());
   if (view->BrowserCompositor())
-    return view->BrowserCompositor()->Compositor();
-  } */
+    return view->BrowserCompositor()->GetCompositor();
 
   return nullptr;
 }
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 5b7eb72..8d3adc64 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -1422,7 +1422,7 @@
     for (MediaStreamDevice& device : request->devices) {
       if (device.type == stream_type &&
           device.session_id == capture_session_id) {
-        CHECK(request->state(device.type) == MEDIA_REQUEST_STATE_OPENING);
+        CHECK_EQ(request->state(device.type), MEDIA_REQUEST_STATE_OPENING);
         // We've found a matching request.
         request->SetState(device.type, MEDIA_REQUEST_STATE_DONE);
 
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index 4a948b2..3b006ff 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -15,7 +15,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
-#include "components/viz/common/gl_helper.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
 #include "content/public/browser/browser_thread.h"
@@ -174,6 +173,9 @@
     result->set_shared_buffer_handle(
         buffer_handle_->get_shared_buffer_handle()->Clone(
             mojo::SharedBufferHandle::AccessMode::READ_WRITE));
+  } else if (buffer_handle_->is_read_only_shmem_region()) {
+    result->set_read_only_shmem_region(
+        buffer_handle_->get_read_only_shmem_region().Duplicate());
   } else if (buffer_handle_->is_mailbox_handles()) {
     result->set_mailbox_handles(buffer_handle_->get_mailbox_handles()->Clone());
   } else {
diff --git a/content/browser/renderer_host/pepper/pepper_gamepad_host.h b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
index cc3bcb581f..3cec62b2 100644
--- a/content/browser/renderer_host/pepper/pepper_gamepad_host.h
+++ b/content/browser/renderer_host/pepper/pepper_gamepad_host.h
@@ -49,11 +49,13 @@
       const IPC::Message& msg,
       ppapi::host::HostMessageContext* context) override;
 
-  // GamepadConsumer implementation.
-  void OnGamepadConnected(unsigned index,
+  // device::GamepadConsumer implementation.
+  void OnGamepadConnected(uint32_t index,
                           const device::Gamepad& gamepad) override {}
-  void OnGamepadDisconnected(unsigned index,
+  void OnGamepadDisconnected(uint32_t index,
                              const device::Gamepad& gamepad) override {}
+  void OnGamepadButtonOrAxisChanged(uint32_t index,
+                                    const device::Gamepad& gamepad) override {}
 
  private:
   int32_t OnRequestMemory(ppapi::host::HostMessageContext* context);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 3dcc6e5c..3eb5677 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -89,6 +89,7 @@
 #include "content/browser/fileapi/fileapi_message_filter.h"
 #include "content/browser/font_unique_name_lookup/font_unique_name_lookup_service.h"
 #include "content/browser/frame_host/render_frame_message_filter.h"
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_client_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
@@ -1465,7 +1466,7 @@
     const uint64_t tracing_id =
         ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(id);
     gpu_client_.reset(new GpuClientImpl(
-        id, tracing_id,
+        std::make_unique<BrowserGpuClientDelegate>(), id, tracing_id,
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)));
   }
 
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index 17b76df4..2df71bf2 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -284,9 +284,6 @@
   // not a WebContents, returns nullptr.
   virtual WebContents* GetAsWebContents();
 
-  // Notifies that a CompositorFrame was received from the renderer.
-  virtual void DidReceiveCompositorFrame() {}
-
   // Gets the size set by a top-level frame with auto-resize enabled.
   virtual gfx::Size GetAutoResizeSize();
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 71a2e09..6d46c37 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -408,8 +408,8 @@
   const auto* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kDisableHangMonitor)) {
     input_event_ack_timeout_.reset(new TimeoutMonitor(
-        base::BindRepeating(&RenderWidgetHostImpl::OnInputEventAckTimeout,
-                            weak_factory_.GetWeakPtr())));
+        base::Bind(&RenderWidgetHostImpl::RendererIsUnresponsive,
+                   weak_factory_.GetWeakPtr())));
   }
 
   if (!command_line->HasSwitch(switches::kDisableNewContentRenderingTimeout)) {
@@ -2086,24 +2086,18 @@
   }
 }
 
-void RenderWidgetHostImpl::OnInputEventAckTimeout() {
-  RendererIsUnresponsive(base::BindRepeating(
-      &RenderWidgetHostImpl::RestartInputEventAckTimeoutIfNecessary,
-      weak_factory_.GetWeakPtr()));
-}
-
-void RenderWidgetHostImpl::RendererIsUnresponsive(
-    base::RepeatingClosure restart_hang_monitor_timeout) {
+void RenderWidgetHostImpl::RendererIsUnresponsive() {
   NotificationService::current()->Notify(
       NOTIFICATION_RENDER_WIDGET_HOST_HANG,
       Source<RenderWidgetHost>(this),
       NotificationService::NoDetails());
   is_unresponsive_ = true;
 
-  if (delegate_) {
-    delegate_->RendererUnresponsive(this,
-                                    std::move(restart_hang_monitor_timeout));
-  }
+  if (delegate_)
+    delegate_->RendererUnresponsive(
+        this, base::BindRepeating(
+                  &RenderWidgetHostImpl::RestartInputEventAckTimeoutIfNecessary,
+                  weak_factory_.GetWeakPtr()));
 
   // Do not add code after this since the Delegate may delete this
   // RenderWidgetHostImpl in RendererUnresponsive.
@@ -2974,9 +2968,6 @@
       }
     }
   }
-
-  if (delegate_)
-    delegate_->DidReceiveCompositorFrame();
 }
 
 void RenderWidgetHostImpl::DidProcessFrame(uint32_t frame_token) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index f475ee2b..0d347cb 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -717,17 +717,6 @@
 
   void GetContentRenderingTimeoutFrom(RenderWidgetHostImpl* other);
 
-  // Called on delayed response from the renderer by either
-  // 1) |hang_monitor_timeout_| (slow to ack input events) or
-  // 2) NavigationHandle::OnCommitTimeout (slow to commit).
-  void RendererIsUnresponsive(
-      base::RepeatingClosure restart_hang_monitor_timeout);
-
-  // Called if we know the renderer is responsive. When we currently think the
-  // renderer is unresponsive, this will clear that state and call
-  // NotifyRendererResponsive.
-  void RendererIsResponsive();
-
  protected:
   // ---------------------------------------------------------------------------
   // The following method is overridden by RenderViewHost to send upwards to
@@ -805,10 +794,18 @@
   // destructor is called as well.
   void Destroy(bool also_delete);
 
+  // Called by |input_event_ack_timeout_| on delayed response from the renderer.
+  void RendererIsUnresponsive();
+
   // Called by |new_content_rendering_timeout_| if a renderer has loaded new
   // content but failed to produce a compositor frame in a defined time.
   void ClearDisplayedGraphics();
 
+  // Called if we know the renderer is responsive. When we currently think the
+  // renderer is unresponsive, this will clear that state and call
+  // NotifyRendererResponsive.
+  void RendererIsResponsive();
+
   // IPC message handlers
   void OnRenderProcessGone(int status, int error_code);
   void OnClose();
@@ -891,10 +888,6 @@
   // was noticed because of input event ack timeout.
   void RestartInputEventAckTimeoutIfNecessary();
 
-  // Called by |input_event_ack_timeout_| when an input event timed out without
-  // getting an ack from the renderer.
-  void OnInputEventAckTimeout();
-
   void SetupInputRouter();
 
   // Start intercepting system keyboard events.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 0eec5c7..881bb211 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -22,7 +22,6 @@
 #include "components/viz/common/features.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/gl_helper.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/bad_message.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 01400ba3..393a084 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -1957,11 +1957,11 @@
 
 TEST_F(RenderWidgetHostViewMacTest, ClearCompositorFrame) {
   BrowserCompositorMac* browser_compositor = rwhv_mac_->BrowserCompositor();
-  ui::Compositor* ui_compositor = browser_compositor->GetCompositorForTesting();
+  ui::Compositor* ui_compositor = browser_compositor->GetCompositor();
   EXPECT_NE(ui_compositor, nullptr);
   EXPECT_TRUE(ui_compositor->IsLocked());
   rwhv_mac_->ClearCompositorFrame();
-  EXPECT_EQ(browser_compositor->GetCompositorForTesting(), ui_compositor);
+  EXPECT_EQ(browser_compositor->GetCompositor(), ui_compositor);
   EXPECT_FALSE(ui_compositor->IsLocked());
 }
 
diff --git a/content/browser/scheduler/responsiveness/native_event_observer.cc b/content/browser/scheduler/responsiveness/native_event_observer.cc
index 5f18b7d..651681a 100644
--- a/content/browser/scheduler/responsiveness/native_event_observer.cc
+++ b/content/browser/scheduler/responsiveness/native_event_observer.cc
@@ -4,6 +4,18 @@
 
 #include "content/browser/scheduler/responsiveness/native_event_observer.h"
 
+#include "ui/events/platform/platform_event_source.h"
+
+#if defined(OS_LINUX)
+#if defined(USE_X11)
+#include "ui/events/platform/x11/x11_event_source.h"  // nogncheck
+#elif defined(USE_OZONE)
+#include "ui/events/event.h"
+#endif
+
+#include "ui/events/platform_event.h"
+#endif
+
 namespace content {
 namespace responsiveness {
 
@@ -20,11 +32,54 @@
 }
 
 #if !defined(OS_MACOSX)
-// TODO(erikchen): Implement this for non-macOS platforms.
+#if defined(OS_LINUX)
+void NativeEventObserver::RegisterObserver() {
+  ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
+}
+void NativeEventObserver::DeregisterObserver() {
+  ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
+}
+
+void NativeEventObserver::WillProcessEvent(const ui::PlatformEvent& event) {
+  will_run_event_callback_.Run(&event);
+}
+
+void NativeEventObserver::DidProcessEvent(const ui::PlatformEvent& event) {
+#if defined(USE_OZONE)
+  did_run_event_callback_.Run(&event, event->time_stamp());
+#elif defined(USE_X11)
+  // X11 uses a uint32_t on the wire protocol. Xlib casts this to an unsigned
+  // long by prepending with 0s. We cast back to a uint32_t so that subtraction
+  // works properly when the timestamp overflows back to 0.
+  uint32_t event_server_time_ms =
+      static_cast<uint32_t>(ui::X11EventSource::GetInstance()->GetTimestamp());
+  uint32_t current_server_time_ms = static_cast<uint32_t>(
+      ui::X11EventSource::GetInstance()->GetCurrentServerTime());
+
+  int32_t delta_ms = current_server_time_ms - event_server_time_ms;
+
+  // If for some reason server time is not monotonically increasing, ignore it.
+  if (delta_ms < 0)
+    delta_ms = 0;
+
+  // Ignore pathologically long deltas. Server is probably having issues.
+  base::TimeDelta delta = base::TimeDelta::FromMilliseconds(delta_ms);
+  base::TimeDelta long_duration = base::TimeDelta::FromSeconds(30);
+  if (delta > long_duration)
+    delta = base::TimeDelta();
+
+  did_run_event_callback_.Run(&event, base::TimeTicks::Now() - delta);
+#else
+#error
+#endif
+}
+#else   // defined(OS_LINUX)
+// TODO(erikchen): Implement this for non-macOS, non-Linux platforms.
 // https://crbug.com/859155.
 void NativeEventObserver::RegisterObserver() {}
 void NativeEventObserver::DeregisterObserver() {}
-#endif
+#endif  // defined(OS_LINUX)
+#endif  // !defined(OS_MACOSX)
 
 }  // namespace responsiveness
 }  // namespace content
diff --git a/content/browser/scheduler/responsiveness/native_event_observer.h b/content/browser/scheduler/responsiveness/native_event_observer.h
index dd4a403..ab2ff65 100644
--- a/content/browser/scheduler/responsiveness/native_event_observer.h
+++ b/content/browser/scheduler/responsiveness/native_event_observer.h
@@ -14,6 +14,10 @@
 #include "content/public/browser/native_event_processor_observer_mac.h"
 #endif
 
+#if defined(OS_LINUX)
+#include "ui/events/platform/platform_event_observer.h"
+#endif
+
 namespace content {
 namespace responsiveness {
 
@@ -31,6 +35,8 @@
 class CONTENT_EXPORT NativeEventObserver
 #if defined(OS_MACOSX)
     : public NativeEventProcessorObserver
+#elif defined(OS_LINUX)
+    : public ui::PlatformEventObserver
 #endif
 {
  public:
@@ -46,7 +52,12 @@
   // processor. The destructor will unregister the object.
   NativeEventObserver(WillRunEventCallback will_run_event_callback,
                       DidRunEventCallback did_run_event_callback);
+
+#if defined(OS_LINUX)
+  ~NativeEventObserver() override;
+#else
   virtual ~NativeEventObserver();
+#endif
 
  protected:
 #if defined(OS_MACOSX)
@@ -55,6 +66,11 @@
   void WillRunNativeEvent(const void* opaque_identifier) override;
   void DidRunNativeEvent(const void* opaque_identifier,
                          base::TimeTicks creation_time) override;
+#elif defined(OS_LINUX)
+  // PlatformEventObserver overrides:
+  // Exposed for tests.
+  void WillProcessEvent(const ui::PlatformEvent& event) override;
+  void DidProcessEvent(const ui::PlatformEvent& event) override;
 #endif
 
  private:
diff --git a/content/browser/service_manager/common_browser_interfaces.cc b/content/browser/service_manager/common_browser_interfaces.cc
index 68e21694..bb155a0 100644
--- a/content/browser/service_manager/common_browser_interfaces.cc
+++ b/content/browser/service_manager/common_browser_interfaces.cc
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "components/discardable_memory/service/discardable_shared_memory_manager.h"
 #include "content/browser/browser_main_loop.h"
+#include "content/browser/gpu/browser_gpu_client_delegate.h"
 #include "content/browser/gpu/gpu_client_impl.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/public/browser/browser_thread.h"
@@ -105,7 +106,8 @@
         ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
             gpu_client_id);
     auto gpu_client = std::make_unique<GpuClientImpl>(
-        gpu_client_id, gpu_client_tracing_id,
+        std::make_unique<BrowserGpuClientDelegate>(), gpu_client_id,
+        gpu_client_tracing_id,
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
     gpu_client->SetConnectionErrorHandler(
         base::BindOnce(&ConnectionFilterImpl::OnGpuConnectionClosed,
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 26dbd2c..76991e6 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -247,7 +247,7 @@
 
   NotificationSource source_;
   NotificationDetails details_;
-  base::RunLoop run_loop_;
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
 };
@@ -268,7 +268,8 @@
     return;
 
   running_ = true;
-  run_loop_.Run();
+  message_loop_runner_ = new MessageLoopRunner;
+  message_loop_runner_->Run();
   EXPECT_TRUE(seen_);
 }
 
@@ -283,7 +284,7 @@
   if (!running_)
     return;
 
-  run_loop_.Quit();
+  message_loop_runner_->Quit();
   running_ = false;
 }
 
@@ -296,7 +297,8 @@
                                  int expected_frame_count)
       : WebContentsObserver(web_contents),
         expected_frame_count_(expected_frame_count),
-        frames_created_(0) {}
+        frames_created_(0),
+        message_loop_runner_(new MessageLoopRunner) {}
 
   ~RenderFrameHostCreatedObserver() override;
 
@@ -314,8 +316,8 @@
   // The number of RenderFrameHosts that have been created.
   int frames_created_;
 
-  // The RunLoop used to spin the message loop.
-  base::RunLoop run_loop_;
+  // The MessageLoopRunner used to spin the message loop.
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
 };
@@ -324,14 +326,14 @@
 }
 
 void RenderFrameHostCreatedObserver::Wait() {
-  run_loop_.Run();
+  message_loop_runner_->Run();
 }
 
 void RenderFrameHostCreatedObserver::RenderFrameCreated(
     RenderFrameHost* render_frame_host) {
   frames_created_++;
   if (frames_created_ == expected_frame_count_) {
-    run_loop_.Quit();
+    message_loop_runner_->Quit();
   }
 }
 
@@ -7183,23 +7185,22 @@
 // Helper class to wait for a ShutdownRequest message to arrive.
 class ShutdownObserver : public RenderProcessHostObserver {
  public:
-  ShutdownObserver() = default;
+  ShutdownObserver() : message_loop_runner_(new MessageLoopRunner) {}
 
   void RenderProcessShutdownRequested(RenderProcessHost* host) override {
     has_received_shutdown_request_ = true;
-    run_loop_.Quit();
+    message_loop_runner_->Quit();
   }
 
-  void Wait() { run_loop_.Run(); }
+  void Wait() { message_loop_runner_->Run(); }
 
   bool has_received_shutdown_request() {
     return has_received_shutdown_request_;
   }
 
  private:
-  base::RunLoop run_loop_;
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
   bool has_received_shutdown_request_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(ShutdownObserver);
 };
 
@@ -7722,7 +7723,8 @@
  public:
   PendingWidgetMessageFilter()
       : BrowserMessageFilter(kMessageClasses, arraysize(kMessageClasses)),
-        routing_id_(MSG_ROUTING_NONE) {}
+        routing_id_(MSG_ROUTING_NONE),
+        message_loop_runner_(new MessageLoopRunner) {}
 
   bool OnMessageReceived(const IPC::Message& message) override {
     bool handled = true;
@@ -7734,7 +7736,9 @@
     return handled;
   }
 
-  void Wait() { run_loop_.Run(); }
+  void Wait() {
+    message_loop_runner_->Run();
+  }
 
   int routing_id() { return routing_id_; }
 
@@ -7760,11 +7764,11 @@
 
   void OnReceivedRoutingIDOnUI(int widget_routing_id) {
     routing_id_ = widget_routing_id;
-    run_loop_.Quit();
+    message_loop_runner_->Quit();
   }
 
   int routing_id_;
-  base::RunLoop run_loop_;
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(PendingWidgetMessageFilter);
 };
@@ -9633,6 +9637,7 @@
  public:
   SetIsInertMessageFilter()
       : content::BrowserMessageFilter(FrameMsgStart),
+        message_loop_runner_(new content::MessageLoopRunner),
         msg_received_(false) {}
 
   bool OnMessageReceived(const IPC::Message& message) override {
@@ -9644,7 +9649,7 @@
 
   bool is_inert() const { return is_inert_; }
 
-  void Wait() { run_loop_.Run(); }
+  void Wait() { message_loop_runner_->Run(); }
 
  private:
   ~SetIsInertMessageFilter() override {}
@@ -9659,10 +9664,10 @@
     is_inert_ = is_inert;
     if (!msg_received_) {
       msg_received_ = true;
-      run_loop_.Quit();
+      message_loop_runner_->Quit();
     }
   }
-  base::RunLoop run_loop_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
   bool msg_received_;
   bool is_inert_;
   DISALLOW_COPY_AND_ASSIGN(SetIsInertMessageFilter);
@@ -12764,12 +12769,13 @@
 // |web_contents|.
 class SameDocumentCommitObserver : public WebContentsObserver {
  public:
-  explicit SameDocumentCommitObserver(WebContents* web_contents)
-      : WebContentsObserver(web_contents) {
+  SameDocumentCommitObserver(WebContents* web_contents)
+      : WebContentsObserver(web_contents),
+        message_loop_runner_(new MessageLoopRunner) {
     EXPECT_TRUE(web_contents);
   }
 
-  void Wait() { run_loop_.Run(); }
+  void Wait() { message_loop_runner_->Run(); }
 
   const GURL& last_committed_url() { return last_committed_url_; }
 
@@ -12777,12 +12783,12 @@
   void DidFinishNavigation(NavigationHandle* navigation_handle) override {
     if (navigation_handle->IsSameDocument()) {
       last_committed_url_ = navigation_handle->GetURL();
-      run_loop_.Quit();
+      message_loop_runner_->Quit();
     }
   }
 
   GURL last_committed_url_;
-  base::RunLoop run_loop_;
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(SameDocumentCommitObserver);
 };
@@ -13020,83 +13026,6 @@
   EXPECT_TRUE(b_process_observer.did_exit_normally());
 }
 
-// This observer waits until WebContentsObserver::OnRendererUnresponsive
-// notification.
-class UnresponsiveRendererObserver : public WebContentsObserver {
- public:
-  explicit UnresponsiveRendererObserver(WebContents* web_contents)
-      : WebContentsObserver(web_contents) {}
-
-  ~UnresponsiveRendererObserver() override {}
-
-  RenderProcessHost* Wait() {
-    if (!captured_render_process_host_)
-      run_loop_.Run();
-    return captured_render_process_host_;
-  }
-
- private:
-  void OnRendererUnresponsive(RenderProcessHost* render_process_host) override {
-    captured_render_process_host_ = render_process_host;
-    run_loop_.Quit();
-  }
-
-  RenderProcessHost* captured_render_process_host_ = nullptr;
-  base::RunLoop run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(UnresponsiveRendererObserver);
-};
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       CommitTimeoutForHungRenderer) {
-  // Navigate first tab to a.com.
-  GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), url));
-  RenderProcessHost* a_process =
-      shell()->web_contents()->GetMainFrame()->GetProcess();
-
-  // Use window.open to open b.com in a second tab.  Using a renderer-initiated
-  // navigation is important to leave a.com and b.com SiteInstances in the same
-  // BrowsingInstance (so the b.com -> a.com navigation in the next test step
-  // will reuse the process associated with the first a.com tab).
-  const char* kWindowOpenScript = R"(
-      var anchor = document.createElement("a");
-      anchor.href = "/cross-site/b.com/title2.html";
-      anchor.target = "_blank";
-      document.body.appendChild(anchor);
-      anchor.click(); )";
-  WebContentsAddedObserver new_window_observer;
-  EXPECT_TRUE(ExecuteScript(shell()->web_contents(), kWindowOpenScript));
-  WebContents* new_window = new_window_observer.GetWebContents();
-  EXPECT_TRUE(WaitForLoadStop(new_window));
-  RenderProcessHost* b_process = new_window->GetMainFrame()->GetProcess();
-  EXPECT_NE(a_process, b_process);
-
-  // Hang the first tab's renderer.
-  const char* kHungScript = "setTimeout(function() { for (;;) {}; }, 0);";
-  EXPECT_TRUE(ExecuteScript(shell()->web_contents(), kHungScript));
-
-  // Attempt to navigate the second tab to a.com.  This will attempt to reuse
-  // the hung process.
-  NavigationHandleImpl::SetCommitTimeoutForTesting(
-      base::TimeDelta::FromMilliseconds(100));
-  const char* kNavigationScript = R"(
-      var anchor = document.createElement("a");
-      anchor.href = "/cross-site/a.com/title3.html";
-      document.body.appendChild(anchor);
-      anchor.click(); )";
-  UnresponsiveRendererObserver unresponsive_renderer_observer(new_window);
-  EXPECT_TRUE(ExecuteScript(new_window, kNavigationScript));
-
-  // Verify that we will be notified about the unresponsive renderer.  Before
-  // changes in https://crrev.com/c/1089797, the test would hang here forever.
-  RenderProcessHost* hung_process = unresponsive_renderer_observer.Wait();
-  EXPECT_EQ(hung_process, a_process);
-
-  // Reset the timeout.
-  NavigationHandleImpl::SetCommitTimeoutForTesting(base::TimeDelta());
-}
-
 // Tests that an inner WebContents will reattach to its outer WebContents after
 // a navigation that causes a process swap.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ProcessSwapOnInnerContents) {
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 16091662..4d758960 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -1340,9 +1340,10 @@
 // Regression test for https://crbug.com/851644. The test passes as long as it
 // doesn't crash.
 // Touch action ack timeout is enabled on Android only.
+// Flaky, see https://crbug.com/871062.
 #if defined(OS_ANDROID)
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       TouchActionAckTimeout) {
+                       DISABLED_TouchActionAckTimeout) {
   GURL main_url(
       embedded_test_server()->GetURL("/frame_tree/page_with_janky_frame.html"));
   ASSERT_TRUE(NavigateToURL(shell(), main_url));
@@ -1882,12 +1883,13 @@
 }
 
 #if defined(USE_AURA)
-IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, RootWindowTransform) {
+IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
+                       DISABLED_RootWindowTransform) {
   HitTestRootWindowTransform(shell(), embedded_test_server());
 }
 
 IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
-                       RootWindowTransform) {
+                       DISABLED_RootWindowTransform) {
   HitTestRootWindowTransform(shell(), embedded_test_server());
 }
 #endif  // defined(USE_AURA)
diff --git a/content/browser/tracing/tracing_controller_browsertest.cc b/content/browser/tracing/tracing_controller_browsertest.cc
index 680c548..2649d7e 100644
--- a/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/content/browser/tracing/tracing_controller_browsertest.cc
@@ -23,6 +23,7 @@
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/test_content_browser_client.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/tracing/public/cpp/trace_event_agent.h"
 
 using base::trace_event::RECORD_CONTINUOUSLY;
@@ -104,7 +105,7 @@
   class TestTracingDelegate : public TracingDelegate {
    public:
     std::unique_ptr<TraceUploader> GetTraceUploader(
-        net::URLRequestContextGetter* request_context) override {
+        scoped_refptr<network::SharedURLLoaderFactory>) override {
       return nullptr;
     }
     MetadataFilterPredicate GetMetadataFilterPredicate() override {
@@ -357,7 +358,13 @@
   std::string last_data_;
 };
 
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_GetCategories DISABLED_GetCategories
+#else
+#define MAYBE_GetCategories GetCategories
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest, MAYBE_GetCategories) {
   Navigate(shell());
 
   TracingController* controller = TracingController::GetInstance();
@@ -372,11 +379,25 @@
   EXPECT_EQ(get_categories_done_callback_count(), 1);
 }
 
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndStopTracing) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracing DISABLED_EnableAndStopTracing
+#else
+#define MAYBE_EnableAndStopTracing EnableAndStopTracing
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest, MAYBE_EnableAndStopTracing) {
   TestStartAndStopTracingString();
 }
 
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, DisableRecordingStoresMetadata) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_DisableRecordingStoresMetadata \
+  DISABLED_DisableRecordingStoresMetadata
+#else
+#define MAYBE_DisableRecordingStoresMetadata DisableRecordingStoresMetadata
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest,
+                       MAYBE_DisableRecordingStoresMetadata) {
   TestStartAndStopTracingString();
   // Check that a number of important keys exist in the metadata dictionary. The
   // values are not checked to ensure the test is robust.
@@ -434,8 +455,15 @@
   EXPECT_TRUE(last_data().find("this_not_found") == std::string::npos);
 }
 
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracingWithFilePath \
+  DISABLED_EnableAndStopTracingWithFilePath
+#else
+#define MAYBE_EnableAndStopTracingWithFilePath EnableAndStopTracingWithFilePath
+#endif
 IN_PROC_BROWSER_TEST_F(TracingControllerTest,
-                       EnableAndStopTracingWithFilePath) {
+                       MAYBE_EnableAndStopTracingWithFilePath) {
   base::FilePath file_path;
   {
     base::ThreadRestrictions::ScopedAllowIO allow_io_for_creating_test_file;
@@ -445,13 +473,29 @@
   EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
 }
 
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracingWithCompression \
+  DISABLED_EnableAndStopTracingWithCompression
+#else
+#define MAYBE_EnableAndStopTracingWithCompression \
+  EnableAndStopTracingWithCompression
+#endif
 IN_PROC_BROWSER_TEST_F(TracingControllerTest,
-                       EnableAndStopTracingWithCompression) {
+                       MAYBE_EnableAndStopTracingWithCompression) {
   TestStartAndStopTracingCompressed();
 }
 
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_EnableAndStopTracingWithEmptyFile \
+  DISABLED_EnableAndStopTracingWithEmptyFile
+#else
+#define MAYBE_EnableAndStopTracingWithEmptyFile \
+  EnableAndStopTracingWithEmptyFile
+#endif
 IN_PROC_BROWSER_TEST_F(TracingControllerTest,
-                       EnableAndStopTracingWithEmptyFile) {
+                       MAYBE_EnableAndStopTracingWithEmptyFile) {
   Navigate(shell());
 
   base::RunLoop run_loop;
@@ -470,7 +514,13 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_F(TracingControllerTest, DoubleStopTracing) {
+// TODO(crbug.com/871770): Disabled for failing on ASAN.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_DoubleStopTracing DISABLED_DoubleStopTracing
+#else
+#define MAYBE_DoubleStopTracing DoubleStopTracing
+#endif
+IN_PROC_BROWSER_TEST_F(TracingControllerTest, MAYBE_DoubleStopTracing) {
   Navigate(shell());
 
   base::RunLoop run_loop;
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index c4da05c..dec9a19 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -242,8 +242,8 @@
 
   trace_uploader_ = delegate_->GetTraceUploader(
       BrowserContext::GetDefaultStoragePartition(
-          web_ui()->GetWebContents()->GetBrowserContext())->
-              GetURLRequestContext());
+          web_ui()->GetWebContents()->GetBrowserContext())
+          ->GetURLLoaderFactoryForBrowserProcess());
   DCHECK(trace_uploader_);
   trace_uploader_->DoUpload(file_contents, upload_mode, nullptr,
                             std::move(progress_callback),
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index df8c751f..580a894 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6572,11 +6572,6 @@
 #endif
 }
 
-void WebContentsImpl::DidReceiveCompositorFrame() {
-  for (auto& observer : observers_)
-    observer.DidReceiveCompositorFrame();
-}
-
 void WebContentsImpl::ShowInsecureLocalhostWarningIfNeeded() {
   bool allow_localhost = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kAllowInsecureLocalhost);
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ad8f130..ebf4bab 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -754,7 +754,6 @@
   bool IsWidgetForMainFrame(RenderWidgetHostImpl* render_widget_host) override;
   bool AddDomainInfoToRapporSample(rappor::Sample* sample) override;
   void FocusedNodeTouched(bool editable) override;
-  void DidReceiveCompositorFrame() override;
   bool IsShowingContextMenuOnPage() const override;
 
   // RenderFrameHostManager::Delegate ------------------------------------------
diff --git a/content/common/content_constants_internal.cc b/content/common/content_constants_internal.cc
index 5cd58371..be2463a 100644
--- a/content/common/content_constants_internal.cc
+++ b/content/common/content_constants_internal.cc
@@ -33,4 +33,8 @@
 
 const char kDoNotTrackHeader[] = "DNT";
 
+#if defined(OS_MACOSX)
+const char kMachBootstrapName[] = "rohitfork";
+#endif
+
 } // namespace content
diff --git a/content/common/content_constants_internal.h b/content/common/content_constants_internal.h
index efd36e6..9c0767b 100644
--- a/content/common/content_constants_internal.h
+++ b/content/common/content_constants_internal.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "build/build_config.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -39,6 +40,11 @@
 // HTTP header set in requests to indicate they should be marked DoNotTrack.
 extern const char kDoNotTrackHeader[];
 
+#if defined(OS_MACOSX)
+// Name of Mach port used for communication between parent and child processes.
+CONTENT_EXPORT extern const char kMachBootstrapName[];
+#endif
+
 } // namespace content
 
 #endif  // CONTENT_COMMON_CONTENT_CONSTANTS_INTERNAL_H_
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index 0d5ff49..25ca97e 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -66,9 +66,9 @@
   // unicode code points. It needs this information frequently so we cache it
   // here.
   std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
-  // For debugging crbug.com/312965
-  base::PlatformThreadId creation_thread_;
   sk_sp<font_service::FontLoader> font_loader_;
+  // For debugging https://crbug.com/312965
+  base::SequenceCheckerImpl creation_thread_sequence_checker_;
 #endif
 };
 
@@ -86,9 +86,7 @@
 
 #elif defined(OS_POSIX)
 
-PpapiBlinkPlatformImpl::SandboxSupport::SandboxSupport()
-    : creation_thread_(base::PlatformThread::CurrentId()) {
-}
+PpapiBlinkPlatformImpl::SandboxSupport::SandboxSupport() {}
 
 void PpapiBlinkPlatformImpl::SandboxSupport::GetFallbackFontForCharacter(
     WebUChar32 character,
@@ -96,7 +94,7 @@
     blink::WebFallbackFont* fallbackFont) {
   ppapi::ProxyLock::AssertAcquired();
   // For debugging crbug.com/312965
-  CHECK_EQ(creation_thread_, base::PlatformThread::CurrentId());
+  CHECK(creation_thread_sequence_checker_.CalledOnValidSequence());
   const std::map<int32_t, blink::WebFallbackFont>::const_iterator iter =
       unicode_font_families_.find(character);
   if (iter != unicode_font_families_.end()) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java
index dd57aba..f1656c4 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java
@@ -112,7 +112,7 @@
 
         mClassificationTask =
                 new ClassificationTask(classifier, requestType, text, start, end, locales);
-        mClassificationTask.execute();
+        mClassificationTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
     }
 
     @TargetApi(Build.VERSION_CODES.O)
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 900e1c3d..2e37d972 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -112,6 +112,11 @@
   return nullptr;
 }
 
+void ContentBrowserClient::LogInitiatorSchemeBypassingDocumentBlocking(
+    const url::Origin& initiator_origin,
+    int render_process_id,
+    ResourceType resource_type) {}
+
 void ContentBrowserClient::GetAdditionalViewSourceSchemes(
     std::vector<std::string>* additional_schemes) {
   GetAdditionalWebUISchemes(additional_schemes);
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 5e35f1d..da7543f 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -296,6 +296,17 @@
   // exceptions should be granted based on initiator's scheme.
   virtual const char* GetInitiatorSchemeBypassingDocumentBlocking();
 
+  // Gives the embedder a chance to log that CORB would have blocked a response
+  // if it wasn't for GetInitatorSchemeBypassingDocumentBlocking above.  Called
+  // only after all the other CORB checks (potentially including sniffing) have
+  // been already run / right before blocking would have otherwise happened (and
+  // only for non-empty, non-4xx responses).
+  // TODO(lukasza): Remove once we gather enough data.
+  virtual void LogInitiatorSchemeBypassingDocumentBlocking(
+      const url::Origin& initiator_origin,
+      int render_process_id,
+      ResourceType resource_type);
+
   // Returns a list additional WebUI schemes, if any.  These additional schemes
   // act as aliases to the chrome: scheme.  The additional schemes may or may
   // not serve specific WebUI pages depending on the particular URLDataSource
diff --git a/content/public/browser/tracing_delegate.h b/content/public/browser/tracing_delegate.h
index 08f6c5b..82af200 100644
--- a/content/public/browser/tracing_delegate.h
+++ b/content/public/browser/tracing_delegate.h
@@ -15,8 +15,8 @@
 class DictionaryValue;
 }
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 namespace content {
@@ -34,7 +34,7 @@
 
   // Provide trace uploading functionality; see trace_uploader.h.
   virtual std::unique_ptr<TraceUploader> GetTraceUploader(
-      net::URLRequestContextGetter* request_context) = 0;
+      scoped_refptr<network::SharedURLLoaderFactory>) = 0;
 
   // This can be used to veto a particular background tracing scenario.
   virtual bool IsAllowedToBeginBackgroundScenario(
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index c10ae50..fcb7fa4 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -517,9 +517,6 @@
   // focus.
   virtual void OnWebContentsLostFocus(RenderWidgetHost* render_widget_host) {}
 
-  // Notifes that a CompositorFrame was received from the renderer.
-  virtual void DidReceiveCompositorFrame() {}
-
   // Notifies that the manifest URL for the main frame changed to
   // |manifest_url|. This will be invoked when a document with a manifest loads
   // or when the manifest URL changes (possibly to nothing). It is not invoked
diff --git a/content/public/browser/web_contents_user_data.h b/content/public/browser/web_contents_user_data.h
index d9a776f..8523f47 100644
--- a/content/public/browser/web_contents_user_data.h
+++ b/content/public/browser/web_contents_user_data.h
@@ -25,9 +25,6 @@
 //   friend class content::WebContentsUserData<FooTabHelper>;
 //   // ... more private stuff here ...
 // }
-// --- in foo_tab_helper.cc ---
-// DEFINE_WEB_CONTENTS_USER_DATA_KEY(FooTabHelper);
-//
 template <typename T>
 class WebContentsUserData : public base::SupportsUserData::Data {
  public:
@@ -58,10 +55,6 @@
   }
 };
 
-// Macro previously used to define the UserDataKey().
-// TODO(fdoray): Remove this. https://crbug.com/589840
-#define DEFINE_WEB_CONTENTS_USER_DATA_KEY(TYPE)
-
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_BROWSER_WEB_CONTENTS_USER_DATA_H_
diff --git a/content/public/browser/webrtc_event_logger.h b/content/public/browser/webrtc_event_logger.h
index 9cecefad..158745d0 100644
--- a/content/public/browser/webrtc_event_logger.h
+++ b/content/public/browser/webrtc_event_logger.h
@@ -54,7 +54,7 @@
   // therefore be careful note to call any of BrowserContext's virtual methods.
   // TODO(eladalon): After changing to a Profile-centered interface, change this
   // to not even receive a pointer. https://crbug.com/775415
-  virtual void DisableForBrowserContext(BrowserContext* browser_context,
+  virtual void DisableForBrowserContext(const BrowserContext* browser_context,
                                         base::OnceClosure reply) = 0;
 
   // Call this to let the logger know when a PeerConnection was created.
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index b022eff1..764ca219 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -171,6 +171,8 @@
     "menu_item.h",
     "mhtml_generation_params.cc",
     "mhtml_generation_params.h",
+    "mime_handler_view_mode.cc",
+    "mime_handler_view_mode.h",
     "notification_resources.cc",
     "notification_resources.h",
     "origin_util.h",
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 3f0ea3c1..6b43766d 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -373,8 +373,8 @@
 
 // Service worker based payment apps as defined by w3c here:
 // https://w3c.github.io/webpayments-payment-apps-api/
-const base::Feature kServiceWorkerPaymentApps{
-    "ServiceWorkerPaymentApps", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kServiceWorkerPaymentApps{"ServiceWorkerPaymentApps",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Generate V8 full code cache of service worker scripts.
 const base::Feature kServiceWorkerScriptFullCodeCache{
@@ -437,13 +437,6 @@
 const base::Feature kUserActivationV2{"UserActivationV2",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Use RenderWidgetHostView::CreateVideoCapturer instead of
-// RenderWidgetHostView::CopyFromSurface to obtain a stream of snapshots
-// captured from the renderer for DevTools performance timeline and eyedropper
-// tool.
-const base::Feature kUseVideoCaptureApiForDevToolsSnapshots{
-    "UseVideoCaptureApiForDevToolsSnapshots", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables to use a snapshot file in creating V8 contexts.
 const base::Feature kV8ContextSnapshot{"V8ContextSnapshot",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
@@ -666,12 +659,6 @@
                                   base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // defined(OS_MACOSX)
 
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
-// Always set the UI thread's priority to DISPLAY.
-const base::Feature kOverrideUIThreadPriority{
-    "OverrideUIThreadPriority", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif  // defined(OS_ANDROID) || defined(OS_CHROMEOS)
-
 enum class VideoCaptureServiceConfiguration {
   kEnabledForOutOfProcess,
   kEnabledForBrowserProcess,
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 5e22f51..5cd76739 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -103,8 +103,6 @@
 CONTENT_EXPORT extern const base::Feature kTouchpadOverscrollHistoryNavigation;
 CONTENT_EXPORT extern const base::Feature kUseFeaturePolicyForPermissions;
 CONTENT_EXPORT extern const base::Feature kUserActivationV2;
-CONTENT_EXPORT extern const base::Feature
-    kUseVideoCaptureApiForDevToolsSnapshots;
 CONTENT_EXPORT extern const base::Feature kV8ContextSnapshot;
 CONTENT_EXPORT extern const base::Feature kV8LowMemoryModeForSubframes;
 CONTENT_EXPORT extern const base::Feature kV8Orinoco;
@@ -156,10 +154,6 @@
 CONTENT_EXPORT extern const base::Feature kWebUIPolymer2;
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
-CONTENT_EXPORT extern const base::Feature kOverrideUIThreadPriority;
-#endif  // defined(OS_ANDROID) || defined(OS_CHROMEOS)
-
 #if defined(OS_MACOSX)
 CONTENT_EXPORT extern const base::Feature kDeviceMonitorMac;
 CONTENT_EXPORT extern const base::Feature kIOSurfaceCapturer;
diff --git a/content/public/common/mime_handler_view_mode.cc b/content/public/common/mime_handler_view_mode.cc
new file mode 100644
index 0000000..e235c62
--- /dev/null
+++ b/content/public/common/mime_handler_view_mode.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/mime_handler_view_mode.h"
+
+#include "content/public/common/content_features.h"
+
+namespace content {
+
+// static
+bool MimeHandlerViewMode::UsesCrossProcessFrame() {
+  return base::FeatureList::IsEnabled(
+      features::kMimeHandlerViewInCrossProcessFrame);
+}
+
+}  // namespace content
diff --git a/content/public/common/mime_handler_view_mode.h b/content/public/common/mime_handler_view_mode.h
new file mode 100644
index 0000000..12cd4c4
--- /dev/null
+++ b/content/public/common/mime_handler_view_mode.h
@@ -0,0 +1,25 @@
+// 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 CONTENT_PUBLIC_COMMON_MIME_HANDLER_VIEW_MODE_H_
+#define CONTENT_PUBLIC_COMMON_MIME_HANDLER_VIEW_MODE_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT MimeHandlerViewMode {
+ public:
+  // Returns true if MimeHandlerViewGuest uses cross-process frames instead of
+  // BrowserPlugin.
+  static bool UsesCrossProcessFrame();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MimeHandlerViewMode);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_COMMON_MIME_HANDLER_VIEW_MODE_H_
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 84ff772..7ea6490 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -24,6 +24,15 @@
   return nullptr;
 }
 
+bool ContentRendererClient::IsPluginHandledByMimeHandlerView(
+    RenderFrame* embedder_frame,
+    const blink::WebElement& owner_element,
+    const GURL& original_url,
+    const std::string& original_mime_type,
+    int32_t instance_id_to_use) {
+  return false;
+}
+
 bool ContentRendererClient::OverrideCreatePlugin(
     RenderFrame* render_frame,
     const blink::WebPluginParams& params,
@@ -114,8 +123,7 @@
                                        const GURL& url,
                                        const std::string& http_method,
                                        bool is_initial_navigation,
-                                       bool is_server_redirect,
-                                       bool* send_referrer) {
+                                       bool is_server_redirect) {
   return false;
 }
 
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index d3762e8e..0aca5928 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -39,6 +39,7 @@
 }
 
 namespace blink {
+class WebElement;
 class WebFrame;
 class WebLocalFrame;
 class WebMIDIAccessor;
@@ -87,6 +88,15 @@
   // none.
   virtual SkBitmap* GetSadWebViewBitmap();
 
+  // Returns true if the embedder renders the contents of the |plugin_element|
+  // in a cross-process frame using MimeHandlerView.
+  virtual bool IsPluginHandledByMimeHandlerView(
+      RenderFrame* embedder_frame,
+      const blink::WebElement& plugin_element,
+      const GURL& original_url,
+      const std::string& original_mime_type,
+      int32_t instance_id_to_use);
+
   // Allows the embedder to override creating a plugin. If it returns true, then
   // |plugin| will contain the created plugin, although it could be NULL. If it
   // returns false, the content layer will create the plugin.
@@ -218,15 +228,11 @@
 #endif
 
   // Returns true if we should fork a new process for the given navigation.
-  // If |send_referrer| is set to false (which is the default), no referrer
-  // header will be send for the navigation. Otherwise, the referrer header is
-  // set according to the frame's referrer policy.
   virtual bool ShouldFork(blink::WebLocalFrame* frame,
                           const GURL& url,
                           const std::string& http_method,
                           bool is_initial_navigation,
-                          bool is_server_redirect,
-                          bool* send_referrer);
+                          bool is_server_redirect);
 
   // Notifies the embedder that the given frame is requesting the resource at
   // |url|. If the function returns a valid |new_url|, the request must be
diff --git a/content/public/test/referrer_unittest.cc b/content/public/test/referrer_unittest.cc
index b272a98..06ee196 100644
--- a/content/public/test/referrer_unittest.cc
+++ b/content/public/test/referrer_unittest.cc
@@ -23,6 +23,14 @@
       Referrer(GURL("http://b"), static_cast<blink::WebReferrerPolicy>(200)))));
 }
 
+TEST(ReferrerSanitizerTest, OnlyHTTPFamilyReferrer) {
+  auto result = Referrer::SanitizeForRequest(
+      GURL("https://a"),
+      Referrer(GURL("chrome-extension://ghbmnnjooekpmoecnnnilnnbdlolhkhi"),
+               blink::kWebReferrerPolicyAlways));
+  EXPECT_TRUE(result.url.is_empty());
+}
+
 TEST(ReferrerTest, BlinkNetRoundTripConversion) {
   const net::URLRequest::ReferrerPolicy policies[] = {
       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 7cf1c5d2..2600551 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -366,6 +366,8 @@
     "media/web_media_element_source_utils.h",
     "media/webrtc/audio_codec_factory.cc",
     "media/webrtc/audio_codec_factory.h",
+    "media/webrtc/fake_rtc_rtp_transceiver.cc",
+    "media/webrtc/fake_rtc_rtp_transceiver.h",
     "media/webrtc/media_stream_remote_video_source.cc",
     "media/webrtc/media_stream_remote_video_source.h",
     "media/webrtc/media_stream_track_metrics.cc",
@@ -570,6 +572,8 @@
     "service_worker/service_worker_network_provider.h",
     "service_worker/service_worker_provider_context.cc",
     "service_worker/service_worker_provider_context.h",
+    "service_worker/service_worker_provider_state_for_client.cc",
+    "service_worker/service_worker_provider_state_for_client.h",
     "service_worker/service_worker_subresource_loader.cc",
     "service_worker/service_worker_subresource_loader.h",
     "service_worker/service_worker_timeout_timer.cc",
diff --git a/content/renderer/indexed_db/indexed_db_callbacks_impl.cc b/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
index 7057e78..839f4b8 100644
--- a/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
+++ b/content/renderer/indexed_db/indexed_db_callbacks_impl.cc
@@ -111,153 +111,21 @@
     int64_t transaction_id,
     const base::WeakPtr<WebIDBCursorImpl>& cursor,
     scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
-    : internal_state_(new InternalState(std::move(callbacks),
-                                        transaction_id,
-                                        cursor,
-                                        callback_runner)),
-      callback_runner_(std::move(callback_runner)) {}
+    : callback_runner_(std::move(callback_runner)),
+      callbacks_(std::move(callbacks)),
+      cursor_(cursor),
+      transaction_id_(transaction_id) {}
 
-IndexedDBCallbacksImpl::~IndexedDBCallbacksImpl() {
-  callback_runner_->DeleteSoon(FROM_HERE, internal_state_);
-}
+IndexedDBCallbacksImpl::~IndexedDBCallbacksImpl() = default;
 
 void IndexedDBCallbacksImpl::Error(int32_t code,
                                    const base::string16& message) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&InternalState::Error, base::Unretained(internal_state_),
-                     code, message));
-}
-
-void IndexedDBCallbacksImpl::SuccessStringList(
-    const std::vector<base::string16>& value) {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&InternalState::SuccessStringList,
-                                base::Unretained(internal_state_), value));
-}
-
-void IndexedDBCallbacksImpl::Blocked(int64_t existing_version) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&InternalState::Blocked, base::Unretained(internal_state_),
-                     existing_version));
-}
-
-void IndexedDBCallbacksImpl::UpgradeNeeded(
-    DatabaseAssociatedPtrInfo database,
-    int64_t old_version,
-    blink::WebIDBDataLoss data_loss,
-    const std::string& data_loss_message,
-    const content::IndexedDBDatabaseMetadata& metadata) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&InternalState::UpgradeNeeded,
-                     base::Unretained(internal_state_), std::move(database),
-                     old_version, data_loss, data_loss_message, metadata));
-}
-
-void IndexedDBCallbacksImpl::SuccessDatabase(
-    DatabaseAssociatedPtrInfo database,
-    const content::IndexedDBDatabaseMetadata& metadata) {
-  callback_runner_->PostTask(FROM_HERE,
-                             base::BindOnce(&InternalState::SuccessDatabase,
-                                            base::Unretained(internal_state_),
-                                            std::move(database), metadata));
-}
-
-void IndexedDBCallbacksImpl::SuccessCursor(
-    indexed_db::mojom::CursorAssociatedPtrInfo cursor,
-    const IndexedDBKey& key,
-    const IndexedDBKey& primary_key,
-    indexed_db::mojom::ValuePtr value) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&InternalState::SuccessCursor,
-                     base::Unretained(internal_state_), std::move(cursor), key,
-                     primary_key, std::move(value)));
-}
-
-void IndexedDBCallbacksImpl::SuccessValue(
-    indexed_db::mojom::ReturnValuePtr value) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&InternalState::SuccessValue,
-                     base::Unretained(internal_state_), std::move(value)));
-}
-
-void IndexedDBCallbacksImpl::SuccessCursorContinue(
-    const IndexedDBKey& key,
-    const IndexedDBKey& primary_key,
-    indexed_db::mojom::ValuePtr value) {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&InternalState::SuccessCursorContinue,
-                                base::Unretained(internal_state_), key,
-                                primary_key, std::move(value)));
-}
-
-void IndexedDBCallbacksImpl::SuccessCursorPrefetch(
-    const std::vector<IndexedDBKey>& keys,
-    const std::vector<IndexedDBKey>& primary_keys,
-    std::vector<indexed_db::mojom::ValuePtr> values) {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&InternalState::SuccessCursorPrefetch,
-                                base::Unretained(internal_state_), keys,
-                                primary_keys, std::move(values)));
-}
-
-void IndexedDBCallbacksImpl::SuccessArray(
-    std::vector<indexed_db::mojom::ReturnValuePtr> values) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&InternalState::SuccessArray,
-                     base::Unretained(internal_state_), std::move(values)));
-}
-
-void IndexedDBCallbacksImpl::SuccessKey(const IndexedDBKey& key) {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&InternalState::SuccessKey,
-                                base::Unretained(internal_state_), key));
-}
-
-void IndexedDBCallbacksImpl::SuccessInteger(int64_t value) {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&InternalState::SuccessInteger,
-                                base::Unretained(internal_state_), value));
-}
-
-void IndexedDBCallbacksImpl::Success() {
-  callback_runner_->PostTask(FROM_HERE,
-                             base::BindOnce(&InternalState::Success,
-                                            base::Unretained(internal_state_)));
-}
-
-IndexedDBCallbacksImpl::InternalState::InternalState(
-    std::unique_ptr<blink::WebIDBCallbacks> callbacks,
-    int64_t transaction_id,
-    const base::WeakPtr<WebIDBCursorImpl>& cursor,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
-    : callbacks_(std::move(callbacks)),
-      transaction_id_(transaction_id),
-      cursor_(cursor),
-      callback_runner_(std::move(callback_runner)) {
-  IndexedDBDispatcher::ThreadSpecificInstance()->RegisterMojoOwnedCallbacks(
-      this);
-}
-
-IndexedDBCallbacksImpl::InternalState::~InternalState() {
-  IndexedDBDispatcher::ThreadSpecificInstance()->UnregisterMojoOwnedCallbacks(
-      this);
-}
-
-void IndexedDBCallbacksImpl::InternalState::Error(
-    int32_t code,
-    const base::string16& message) {
   callbacks_->OnError(
       blink::WebIDBDatabaseError(code, WebString::FromUTF16(message)));
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessStringList(
+void IndexedDBCallbacksImpl::SuccessStringList(
     const std::vector<base::string16>& value) {
   WebVector<WebString> web_value(value.size());
   std::transform(
@@ -267,12 +135,12 @@
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::Blocked(int64_t existing_version) {
+void IndexedDBCallbacksImpl::Blocked(int64_t existing_version) {
   callbacks_->OnBlocked(existing_version);
   // Not resetting |callbacks_|.
 }
 
-void IndexedDBCallbacksImpl::InternalState::UpgradeNeeded(
+void IndexedDBCallbacksImpl::UpgradeNeeded(
     DatabaseAssociatedPtrInfo database_info,
     int64_t old_version,
     blink::WebIDBDataLoss data_loss,
@@ -287,7 +155,7 @@
   // Not resetting |callbacks_|.
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessDatabase(
+void IndexedDBCallbacksImpl::SuccessDatabase(
     DatabaseAssociatedPtrInfo database_info,
     const content::IndexedDBDatabaseMetadata& metadata) {
   WebIDBDatabase* database = nullptr;
@@ -302,7 +170,7 @@
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessCursor(
+void IndexedDBCallbacksImpl::SuccessCursor(
     indexed_db::mojom::CursorAssociatedPtrInfo cursor_info,
     const IndexedDBKey& key,
     const IndexedDBKey& primary_key,
@@ -315,19 +183,13 @@
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessKey(
-    const IndexedDBKey& key) {
-  callbacks_->OnSuccess(WebIDBKeyBuilder::Build(key));
-  callbacks_.reset();
-}
-
-void IndexedDBCallbacksImpl::InternalState::SuccessValue(
+void IndexedDBCallbacksImpl::SuccessValue(
     indexed_db::mojom::ReturnValuePtr value) {
   callbacks_->OnSuccess(ConvertReturnValue(value));
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessCursorContinue(
+void IndexedDBCallbacksImpl::SuccessCursorContinue(
     const IndexedDBKey& key,
     const IndexedDBKey& primary_key,
     indexed_db::mojom::ValuePtr value) {
@@ -337,7 +199,7 @@
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessCursorPrefetch(
+void IndexedDBCallbacksImpl::SuccessCursorPrefetch(
     const std::vector<IndexedDBKey>& keys,
     const std::vector<IndexedDBKey>& primary_keys,
     std::vector<indexed_db::mojom::ValuePtr> values) {
@@ -353,7 +215,7 @@
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessArray(
+void IndexedDBCallbacksImpl::SuccessArray(
     std::vector<indexed_db::mojom::ReturnValuePtr> values) {
   WebVector<WebIDBValue> web_values;
   web_values.reserve(values.size());
@@ -363,12 +225,17 @@
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::SuccessInteger(int64_t value) {
+void IndexedDBCallbacksImpl::SuccessKey(const IndexedDBKey& key) {
+  callbacks_->OnSuccess(WebIDBKeyBuilder::Build(key));
+  callbacks_.reset();
+}
+
+void IndexedDBCallbacksImpl::SuccessInteger(int64_t value) {
   callbacks_->OnSuccess(value);
   callbacks_.reset();
 }
 
-void IndexedDBCallbacksImpl::InternalState::Success() {
+void IndexedDBCallbacksImpl::Success() {
   callbacks_->OnSuccess();
   callbacks_.reset();
 }
diff --git a/content/renderer/indexed_db/indexed_db_callbacks_impl.h b/content/renderer/indexed_db/indexed_db_callbacks_impl.h
index 1f41f85..5cdcbbb 100644
--- a/content/renderer/indexed_db/indexed_db_callbacks_impl.h
+++ b/content/renderer/indexed_db/indexed_db_callbacks_impl.h
@@ -25,51 +25,6 @@
  public:
   enum : int64_t { kNoTransaction = -1 };
 
-  // This class holds the parts of the internal state of IndexedDBCallbacksImpl
-  // that must live on whatever renderer or worker thread the API is used from.
-  class InternalState {
-   public:
-    InternalState(std::unique_ptr<blink::WebIDBCallbacks> callbacks,
-                  int64_t transaction_id,
-                  const base::WeakPtr<WebIDBCursorImpl>& cursor,
-                  scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
-    ~InternalState();
-
-    void Error(int32_t code, const base::string16& message);
-    void SuccessStringList(const std::vector<base::string16>& value);
-    void Blocked(int64_t existing_version);
-    void UpgradeNeeded(indexed_db::mojom::DatabaseAssociatedPtrInfo database,
-                       int64_t old_version,
-                       blink::WebIDBDataLoss data_loss,
-                       const std::string& data_loss_message,
-                       const content::IndexedDBDatabaseMetadata& metadata);
-    void SuccessDatabase(indexed_db::mojom::DatabaseAssociatedPtrInfo database,
-                         const content::IndexedDBDatabaseMetadata& metadata);
-    void SuccessCursor(indexed_db::mojom::CursorAssociatedPtrInfo cursor,
-                       const IndexedDBKey& key,
-                       const IndexedDBKey& primary_key,
-                       indexed_db::mojom::ValuePtr value);
-    void SuccessValue(indexed_db::mojom::ReturnValuePtr value);
-    void SuccessCursorContinue(const IndexedDBKey& key,
-                               const IndexedDBKey& primary_key,
-                               indexed_db::mojom::ValuePtr value);
-    void SuccessCursorPrefetch(const std::vector<IndexedDBKey>& keys,
-                               const std::vector<IndexedDBKey>& primary_keys,
-                               std::vector<indexed_db::mojom::ValuePtr> values);
-    void SuccessArray(std::vector<indexed_db::mojom::ReturnValuePtr> values);
-    void SuccessKey(const IndexedDBKey& key);
-    void SuccessInteger(int64_t value);
-    void Success();
-
-   private:
-    std::unique_ptr<blink::WebIDBCallbacks> callbacks_;
-    int64_t transaction_id_;
-    base::WeakPtr<WebIDBCursorImpl> cursor_;
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
-
-    DISALLOW_COPY_AND_ASSIGN(InternalState);
-  };
-
   static blink::WebIDBValue ConvertValue(
       const indexed_db::mojom::ValuePtr& value);
 
@@ -112,10 +67,10 @@
   void Success() override;
 
  private:
-  // |internal_state_| is owned by the thread on which |callback_runner_|
-  // executes tasks and must be destroyed there.
-  InternalState* internal_state_;
   scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
+  std::unique_ptr<blink::WebIDBCallbacks> callbacks_;
+  base::WeakPtr<WebIDBCursorImpl> cursor_;
+  int64_t transaction_id_;
 
   DISALLOW_COPY_AND_ASSIGN(IndexedDBCallbacksImpl);
 };
diff --git a/content/renderer/indexed_db/indexed_db_database_callbacks_impl.cc b/content/renderer/indexed_db/indexed_db_database_callbacks_impl.cc
index 4ccf2af..813b9e6 100644
--- a/content/renderer/indexed_db/indexed_db_database_callbacks_impl.cc
+++ b/content/renderer/indexed_db/indexed_db_database_callbacks_impl.cc
@@ -21,25 +21,35 @@
 
 namespace content {
 
-namespace {
+IndexedDBDatabaseCallbacksImpl::IndexedDBDatabaseCallbacksImpl(
+    std::unique_ptr<WebIDBDatabaseCallbacks> callbacks)
+    : callbacks_(std::move(callbacks)) {}
 
-void DeleteDatabaseCallbacks(WebIDBDatabaseCallbacks* callbacks) {
-  IndexedDBDispatcher::ThreadSpecificInstance()
-      ->UnregisterMojoOwnedDatabaseCallbacks(callbacks);
-  delete callbacks;
+IndexedDBDatabaseCallbacksImpl::~IndexedDBDatabaseCallbacksImpl() = default;
+
+void IndexedDBDatabaseCallbacksImpl::ForcedClose() {
+  callbacks_->OnForcedClose();
 }
 
-void BuildErrorAndAbort(WebIDBDatabaseCallbacks* callbacks,
-                        int64_t transaction_id,
-                        int32_t code,
-                        const base::string16& message) {
-  callbacks->OnAbort(
+void IndexedDBDatabaseCallbacksImpl::VersionChange(int64_t old_version,
+                                                   int64_t new_version) {
+  callbacks_->OnVersionChange(old_version, new_version);
+}
+
+void IndexedDBDatabaseCallbacksImpl::Abort(int64_t transaction_id,
+                                           int32_t code,
+                                           const base::string16& message) {
+  callbacks_->OnAbort(
       transaction_id,
       blink::WebIDBDatabaseError(code, blink::WebString::FromUTF16(message)));
 }
 
-void BuildObservationsAndNotify(WebIDBDatabaseCallbacks* callbacks,
-                                indexed_db::mojom::ObserverChangesPtr changes) {
+void IndexedDBDatabaseCallbacksImpl::Complete(int64_t transaction_id) {
+  callbacks_->OnComplete(transaction_id);
+}
+
+void IndexedDBDatabaseCallbacksImpl::Changes(
+    indexed_db::mojom::ObserverChangesPtr changes) {
   WebVector<WebIDBObservation> web_observations;
   web_observations.reserve(changes->observations.size());
   for (const auto& observation : changes->observations) {
@@ -64,63 +74,8 @@
             std::move(transaction_pair.second->scope));
   }
 
-  callbacks->OnChanges(observation_index_map, std::move(web_observations),
-                       observer_transactions);
-}
-
-}  // namespace
-
-IndexedDBDatabaseCallbacksImpl::IndexedDBDatabaseCallbacksImpl(
-    std::unique_ptr<WebIDBDatabaseCallbacks> callbacks,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
-    : callback_runner_(std::move(callback_runner)),
-      callbacks_(callbacks.release()) {
-  IndexedDBDispatcher::ThreadSpecificInstance()
-      ->RegisterMojoOwnedDatabaseCallbacks(callbacks_);
-}
-
-IndexedDBDatabaseCallbacksImpl::~IndexedDBDatabaseCallbacksImpl() {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&DeleteDatabaseCallbacks, callbacks_));
-}
-
-void IndexedDBDatabaseCallbacksImpl::ForcedClose() {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&WebIDBDatabaseCallbacks::OnForcedClose,
-                                base::Unretained(callbacks_)));
-}
-
-void IndexedDBDatabaseCallbacksImpl::VersionChange(int64_t old_version,
-                                                   int64_t new_version) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&WebIDBDatabaseCallbacks::OnVersionChange,
-                     base::Unretained(callbacks_), old_version, new_version));
-}
-
-void IndexedDBDatabaseCallbacksImpl::Abort(int64_t transaction_id,
-                                           int32_t code,
-                                           const base::string16& message) {
-  // Indirect through BuildErrorAndAbort because it isn't safe to pass a
-  // WebIDBDatabaseError between threads.
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&BuildErrorAndAbort, base::Unretained(callbacks_),
-                     transaction_id, code, message));
-}
-
-void IndexedDBDatabaseCallbacksImpl::Complete(int64_t transaction_id) {
-  callback_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&WebIDBDatabaseCallbacks::OnComplete,
-                                base::Unretained(callbacks_), transaction_id));
-}
-
-void IndexedDBDatabaseCallbacksImpl::Changes(
-    indexed_db::mojom::ObserverChangesPtr changes) {
-  callback_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&BuildObservationsAndNotify, base::Unretained(callbacks_),
-                     std::move(changes)));
+  callbacks_->OnChanges(observation_index_map, std::move(web_observations),
+                        observer_transactions);
 }
 
 }  // namespace content
diff --git a/content/renderer/indexed_db/indexed_db_database_callbacks_impl.h b/content/renderer/indexed_db/indexed_db_database_callbacks_impl.h
index 13df0fa2..2b36930 100644
--- a/content/renderer/indexed_db/indexed_db_database_callbacks_impl.h
+++ b/content/renderer/indexed_db/indexed_db_database_callbacks_impl.h
@@ -18,8 +18,7 @@
     : public indexed_db::mojom::DatabaseCallbacks {
  public:
   explicit IndexedDBDatabaseCallbacksImpl(
-      std::unique_ptr<blink::WebIDBDatabaseCallbacks> callbacks,
-      scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
+      std::unique_ptr<blink::WebIDBDatabaseCallbacks> callbacks);
   ~IndexedDBDatabaseCallbacksImpl() override;
 
   // indexed_db::mojom::DatabaseCallbacks implementation
@@ -32,8 +31,7 @@
   void Changes(indexed_db::mojom::ObserverChangesPtr changes) override;
 
  private:
-  scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
-  blink::WebIDBDatabaseCallbacks* callbacks_;
+  std::unique_ptr<blink::WebIDBDatabaseCallbacks> callbacks_;
 
   DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseCallbacksImpl);
 };
diff --git a/content/renderer/indexed_db/indexed_db_dispatcher.cc b/content/renderer/indexed_db/indexed_db_dispatcher.cc
index 5af2a9ae..6237adb 100644
--- a/content/renderer/indexed_db/indexed_db_dispatcher.cc
+++ b/content/renderer/indexed_db/indexed_db_dispatcher.cc
@@ -35,10 +35,6 @@
 }
 
 IndexedDBDispatcher::~IndexedDBDispatcher() {
-  in_destructor_ = true;
-  mojo_owned_callback_state_.clear();
-  mojo_owned_database_callback_state_.clear();
-
   g_idb_dispatcher_tls.Pointer()->Set(kDeletedIndexedDBDispatcherMarker);
 }
 
@@ -61,38 +57,6 @@
   delete this;
 }
 
-void IndexedDBDispatcher::RegisterMojoOwnedCallbacks(
-    IndexedDBCallbacksImpl::InternalState* callbacks) {
-  mojo_owned_callback_state_[callbacks] = base::WrapUnique(callbacks);
-}
-
-void IndexedDBDispatcher::UnregisterMojoOwnedCallbacks(
-    IndexedDBCallbacksImpl::InternalState* callbacks) {
-  if (in_destructor_)
-    return;
-
-  auto it = mojo_owned_callback_state_.find(callbacks);
-  DCHECK(it != mojo_owned_callback_state_.end());
-  it->second.release();
-  mojo_owned_callback_state_.erase(it);
-}
-
-void IndexedDBDispatcher::RegisterMojoOwnedDatabaseCallbacks(
-    blink::WebIDBDatabaseCallbacks* callbacks) {
-  mojo_owned_database_callback_state_[callbacks] = base::WrapUnique(callbacks);
-}
-
-void IndexedDBDispatcher::UnregisterMojoOwnedDatabaseCallbacks(
-    blink::WebIDBDatabaseCallbacks* callbacks) {
-  if (in_destructor_)
-    return;
-
-  auto it = mojo_owned_database_callback_state_.find(callbacks);
-  DCHECK(it != mojo_owned_database_callback_state_.end());
-  it->second.release();
-  mojo_owned_database_callback_state_.erase(it);
-}
-
 void IndexedDBDispatcher::RegisterCursor(WebIDBCursorImpl* cursor) {
   DCHECK(!base::ContainsKey(cursors_, cursor));
   cursors_.insert(cursor);
diff --git a/content/renderer/indexed_db/indexed_db_dispatcher.h b/content/renderer/indexed_db/indexed_db_dispatcher.h
index 71ea1cf6..b568519 100644
--- a/content/renderer/indexed_db/indexed_db_dispatcher.h
+++ b/content/renderer/indexed_db/indexed_db_dispatcher.h
@@ -46,40 +46,12 @@
   void ResetCursorPrefetchCaches(int64_t transaction_id,
                                  WebIDBCursorImpl* exception_cursor);
 
-  void RegisterMojoOwnedCallbacks(
-      IndexedDBCallbacksImpl::InternalState* callback_state);
-  void UnregisterMojoOwnedCallbacks(
-      IndexedDBCallbacksImpl::InternalState* callback_state);
-  void RegisterMojoOwnedDatabaseCallbacks(
-      blink::WebIDBDatabaseCallbacks* callback_state);
-  void UnregisterMojoOwnedDatabaseCallbacks(
-      blink::WebIDBDatabaseCallbacks* callback_state);
-
  private:
   FRIEND_TEST_ALL_PREFIXES(IndexedDBDispatcherTest, CursorReset);
   FRIEND_TEST_ALL_PREFIXES(IndexedDBDispatcherTest, CursorTransactionId);
 
-  // Looking up move-only entries in an std::unordered_set and removing them
-  // with out freeing them seems to be impossible so use a map instead so that
-  // the key type can remain a raw pointer.
-  using CallbackStateSet = std::unordered_map<
-      IndexedDBCallbacksImpl::InternalState*,
-      std::unique_ptr<IndexedDBCallbacksImpl::InternalState>>;
-  using DatabaseCallbackStateSet =
-      std::unordered_map<blink::WebIDBDatabaseCallbacks*,
-                         std::unique_ptr<blink::WebIDBDatabaseCallbacks>>;
-
   std::unordered_set<WebIDBCursorImpl*> cursors_;
 
-  // Holds pointers to the worker-thread owned state of IndexedDBCallbacksImpl
-  // and IndexedDBDatabaseCallbacksImpl objects to makes sure that it is
-  // destroyed on thread exit if the Mojo pipe is not yet closed. Otherwise the
-  // object will leak because the thread's task runner is no longer executing
-  // tasks.
-  CallbackStateSet mojo_owned_callback_state_;
-  DatabaseCallbackStateSet mojo_owned_database_callback_state_;
-  bool in_destructor_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcher);
 };
 
diff --git a/content/renderer/indexed_db/webidbfactory_impl.cc b/content/renderer/indexed_db/webidbfactory_impl.cc
index 221045a..403596c 100644
--- a/content/renderer/indexed_db/webidbfactory_impl.cc
+++ b/content/renderer/indexed_db/webidbfactory_impl.cc
@@ -53,7 +53,7 @@
       base::WrapUnique(callbacks), transaction_id, nullptr, task_runner);
   auto database_callbacks_impl =
       std::make_unique<IndexedDBDatabaseCallbacksImpl>(
-          base::WrapUnique(database_callbacks), std::move(task_runner));
+          base::WrapUnique(database_callbacks));
   factory_->Open(GetCallbacksProxy(std::move(callbacks_impl)),
                  GetDatabaseCallbacksProxy(std::move(database_callbacks_impl)),
                  url::Origin(origin), name.Utf16(), version, transaction_id);
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index edf50675..990a11524 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -41,6 +41,10 @@
         InitializeFromSharedMemory(
             std::move(buffer_handle->get_shared_buffer_handle()));
         break;
+      case VideoFrameBufferHandleType::READ_ONLY_SHMEM_REGION:
+        InitializeFromReadOnlyShmemRegion(
+            std::move(buffer_handle->get_read_only_shmem_region()));
+        break;
       case VideoFrameBufferHandleType::SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR:
         NOTREACHED();
         break;
@@ -51,8 +55,10 @@
   }
 
   VideoFrameBufferHandleType buffer_type() const { return buffer_type_; }
-  base::SharedMemory* shared_memory() { return shared_memory_.get(); }
+  base::SharedMemory* shared_memory() const { return shared_memory_.get(); }
   size_t shared_memory_size() const { return shared_memory_size_; }
+  const void* read_only_shmem() const { return read_only_mapping_.memory(); }
+  size_t read_only_shmem_size() const { return read_only_mapping_.size(); }
   const std::vector<gpu::MailboxHolder>& mailbox_holders() const {
     return mailbox_holders_;
   }
@@ -79,6 +85,13 @@
     }
   }
 
+  void InitializeFromReadOnlyShmemRegion(
+      base::ReadOnlySharedMemoryRegion region) {
+    DCHECK(region.IsValid());
+    read_only_mapping_ = region.Map();
+    DCHECK(read_only_mapping_.IsValid());
+  }
+
   void InitializeFromMailbox(
       media::mojom::MailboxBufferHandleSetPtr mailbox_handles) {
     DCHECK_EQ(media::VideoFrame::kMaxPlanes,
@@ -91,11 +104,14 @@
 
   VideoFrameBufferHandleType buffer_type_;
 
-  // Only valid for |buffer_type_ == kSharedMemory|.
+  // Only valid for |buffer_type_ == SHARED_BUFFER_HANDLE|.
   std::unique_ptr<base::SharedMemory> shared_memory_;
   size_t shared_memory_size_;
 
-  // Only valid for |buffer_type_ == kMailboxHolder|.
+  // Only valid for |buffer_type_ == READ_ONLY_SHMEM_REGION|.
+  base::ReadOnlySharedMemoryMapping read_only_mapping_;
+
+  // Only valid for |buffer_type_ == MAILBOX_HANDLES|.
   std::vector<gpu::MailboxHolder> mailbox_holders_;
 
   DISALLOW_COPY_AND_ASSIGN(BufferContext);
@@ -349,6 +365,14 @@
           buffer_context->shared_memory()->handle(),
           0 /* shared_memory_offset */, info->timestamp);
       break;
+    case VideoFrameBufferHandleType::READ_ONLY_SHMEM_REGION:
+      frame = media::VideoFrame::WrapExternalData(
+          static_cast<media::VideoPixelFormat>(info->pixel_format),
+          info->coded_size, info->visible_rect, info->visible_rect.size(),
+          const_cast<uint8_t*>(
+              static_cast<const uint8_t*>(buffer_context->read_only_shmem())),
+          buffer_context->read_only_shmem_size(), info->timestamp);
+      break;
     case VideoFrameBufferHandleType::SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR:
       NOTREACHED();
       break;
@@ -402,7 +426,7 @@
     double consumer_resource_utilization) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
 
-// Subtle race note: It's important that the |buffer| argument be
+// Subtle race note: It's important that the |buffer_context| argument be
 // std::move()'ed to this method and never copied. This is so that the caller,
 // DidFinishConsumingFrame(), does not implicitly retain a reference while it
 // is running the trampoline callback on another thread. This is necessary to
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc
index 634cb052..251e4d7 100644
--- a/content/renderer/media/video_capture_impl_unittest.cc
+++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 
 #include "base/macros.h"
+#include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/shared_memory.h"
 #include "base/test/scoped_task_environment.h"
 #include "content/child/child_process.h"
@@ -146,12 +147,19 @@
   }
 
   void SimulateOnBufferCreated(int buffer_id, const base::SharedMemory& shm) {
-    media::mojom::VideoBufferHandlePtr buffer_handle =
-        media::mojom::VideoBufferHandle::New();
-    buffer_handle->set_shared_buffer_handle(mojo::WrapSharedMemoryHandle(
-        shm.GetReadOnlyHandle(), shm.mapped_size(),
-        mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly));
-    video_capture_impl_->OnNewBuffer(buffer_id, std::move(buffer_handle));
+    video_capture_impl_->OnNewBuffer(
+        buffer_id,
+        media::mojom::VideoBufferHandle::NewSharedBufferHandle(
+            mojo::WrapSharedMemoryHandle(
+                shm.GetReadOnlyHandle(), shm.mapped_size(),
+                mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly)));
+  }
+
+  void SimulateReadOnlyBufferCreated(int buffer_id,
+                                     base::ReadOnlySharedMemoryRegion region) {
+    video_capture_impl_->OnNewBuffer(
+        buffer_id, media::mojom::VideoBufferHandle::NewReadOnlyShmemRegion(
+                       std::move(region)));
   }
 
   void SimulateBufferReceived(int buffer_id, const gfx::Size& size) {
@@ -284,7 +292,7 @@
 }
 
 TEST_F(VideoCaptureImplTest, BufferReceived) {
-  const int kBufferId = 11;
+  const int kArbitraryBufferId = 11;
 
   base::SharedMemory shm;
   const size_t frame_size = media::VideoFrame::AllocationSize(
@@ -296,20 +304,48 @@
   EXPECT_CALL(*this, OnFrameReady(_, _));
   EXPECT_CALL(mock_video_capture_host_, DoStart(_, kSessionId, params_small_));
   EXPECT_CALL(mock_video_capture_host_, Stop(_));
-  EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kBufferId, _))
+  EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kArbitraryBufferId, _))
       .Times(0);
 
   StartCapture(0, params_small_);
-  SimulateOnBufferCreated(kBufferId, shm);
-  SimulateBufferReceived(kBufferId, params_small_.requested_format.frame_size);
+  SimulateOnBufferCreated(kArbitraryBufferId, shm);
+  SimulateBufferReceived(kArbitraryBufferId,
+                         params_small_.requested_format.frame_size);
   StopCapture(0);
-  SimulateBufferDestroyed(kBufferId);
+  SimulateBufferDestroyed(kArbitraryBufferId);
+
+  EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 0);
+}
+
+TEST_F(VideoCaptureImplTest, BufferReceived_ReadOnlyShmemRegion) {
+  const int kArbitraryBufferId = 11;
+
+  const size_t frame_size = media::VideoFrame::AllocationSize(
+      media::PIXEL_FORMAT_I420, params_small_.requested_format.frame_size);
+  base::MappedReadOnlyRegion shm =
+      base::ReadOnlySharedMemoryRegion::Create(frame_size);
+  ASSERT_TRUE(shm.IsValid());
+
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
+  EXPECT_CALL(*this, OnFrameReady(_, _));
+  EXPECT_CALL(mock_video_capture_host_, DoStart(_, kSessionId, params_small_));
+  EXPECT_CALL(mock_video_capture_host_, Stop(_));
+  EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kArbitraryBufferId, _))
+      .Times(0);
+
+  StartCapture(0, params_small_);
+  SimulateReadOnlyBufferCreated(kArbitraryBufferId, std::move(shm.region));
+  SimulateBufferReceived(kArbitraryBufferId,
+                         params_small_.requested_format.frame_size);
+  StopCapture(0);
+  SimulateBufferDestroyed(kArbitraryBufferId);
 
   EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 0);
 }
 
 TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop) {
-  const int kBufferId = 12;
+  const int kArbitraryBufferId = 12;
 
   base::SharedMemory shm;
   const size_t frame_size = media::VideoFrame::AllocationSize(
@@ -321,14 +357,44 @@
   EXPECT_CALL(*this, OnFrameReady(_, _)).Times(0);
   EXPECT_CALL(mock_video_capture_host_, DoStart(_, kSessionId, params_large_));
   EXPECT_CALL(mock_video_capture_host_, Stop(_));
-  EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kBufferId, _));
+  EXPECT_CALL(mock_video_capture_host_,
+              ReleaseBuffer(_, kArbitraryBufferId, _));
 
   StartCapture(0, params_large_);
-  SimulateOnBufferCreated(kBufferId, shm);
+  SimulateOnBufferCreated(kArbitraryBufferId, shm);
   StopCapture(0);
   // A buffer received after StopCapture() triggers an instant ReleaseBuffer().
-  SimulateBufferReceived(kBufferId, params_large_.requested_format.frame_size);
-  SimulateBufferDestroyed(kBufferId);
+  SimulateBufferReceived(kArbitraryBufferId,
+                         params_large_.requested_format.frame_size);
+  SimulateBufferDestroyed(kArbitraryBufferId);
+
+  EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 1);
+}
+
+TEST_F(VideoCaptureImplTest, BufferReceivedAfterStop_ReadOnlyShmemRegion) {
+  const int kArbitraryBufferId = 12;
+
+  const size_t frame_size = media::VideoFrame::AllocationSize(
+      media::PIXEL_FORMAT_I420, params_large_.requested_format.frame_size);
+  base::MappedReadOnlyRegion shm =
+      base::ReadOnlySharedMemoryRegion::Create(frame_size);
+  ASSERT_TRUE(shm.IsValid());
+
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
+  EXPECT_CALL(*this, OnFrameReady(_, _)).Times(0);
+  EXPECT_CALL(mock_video_capture_host_, DoStart(_, kSessionId, params_large_));
+  EXPECT_CALL(mock_video_capture_host_, Stop(_));
+  EXPECT_CALL(mock_video_capture_host_,
+              ReleaseBuffer(_, kArbitraryBufferId, _));
+
+  StartCapture(0, params_large_);
+  SimulateReadOnlyBufferCreated(kArbitraryBufferId, std::move(shm.region));
+  StopCapture(0);
+  // A buffer received after StopCapture() triggers an instant ReleaseBuffer().
+  SimulateBufferReceived(kArbitraryBufferId,
+                         params_large_.requested_format.frame_size);
+  SimulateBufferDestroyed(kArbitraryBufferId);
 
   EXPECT_EQ(mock_video_capture_host_.released_buffer_count(), 1);
 }
@@ -377,7 +443,7 @@
 }
 
 TEST_F(VideoCaptureImplTest, BufferReceivedBeforeOnStarted) {
-  const int kBufferId = 16;
+  const int kArbitraryBufferId = 16;
 
   base::SharedMemory shm;
   const size_t frame_size = media::VideoFrame::AllocationSize(
@@ -387,10 +453,46 @@
   InSequence s;
   EXPECT_CALL(mock_video_capture_host_, DoStart(_, kSessionId, params_small_))
       .WillOnce(DoNothing());
-  EXPECT_CALL(mock_video_capture_host_, ReleaseBuffer(_, kBufferId, _));
+  EXPECT_CALL(mock_video_capture_host_,
+              ReleaseBuffer(_, kArbitraryBufferId, _));
   StartCapture(0, params_small_);
-  SimulateOnBufferCreated(kBufferId, shm);
-  SimulateBufferReceived(kBufferId, params_small_.requested_format.frame_size);
+  SimulateOnBufferCreated(kArbitraryBufferId, shm);
+  SimulateBufferReceived(kArbitraryBufferId,
+                         params_small_.requested_format.frame_size);
+
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
+  EXPECT_CALL(mock_video_capture_host_, RequestRefreshFrame(_));
+  video_capture_impl_->OnStateChanged(media::mojom::VideoCaptureState::STARTED);
+
+  // Additional STARTED will cause RequestRefreshFrame a second time.
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
+  EXPECT_CALL(mock_video_capture_host_, RequestRefreshFrame(_));
+  video_capture_impl_->OnStateChanged(media::mojom::VideoCaptureState::STARTED);
+
+  EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STOPPED));
+  EXPECT_CALL(mock_video_capture_host_, Stop(_));
+  StopCapture(0);
+}
+
+TEST_F(VideoCaptureImplTest,
+       BufferReceivedBeforeOnStarted_ReadOnlyShmemRegion) {
+  const int kArbitraryBufferId = 16;
+
+  const size_t frame_size = media::VideoFrame::AllocationSize(
+      media::PIXEL_FORMAT_I420, params_small_.requested_format.frame_size);
+  base::MappedReadOnlyRegion shm =
+      base::ReadOnlySharedMemoryRegion::Create(frame_size);
+  ASSERT_TRUE(shm.IsValid());
+
+  InSequence s;
+  EXPECT_CALL(mock_video_capture_host_, DoStart(_, kSessionId, params_small_))
+      .WillOnce(DoNothing());
+  EXPECT_CALL(mock_video_capture_host_,
+              ReleaseBuffer(_, kArbitraryBufferId, _));
+  StartCapture(0, params_small_);
+  SimulateReadOnlyBufferCreated(kArbitraryBufferId, std::move(shm.region));
+  SimulateBufferReceived(kArbitraryBufferId,
+                         params_small_.requested_format.frame_size);
 
   EXPECT_CALL(*this, OnStateUpdate(VIDEO_CAPTURE_STATE_STARTED));
   EXPECT_CALL(mock_video_capture_host_, RequestRefreshFrame(_));
diff --git a/content/renderer/media/webrtc/fake_rtc_rtp_transceiver.cc b/content/renderer/media/webrtc/fake_rtc_rtp_transceiver.cc
new file mode 100644
index 0000000..acb9937
--- /dev/null
+++ b/content/renderer/media/webrtc/fake_rtc_rtp_transceiver.cc
@@ -0,0 +1,193 @@
+// 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 "content/renderer/media/webrtc/fake_rtc_rtp_transceiver.h"
+
+namespace content {
+
+blink::WebMediaStreamTrack CreateWebMediaStreamTrack(const std::string& id) {
+  blink::WebMediaStreamSource web_source;
+  web_source.Initialize(blink::WebString::FromUTF8(id),
+                        blink::WebMediaStreamSource::kTypeAudio,
+                        blink::WebString::FromUTF8("audio_track"), false);
+  MediaStreamAudioSource* audio_source = new MediaStreamAudioSource(true);
+  // Takes ownership of |audio_source|.
+  web_source.SetExtraData(audio_source);
+
+  blink::WebMediaStreamTrack web_track;
+  web_track.Initialize(web_source.Id(), web_source);
+  audio_source->ConnectToTrack(web_track);
+  return web_track;
+}
+
+FakeRTCRtpSender::FakeRTCRtpSender(base::Optional<std::string> track_id,
+                                   std::vector<std::string> stream_ids)
+    : track_id_(std::move(track_id)), stream_ids_(std::move(stream_ids)) {}
+
+FakeRTCRtpSender::FakeRTCRtpSender(const FakeRTCRtpSender&) = default;
+
+FakeRTCRtpSender::~FakeRTCRtpSender() {}
+
+FakeRTCRtpSender& FakeRTCRtpSender::operator=(const FakeRTCRtpSender&) =
+    default;
+
+std::unique_ptr<blink::WebRTCRtpSender> FakeRTCRtpSender::ShallowCopy() const {
+  return std::make_unique<FakeRTCRtpSender>(*this);
+}
+
+uintptr_t FakeRTCRtpSender::Id() const {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+blink::WebMediaStreamTrack FakeRTCRtpSender::Track() const {
+  return track_id_ ? CreateWebMediaStreamTrack(*track_id_)
+                   : blink::WebMediaStreamTrack();  // null
+}
+
+blink::WebVector<blink::WebString> FakeRTCRtpSender::StreamIds() const {
+  blink::WebVector<blink::WebString> web_stream_ids(stream_ids_.size());
+  for (size_t i = 0; i < stream_ids_.size(); ++i) {
+    web_stream_ids[i] = blink::WebString::FromUTF8(stream_ids_[i]);
+  }
+  return web_stream_ids;
+}
+
+void FakeRTCRtpSender::ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                                    blink::WebRTCVoidRequest request) {
+  NOTIMPLEMENTED();
+}
+
+std::unique_ptr<blink::WebRTCDTMFSenderHandler>
+FakeRTCRtpSender::GetDtmfSender() const {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+std::unique_ptr<webrtc::RtpParameters> FakeRTCRtpSender::GetParameters() const {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void FakeRTCRtpSender::SetParameters(
+    blink::WebVector<webrtc::RtpEncodingParameters>,
+    webrtc::DegradationPreference,
+    blink::WebRTCVoidRequest) {
+  NOTIMPLEMENTED();
+}
+
+void FakeRTCRtpSender::GetStats(
+    std::unique_ptr<blink::WebRTCStatsReportCallback>) {
+  NOTIMPLEMENTED();
+}
+
+FakeRTCRtpReceiver::FakeRTCRtpReceiver(const std::string& track_id,
+                                       std::vector<std::string> stream_ids)
+    : track_(CreateWebMediaStreamTrack(track_id)),
+      stream_ids_(std::move(stream_ids)) {}
+
+FakeRTCRtpReceiver::FakeRTCRtpReceiver(const FakeRTCRtpReceiver&) = default;
+
+FakeRTCRtpReceiver::~FakeRTCRtpReceiver() {}
+
+FakeRTCRtpReceiver& FakeRTCRtpReceiver::operator=(const FakeRTCRtpReceiver&) =
+    default;
+
+std::unique_ptr<blink::WebRTCRtpReceiver> FakeRTCRtpReceiver::ShallowCopy()
+    const {
+  return std::make_unique<FakeRTCRtpReceiver>(*this);
+}
+
+uintptr_t FakeRTCRtpReceiver::Id() const {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+const blink::WebMediaStreamTrack& FakeRTCRtpReceiver::Track() const {
+  return track_;
+}
+
+blink::WebVector<blink::WebString> FakeRTCRtpReceiver::StreamIds() const {
+  blink::WebVector<blink::WebString> web_stream_ids(stream_ids_.size());
+  for (size_t i = 0; i < stream_ids_.size(); ++i) {
+    web_stream_ids[i] = blink::WebString::FromUTF8(stream_ids_[i]);
+  }
+  return web_stream_ids;
+}
+
+blink::WebVector<std::unique_ptr<blink::WebRTCRtpContributingSource>>
+FakeRTCRtpReceiver::GetSources() {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+void FakeRTCRtpReceiver::GetStats(
+    std::unique_ptr<blink::WebRTCStatsReportCallback>) {
+  NOTIMPLEMENTED();
+}
+
+FakeRTCRtpTransceiver::FakeRTCRtpTransceiver(
+    base::Optional<std::string> mid,
+    FakeRTCRtpSender sender,
+    FakeRTCRtpReceiver receiver,
+    bool stopped,
+    webrtc::RtpTransceiverDirection direction,
+    base::Optional<webrtc::RtpTransceiverDirection> current_direction)
+    : mid_(std::move(mid)),
+      sender_(std::move(sender)),
+      receiver_(std::move(receiver)),
+      stopped_(stopped),
+      direction_(std::move(direction)),
+      current_direction_(std::move(current_direction)) {}
+
+FakeRTCRtpTransceiver::~FakeRTCRtpTransceiver() {}
+
+blink::WebRTCRtpTransceiverImplementationType
+FakeRTCRtpTransceiver::ImplementationType() const {
+  return blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver;
+}
+
+uintptr_t FakeRTCRtpTransceiver::Id() const {
+  NOTIMPLEMENTED();
+  return 0u;
+}
+
+blink::WebString FakeRTCRtpTransceiver::Mid() const {
+  return mid_ ? blink::WebString::FromUTF8(*mid_) : blink::WebString();
+}
+
+std::unique_ptr<blink::WebRTCRtpSender> FakeRTCRtpTransceiver::Sender() const {
+  return sender_.ShallowCopy();
+}
+
+std::unique_ptr<blink::WebRTCRtpReceiver> FakeRTCRtpTransceiver::Receiver()
+    const {
+  return receiver_.ShallowCopy();
+}
+
+bool FakeRTCRtpTransceiver::Stopped() const {
+  return stopped_;
+}
+
+webrtc::RtpTransceiverDirection FakeRTCRtpTransceiver::Direction() const {
+  return direction_;
+}
+
+void FakeRTCRtpTransceiver::SetDirection(
+    webrtc::RtpTransceiverDirection direction) {
+  NOTIMPLEMENTED();
+}
+
+base::Optional<webrtc::RtpTransceiverDirection>
+FakeRTCRtpTransceiver::CurrentDirection() const {
+  return current_direction_;
+}
+
+base::Optional<webrtc::RtpTransceiverDirection>
+FakeRTCRtpTransceiver::FiredDirection() const {
+  NOTIMPLEMENTED();
+  return base::nullopt;
+}
+
+}  // namespace content
diff --git a/content/renderer/media/webrtc/fake_rtc_rtp_transceiver.h b/content/renderer/media/webrtc/fake_rtc_rtp_transceiver.h
new file mode 100644
index 0000000..7f8dbfed6
--- /dev/null
+++ b/content/renderer/media/webrtc/fake_rtc_rtp_transceiver.h
@@ -0,0 +1,111 @@
+// 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 CONTENT_RENDERER_MEDIA_WEBRTC_FAKE_RTC_RTP_TRANSCEIVER_H_
+#define CONTENT_RENDERER_MEDIA_WEBRTC_FAKE_RTC_RTP_TRANSCEIVER_H_
+
+#include <memory>
+
+#include "content/renderer/media/stream/media_stream_audio_source.h"
+#include "third_party/blink/public/platform/web_media_constraints.h"
+#include "third_party/blink/public/platform/web_media_stream_source.h"
+#include "third_party/blink/public/platform/web_media_stream_track.h"
+#include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_contributing_source.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_receiver.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_sender.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_transceiver.h"
+
+namespace content {
+
+// TODO(https://crbug.com/868868): Similar methods to this exist in many content
+// unittests. Move to a separate file and reuse it in all of them.
+blink::WebMediaStreamTrack CreateWebMediaStreamTrack(const std::string& id);
+
+class CONTENT_EXPORT FakeRTCRtpSender : public blink::WebRTCRtpSender {
+ public:
+  FakeRTCRtpSender(base::Optional<std::string> track_id,
+                   std::vector<std::string> stream_ids);
+  FakeRTCRtpSender(const FakeRTCRtpSender&);
+  ~FakeRTCRtpSender() override;
+  FakeRTCRtpSender& operator=(const FakeRTCRtpSender&);
+
+  std::unique_ptr<blink::WebRTCRtpSender> ShallowCopy() const override;
+  uintptr_t Id() const override;
+  blink::WebMediaStreamTrack Track() const override;
+  blink::WebVector<blink::WebString> StreamIds() const override;
+  void ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                    blink::WebRTCVoidRequest request) override;
+  std::unique_ptr<blink::WebRTCDTMFSenderHandler> GetDtmfSender()
+      const override;
+  std::unique_ptr<webrtc::RtpParameters> GetParameters() const override;
+  void SetParameters(blink::WebVector<webrtc::RtpEncodingParameters>,
+                     webrtc::DegradationPreference,
+                     blink::WebRTCVoidRequest) override;
+  void GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>) override;
+
+ private:
+  base::Optional<std::string> track_id_;
+  std::vector<std::string> stream_ids_;
+};
+
+class CONTENT_EXPORT FakeRTCRtpReceiver : public blink::WebRTCRtpReceiver {
+ public:
+  FakeRTCRtpReceiver(const std::string& track_id,
+                     std::vector<std::string> stream_ids);
+  FakeRTCRtpReceiver(const FakeRTCRtpReceiver&);
+  ~FakeRTCRtpReceiver() override;
+  FakeRTCRtpReceiver& operator=(const FakeRTCRtpReceiver&);
+
+  std::unique_ptr<blink::WebRTCRtpReceiver> ShallowCopy() const override;
+  uintptr_t Id() const override;
+  const blink::WebMediaStreamTrack& Track() const override;
+  blink::WebVector<blink::WebString> StreamIds() const override;
+  blink::WebVector<std::unique_ptr<blink::WebRTCRtpContributingSource>>
+  GetSources() override;
+  void GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>) override;
+
+ private:
+  blink::WebMediaStreamTrack track_;
+  std::vector<std::string> stream_ids_;
+};
+
+class CONTENT_EXPORT FakeRTCRtpTransceiver
+    : public blink::WebRTCRtpTransceiver {
+ public:
+  FakeRTCRtpTransceiver(
+      base::Optional<std::string> mid,
+      FakeRTCRtpSender sender,
+      FakeRTCRtpReceiver receiver,
+      bool stopped,
+      webrtc::RtpTransceiverDirection direction,
+      base::Optional<webrtc::RtpTransceiverDirection> current_direction);
+  ~FakeRTCRtpTransceiver() override;
+
+  blink::WebRTCRtpTransceiverImplementationType ImplementationType()
+      const override;
+  uintptr_t Id() const override;
+  blink::WebString Mid() const override;
+  std::unique_ptr<blink::WebRTCRtpSender> Sender() const override;
+  std::unique_ptr<blink::WebRTCRtpReceiver> Receiver() const override;
+  bool Stopped() const override;
+  webrtc::RtpTransceiverDirection Direction() const override;
+  void SetDirection(webrtc::RtpTransceiverDirection direction) override;
+  base::Optional<webrtc::RtpTransceiverDirection> CurrentDirection()
+      const override;
+  base::Optional<webrtc::RtpTransceiverDirection> FiredDirection()
+      const override;
+
+ private:
+  base::Optional<std::string> mid_;
+  FakeRTCRtpSender sender_;
+  FakeRTCRtpReceiver receiver_;
+  bool stopped_;
+  webrtc::RtpTransceiverDirection direction_;
+  base::Optional<webrtc::RtpTransceiverDirection> current_direction_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_FAKE_RTC_RTP_TRANSCEIVER_H_
diff --git a/content/renderer/media/webrtc/peer_connection_tracker.cc b/content/renderer/media/webrtc/peer_connection_tracker.cc
index 2feba296..4566c247 100644
--- a/content/renderer/media/webrtc/peer_connection_tracker.cc
+++ b/content/renderer/media/webrtc/peer_connection_tracker.cc
@@ -87,53 +87,109 @@
   return result.str();
 }
 
-static std::string SerializeMediaStreamComponent(
-    const blink::WebMediaStreamTrack& component) {
-  return component.Source().Id().Utf8();
-}
-
 static std::string SerializeMediaStreamIds(
     const blink::WebVector<blink::WebString>& stream_ids) {
   if (!stream_ids.size())
     return "[]";
-  std::string result = "[ ";
+  std::string result = "[";
   for (const auto& stream_id : stream_ids) {
     if (result.size() > 2u)
-      result += ", ";
-    result += stream_id.Utf8();
+      result += ",";
+    result += "'" + stream_id.Utf8() + "'";
   }
-  result += " ]";
+  result += "]";
+  return result;
+}
+
+static const char* SerializeDirection(
+    webrtc::RtpTransceiverDirection direction) {
+  switch (direction) {
+    case webrtc::RtpTransceiverDirection::kSendRecv:
+      return "'sendrecv'";
+    case webrtc::RtpTransceiverDirection::kSendOnly:
+      return "'sendonly'";
+    case webrtc::RtpTransceiverDirection::kRecvOnly:
+      return "'recvonly'";
+    case webrtc::RtpTransceiverDirection::kInactive:
+      return "'inactive'";
+  }
+}
+
+static const char* SerializeOptionalDirection(
+    const base::Optional<webrtc::RtpTransceiverDirection>& direction) {
+  return direction ? SerializeDirection(*direction) : "null";
+}
+
+static std::string SerializeSender(const std::string& indent,
+                                   const blink::WebRTCRtpSender& sender) {
+  std::string result = "{\n";
+  // track:'id',
+  result += indent + "  track:";
+  if (sender.Track().IsNull()) {
+    result += "null";
+  } else {
+    result += "'" + sender.Track().Source().Id().Utf8() + "'";
+  }
+  result += ",\n";
+  // streams:['id,'id'],
+  result += indent +
+            "  streams:" + SerializeMediaStreamIds(sender.StreamIds()) + ",\n";
+  result += indent + "}";
+  return result;
+}
+
+static std::string SerializeReceiver(const std::string& indent,
+                                     const blink::WebRTCRtpReceiver& receiver) {
+  std::string result = "{\n";
+  // track:'id',
+  DCHECK(!receiver.Track().IsNull());
+  result +=
+      indent + "  track:'" + receiver.Track().Source().Id().Utf8() + "',\n";
+  // streams:['id,'id'],
+  result += indent +
+            "  streams:" + SerializeMediaStreamIds(receiver.StreamIds()) +
+            ",\n";
+  result += indent + "}";
   return result;
 }
 
 static std::string SerializeTransceiver(
-    const blink::WebRTCRtpSender* sender,
-    const blink::WebRTCRtpReceiver* receiver) {
-  DCHECK(sender || receiver);
-  std::string result;
-  if (sender && receiver)
-    result += "{ ";
-  if (sender) {
-    result += "sender: { ";
-    if (sender->Track().IsNull())
-      result += "track: null";
+    const blink::WebRTCRtpTransceiver& transceiver) {
+  if (transceiver.ImplementationType() ==
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver) {
+    std::string result = "{\n";
+    // mid:'foo',
+    if (transceiver.Mid().IsNull())
+      result += "  mid:null,\n";
     else
-      result += "track: " + SerializeMediaStreamComponent(sender->Track());
-    result += ", streams: " + SerializeMediaStreamIds(sender->StreamIds());
-    result += " }";
+      result += "  mid:'" + transceiver.Mid().Utf8() + "',\n";
+    // sender:{...},
+    result +=
+        "  sender:" + SerializeSender("  ", *transceiver.Sender()) + ",\n";
+    // receiver:{...},
+    result += "  receiver:" + SerializeReceiver("  ", *transceiver.Receiver()) +
+              ",\n";
+    // stopped:false,
+    result += "  stopped:" +
+              std::string(SerializeBoolean(transceiver.Stopped())) + ",\n";
+    // direction:'sendrecv',
+    result += "  direction:" +
+              std::string(SerializeDirection(transceiver.Direction())) + ",\n";
+    // currentDirection:null,
+    result += "  currentDirection:" +
+              std::string(
+                  SerializeOptionalDirection(transceiver.CurrentDirection())) +
+              ",\n";
+    result += "}";
+    return result;
   }
-  if (receiver) {
-    if (sender)
-      result += ", ";
-    result += "receiver: { ";
-    DCHECK(!receiver->Track().IsNull());
-    result += "track: " + SerializeMediaStreamComponent(receiver->Track());
-    result += ", streams: " + SerializeMediaStreamIds(receiver->StreamIds());
-    result += " }";
-    if (sender)
-      result += " }";
+  if (transceiver.ImplementationType() ==
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly) {
+    return SerializeSender("", *transceiver.Sender());
   }
-  return result;
+  DCHECK(transceiver.ImplementationType() ==
+         blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+  return SerializeReceiver("", *transceiver.Receiver());
 }
 
 static const char* SerializeIceTransportType(
@@ -289,10 +345,14 @@
 static const char* GetTransceiverUpdatedReasonString(
     PeerConnectionTracker::TransceiverUpdatedReason reason) {
   switch (reason) {
+    case PeerConnectionTracker::TransceiverUpdatedReason::kAddTransceiver:
+      return "addTransceiver";
     case PeerConnectionTracker::TransceiverUpdatedReason::kAddTrack:
       return "addTrack";
     case PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack:
       return "removeTrack";
+    case PeerConnectionTracker::TransceiverUpdatedReason::kSetLocalDescription:
+      return "setLocalDescription";
     case PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription:
       return "setRemoteDescription";
   }
@@ -652,50 +712,70 @@
 void PeerConnectionTracker::TrackAddTransceiver(
     RTCPeerConnectionHandler* pc_handler,
     PeerConnectionTracker::TransceiverUpdatedReason reason,
-    const blink::WebRTCRtpSender* sender,
-    const blink::WebRTCRtpReceiver* receiver) {
-  TrackTransceiver("Added", pc_handler, reason, sender, receiver);
+    const blink::WebRTCRtpTransceiver& transceiver,
+    size_t transceiver_index) {
+  TrackTransceiver("Added", pc_handler, reason, transceiver, transceiver_index);
 }
 
 void PeerConnectionTracker::TrackModifyTransceiver(
     RTCPeerConnectionHandler* pc_handler,
     PeerConnectionTracker::TransceiverUpdatedReason reason,
-    const blink::WebRTCRtpSender* sender,
-    const blink::WebRTCRtpReceiver* receiver) {
-  TrackTransceiver("Modified", pc_handler, reason, sender, receiver);
+    const blink::WebRTCRtpTransceiver& transceiver,
+    size_t transceiver_index) {
+  TrackTransceiver("Modified", pc_handler, reason, transceiver,
+                   transceiver_index);
 }
 
 void PeerConnectionTracker::TrackRemoveTransceiver(
     RTCPeerConnectionHandler* pc_handler,
     PeerConnectionTracker::TransceiverUpdatedReason reason,
-    const blink::WebRTCRtpSender* sender,
-    const blink::WebRTCRtpReceiver* receiver) {
-  TrackTransceiver("Removed", pc_handler, reason, sender, receiver);
+    const blink::WebRTCRtpTransceiver& transceiver,
+    size_t transceiver_index) {
+  TrackTransceiver("Removed", pc_handler, reason, transceiver,
+                   transceiver_index);
 }
 
 void PeerConnectionTracker::TrackTransceiver(
     const char* callback_type_ending,
     RTCPeerConnectionHandler* pc_handler,
     PeerConnectionTracker::TransceiverUpdatedReason reason,
-    const blink::WebRTCRtpSender* sender,
-    const blink::WebRTCRtpReceiver* receiver) {
+    const blink::WebRTCRtpTransceiver& transceiver,
+    size_t transceiver_index) {
   DCHECK(main_thread_.CalledOnValidThread());
   int id = GetLocalIDForHandler(pc_handler);
   if (id == -1)
     return;
   std::string callback_type;
-  if (sender && receiver)
+  if (transceiver.ImplementationType() ==
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver) {
     callback_type = "transceiver";
-  else if (sender)
+  } else if (transceiver.ImplementationType() ==
+             blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly) {
     callback_type = "sender";
-  else
+  } else {
     callback_type = "receiver";
+  }
   callback_type += callback_type_ending;
-  callback_type += " (";
-  callback_type += GetTransceiverUpdatedReasonString(reason);
-  callback_type += ")";
-  SendPeerConnectionUpdate(id, callback_type,
-                           SerializeTransceiver(sender, receiver));
+
+  std::string result;
+  result += "Caused by: ";
+  result += GetTransceiverUpdatedReasonString(reason);
+  result += "\n\n";
+  if (transceiver.ImplementationType() ==
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver) {
+    result += "getTransceivers()";
+  } else if (transceiver.ImplementationType() ==
+             blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly) {
+    result += "getSenders()";
+  } else {
+    DCHECK_EQ(
+        transceiver.ImplementationType(),
+        blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+    result += "getReceivers()";
+  }
+  result += "[" + base::UintToString(transceiver_index) + "]:";
+  result += SerializeTransceiver(transceiver);
+  SendPeerConnectionUpdate(id, callback_type, result);
 }
 
 void PeerConnectionTracker::TrackCreateDataChannel(
diff --git a/content/renderer/media/webrtc/peer_connection_tracker.h b/content/renderer/media/webrtc/peer_connection_tracker.h
index 0aeac83..24e0fd85 100644
--- a/content/renderer/media/webrtc/peer_connection_tracker.h
+++ b/content/renderer/media/webrtc/peer_connection_tracker.h
@@ -16,8 +16,7 @@
 #include "ipc/ipc_platform_file.h"
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/platform/web_rtc_peer_connection_handler_client.h"
-#include "third_party/blink/public/platform/web_rtc_rtp_receiver.h"
-#include "third_party/blink/public/platform/web_rtc_rtp_sender.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_transceiver.h"
 #include "third_party/blink/public/platform/web_rtc_session_description.h"
 #include "third_party/webrtc/api/peerconnectioninterface.h"
 
@@ -65,12 +64,11 @@
   // In Plan B: "Transceiver" refers to RTCRtpSender or RTCRtpReceiver.
   // In Unified Plan: "Transceiver" refers to RTCRtpTransceiver.
   enum class TransceiverUpdatedReason {
+    kAddTransceiver,
     kAddTrack,
     kRemoveTrack,
+    kSetLocalDescription,
     kSetRemoteDescription,
-    // TODO(hbos): When we have RTCRtpTransceiver support, this list should be
-    // expanded to include kAddTransceiver and kSetLocalDescription.
-    // https://crbug.com/777617
   };
 
   // RenderThreadObserver implementation.
@@ -129,26 +127,31 @@
       Source source,
       bool succeeded);
 
-  // Sends an update when a transceiver is added, modified or removed, which
-  // for example can happen on addTrack() or setRemoteDescription().
-  // In Plan B: "Transceiver" refers to RTCRtpSender or RTCRtpReceiver.
-  // In Unified Plan: "Transceiver" refers to RTCRtpTransceiver.
-  // TODO(hbos): When we support transceivers, take blink::WebRTCRtpTransceiver
-  // as the argument. https://crbug.com/777617
-  virtual void TrackAddTransceiver(RTCPeerConnectionHandler* pc_handler,
-                                   TransceiverUpdatedReason reason,
-                                   const blink::WebRTCRtpSender* sender,
-                                   const blink::WebRTCRtpReceiver* receiver);
-  virtual void TrackModifyTransceiver(RTCPeerConnectionHandler* pc_handler,
-                                      TransceiverUpdatedReason reason,
-                                      const blink::WebRTCRtpSender* sender,
-                                      const blink::WebRTCRtpReceiver* receiver);
+  // Sends an update when a transceiver is added, modified or removed. This can
+  // happen as a result of any of the methods indicated by |reason|.
+  // In Plan B: |transceiver| refers to its Sender() or Receiver() depending on
+  // ImplementationType(). Example events: "senderAdded", "receiverRemoved".
+  // In Plan B: |transceiver| has a fully implemented ImplementationType().
+  // Example events: "transceiverAdded", "transceiverModified".
+  // See peer_connection_tracker_unittest.cc for expected resulting event
+  // strings.
+  virtual void TrackAddTransceiver(
+      RTCPeerConnectionHandler* pc_handler,
+      TransceiverUpdatedReason reason,
+      const blink::WebRTCRtpTransceiver& transceiver,
+      size_t transceiver_index);
+  virtual void TrackModifyTransceiver(
+      RTCPeerConnectionHandler* pc_handler,
+      TransceiverUpdatedReason reason,
+      const blink::WebRTCRtpTransceiver& transceiver,
+      size_t transceiver_index);
   // TODO(hbos): When Plan B is removed this is no longer applicable.
   // https://crbug.com/857004
-  virtual void TrackRemoveTransceiver(RTCPeerConnectionHandler* pc_handler,
-                                      TransceiverUpdatedReason reason,
-                                      const blink::WebRTCRtpSender* sender,
-                                      const blink::WebRTCRtpReceiver* receiver);
+  virtual void TrackRemoveTransceiver(
+      RTCPeerConnectionHandler* pc_handler,
+      TransceiverUpdatedReason reason,
+      const blink::WebRTCRtpTransceiver& transceiver,
+      size_t transceiver_index);
 
   // Sends an update when a DataChannel is created.
   virtual void TrackCreateDataChannel(
@@ -207,8 +210,8 @@
   void TrackTransceiver(const char* callback_type_ending,
                         RTCPeerConnectionHandler* pc_handler,
                         PeerConnectionTracker::TransceiverUpdatedReason reason,
-                        const blink::WebRTCRtpSender* sender,
-                        const blink::WebRTCRtpReceiver* receiver);
+                        const blink::WebRTCRtpTransceiver& transceiver,
+                        size_t transceiver_index);
 
   // IPC Message handler for getting all stats.
   void OnGetAllStats();
diff --git a/content/renderer/media/webrtc/peer_connection_tracker_unittest.cc b/content/renderer/media/webrtc/peer_connection_tracker_unittest.cc
index 647a646..8486597 100644
--- a/content/renderer/media/webrtc/peer_connection_tracker_unittest.cc
+++ b/content/renderer/media/webrtc/peer_connection_tracker_unittest.cc
@@ -8,6 +8,7 @@
 #include "content/common/media/peer_connection_tracker.mojom.h"
 #include "content/common/media/peer_connection_tracker_messages.h"
 #include "content/public/test/mock_render_thread.h"
+#include "content/renderer/media/webrtc/fake_rtc_rtp_transceiver.h"
 #include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc/mock_web_rtc_peer_connection_handler_client.h"
 #include "content/renderer/media/webrtc/rtc_peer_connection_handler.h"
@@ -18,11 +19,42 @@
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_media_constraints.h"
 #include "third_party/blink/public/platform/web_rtc_offer_options.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_receiver.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_sender.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_transceiver.h"
 
 using ::testing::_;
 
 namespace content {
 
+const char* kDefaultTransceiverString =
+    "getTransceivers()[0]:{\n"
+    "  mid:null,\n"
+    "  sender:{\n"
+    "    track:'senderTrackId',\n"
+    "    streams:['senderStreamId'],\n"
+    "  },\n"
+    "  receiver:{\n"
+    "    track:'receiverTrackId',\n"
+    "    streams:['receiverStreamId'],\n"
+    "  },\n"
+    "  stopped:false,\n"
+    "  direction:'sendonly',\n"
+    "  currentDirection:null,\n"
+    "}";
+
+const char* kDefaultSenderString =
+    "getSenders()[0]:{\n"
+    "  track:'senderTrackId',\n"
+    "  streams:['senderStreamId'],\n"
+    "}";
+
+const char* kDefaultReceiverString =
+    "getReceivers()[0]:{\n"
+    "  track:'receiverTrackId',\n"
+    "  streams:['receiverStreamId'],\n"
+    "}";
+
 class MockPeerConnectionTrackerHost : public mojom::PeerConnectionTrackerHost {
  public:
   MockPeerConnectionTrackerHost() : binding_(this) {}
@@ -47,7 +79,41 @@
   mojo::AssociatedBinding<mojom::PeerConnectionTrackerHost> binding_;
 };
 
+// Creates a transceiver that is expected to be logged as
+// |kDefaultTransceiverString|, |kDefaultSenderString| or
+// |kDefaultReceiverString| depending on if |implementation_type| refers to a
+// fully implemented, sender-only or receiver-only transceiver.
+//
+// This is used in unittests that don't care about the specific attributes of
+// the transceiver.
+std::unique_ptr<blink::WebRTCRtpTransceiver> CreateDefaultTransceiver(
+    blink::WebRTCRtpTransceiverImplementationType implementation_type) {
+  std::unique_ptr<blink::WebRTCRtpTransceiver> transceiver;
+  FakeRTCRtpSender sender("senderTrackId", {"senderStreamId"});
+  FakeRTCRtpReceiver receiver("receiverTrackId", {"receiverStreamId"});
+  if (implementation_type ==
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver) {
+    transceiver = std::make_unique<FakeRTCRtpTransceiver>(
+        base::nullopt, std::move(sender), std::move(receiver),
+        false /* stopped */,
+        webrtc::RtpTransceiverDirection::kSendOnly /* direction */,
+        base::nullopt /* current_direction */);
+  } else if (implementation_type ==
+             blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly) {
+    transceiver = std::make_unique<RTCRtpSenderOnlyTransceiver>(
+        std::make_unique<FakeRTCRtpSender>(sender));
+  } else {
+    DCHECK_EQ(
+        implementation_type,
+        blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+    transceiver = std::make_unique<RTCRtpReceiverOnlyTransceiver>(
+        std::make_unique<FakeRTCRtpReceiver>(receiver));
+  }
+  return transceiver;
+}
+
 namespace {
+
 class MockSendTargetThread : public MockRenderThread {
  public:
   MOCK_METHOD1(OnAddPeerConnection, void(PeerConnectionInfo));
@@ -66,6 +132,7 @@
   return handled;
 }
 
+// TODO(https://crbug.com/868868): Move this into a separate file.
 class MockPeerConnectionHandler : public RTCPeerConnectionHandler {
  public:
   MockPeerConnectionHandler()
@@ -81,8 +148,30 @@
 };
 
 class PeerConnectionTrackerTest : public ::testing::Test {
- private:
+ public:
+  void CreateTrackerWithMocks() {
+    mock_host_.reset(new MockPeerConnectionTrackerHost());
+    tracker_.reset(
+        new PeerConnectionTracker(mock_host_->CreateInterfacePtrAndBind()));
+    target_thread_.reset(new MockSendTargetThread());
+    tracker_->OverrideSendTargetForTesting(target_thread_.get());
+  }
+
+  void CreateAndRegisterPeerConnectionHandler() {
+    mock_handler_.reset(new MockPeerConnectionHandler());
+    EXPECT_CALL(*target_thread_, OnAddPeerConnection(_));
+    tracker_->RegisterPeerConnection(
+        mock_handler_.get(),
+        webrtc::PeerConnectionInterface::RTCConfiguration(),
+        blink::WebMediaConstraints(), nullptr);
+  }
+
+ protected:
   base::MessageLoop message_loop_;
+  std::unique_ptr<MockPeerConnectionTrackerHost> mock_host_;
+  std::unique_ptr<PeerConnectionTracker> tracker_;
+  std::unique_ptr<MockSendTargetThread> target_thread_;
+  std::unique_ptr<MockPeerConnectionHandler> mock_handler_;
 };
 
 }  // namespace
@@ -92,47 +181,258 @@
 }
 
 TEST_F(PeerConnectionTrackerTest, TrackCreateOffer) {
-  MockPeerConnectionTrackerHost mock_peer_connection_tracker_host;
-  PeerConnectionTracker tracker(
-      mock_peer_connection_tracker_host.CreateInterfacePtrAndBind());
-  // mojom::PeerConnectionTrackerHostAssociatedPtr
-  // mock_peer_connection_tracker_host_ptr_
-  //  = mock_peer_connection_tracker_host.CreateInterfacePtrAndBind();
-  // tracker.SetPeerConnectionTrackerHostForTesting(std::move(ptr1));
-  // Note: blink::WebRTCOfferOptions is not mockable. So we can't write
-  // tests for anything but a null options parameter.
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  // Note: blink::WebRTCOfferOptions is not mockable. So we can't write tests
+  // for anything but a null options parameter.
   blink::WebRTCOfferOptions options(0, 0, false, false);
-  // Initialization stuff. This can be separated into a test class.
-  MockPeerConnectionHandler pc_handler;
-  MockSendTargetThread target_thread;
-  webrtc::PeerConnectionInterface::RTCConfiguration config;
-  blink::WebMediaConstraints constraints;
-  tracker.OverrideSendTargetForTesting(&target_thread);
-  EXPECT_CALL(target_thread, OnAddPeerConnection(_));
-  tracker.RegisterPeerConnection(&pc_handler, config, constraints, nullptr);
-  // Back to the test.
-  EXPECT_CALL(mock_peer_connection_tracker_host,
+  EXPECT_CALL(*mock_host_,
               UpdatePeerConnection(
                   _, "createOffer",
                   "options: {offerToReceiveVideo: 0, offerToReceiveAudio: 0, "
                   "voiceActivityDetection: false, iceRestart: false}"));
-  tracker.TrackCreateOffer(&pc_handler, options);
+  tracker_->TrackCreateOffer(mock_handler_.get(), options);
   base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(PeerConnectionTrackerTest, OnSuspend) {
-  PeerConnectionTracker tracker;
-  // Initialization stuff.
-  MockPeerConnectionHandler pc_handler;
-  MockSendTargetThread target_thread;
-  webrtc::PeerConnectionInterface::RTCConfiguration config;
-  blink::WebMediaConstraints constraints;
-  tracker.OverrideSendTargetForTesting(&target_thread);
-  EXPECT_CALL(target_thread, OnAddPeerConnection(_));
-  tracker.RegisterPeerConnection(&pc_handler, config, constraints, nullptr);
-  EXPECT_CALL(pc_handler, CloseClientPeerConnection());
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  EXPECT_CALL(*mock_handler_, CloseClientPeerConnection());
   std::unique_ptr<IPC::Message> message(new PeerConnectionTracker_OnSuspend());
-  tracker.OnControlMessageReceived(*message.get());
+  tracker_->OnControlMessageReceived(*message.get());
+}
+
+TEST_F(PeerConnectionTrackerTest, AddTransceiverWithOptionalValuesPresent) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  FakeRTCRtpTransceiver transceiver(
+      "midValue", FakeRTCRtpSender("senderTrackId", {"streamIdA", "streamIdB"}),
+      FakeRTCRtpReceiver("receiverTrackId", {"streamIdC"}), true /* stopped */,
+      webrtc::RtpTransceiverDirection::kSendRecv /* direction */,
+      webrtc::RtpTransceiverDirection::kInactive /* current_direction */);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "transceiverAdded", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackAddTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kAddTrack, transceiver,
+      0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: addTrack\n"
+      "\n"
+      "getTransceivers()[0]:{\n"
+      "  mid:'midValue',\n"
+      "  sender:{\n"
+      "    track:'senderTrackId',\n"
+      "    streams:['streamIdA','streamIdB'],\n"
+      "  },\n"
+      "  receiver:{\n"
+      "    track:'receiverTrackId',\n"
+      "    streams:['streamIdC'],\n"
+      "  },\n"
+      "  stopped:true,\n"
+      "  direction:'sendrecv',\n"
+      "  currentDirection:'inactive',\n"
+      "}",
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, AddTransceiverWithOptionalValuesNull) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  FakeRTCRtpTransceiver transceiver(
+      base::nullopt, FakeRTCRtpSender(base::nullopt, {}),
+      FakeRTCRtpReceiver("receiverTrackId", {}), false /* stopped */,
+      webrtc::RtpTransceiverDirection::kInactive /* direction */,
+      base::nullopt /* current_direction */);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "transceiverAdded", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackAddTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kAddTransceiver,
+      transceiver, 1u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: addTransceiver\n"
+      "\n"
+      "getTransceivers()[1]:{\n"
+      "  mid:null,\n"
+      "  sender:{\n"
+      "    track:null,\n"
+      "    streams:[],\n"
+      "  },\n"
+      "  receiver:{\n"
+      "    track:'receiverTrackId',\n"
+      "    streams:[],\n"
+      "  },\n"
+      "  stopped:false,\n"
+      "  direction:'inactive',\n"
+      "  currentDirection:null,\n"
+      "}",
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, ModifyTransceiver) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto transceiver = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "transceiverModified", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackModifyTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetLocalDescription,
+      *transceiver, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setLocalDescription\n"
+      "\n" +
+          std::string(kDefaultTransceiverString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, RemoveTransceiver) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto transceiver = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "transceiverRemoved", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackRemoveTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack,
+      *transceiver, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: removeTrack\n"
+      "\n" +
+          std::string(kDefaultTransceiverString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, AddSender) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto sender_only = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "senderAdded", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackAddTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetLocalDescription,
+      *sender_only, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setLocalDescription\n"
+      "\n" +
+          std::string(kDefaultSenderString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, ModifySender) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto sender_only = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "senderModified", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackModifyTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
+      *sender_only, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setRemoteDescription\n"
+      "\n" +
+          std::string(kDefaultSenderString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, RemoveSender) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto sender_only = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "senderRemoved", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackRemoveTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
+      *sender_only, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setRemoteDescription\n"
+      "\n" +
+          std::string(kDefaultSenderString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, AddReceiver) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto receiver_only = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "receiverAdded", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackAddTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
+      *receiver_only, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setRemoteDescription\n"
+      "\n" +
+          std::string(kDefaultReceiverString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, ModifyReceiver) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto receiver_only = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "receiverModified", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackModifyTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
+      *receiver_only, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setRemoteDescription\n"
+      "\n" +
+          std::string(kDefaultReceiverString),
+      update_value);
+}
+
+TEST_F(PeerConnectionTrackerTest, RemoveReceiver) {
+  CreateTrackerWithMocks();
+  CreateAndRegisterPeerConnectionHandler();
+  auto receiver_only = CreateDefaultTransceiver(
+      blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+  std::string update_value;
+  EXPECT_CALL(*mock_host_, UpdatePeerConnection(_, "receiverRemoved", _))
+      .WillOnce(testing::SaveArg<2>(&update_value));
+  tracker_->TrackRemoveTransceiver(
+      mock_handler_.get(),
+      PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
+      *receiver_only, 0u);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(
+      "Caused by: setRemoteDescription\n"
+      "\n" +
+          std::string(kDefaultReceiverString),
+      update_value);
 }
 
 // TODO(hta): Write tests for the other tracking functions.
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index f6a87784..6e95055e 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -644,11 +644,10 @@
 }
 
 bool IsRemoteStream(
-    const std::map<uintptr_t, std::unique_ptr<RTCRtpReceiver>>& rtp_receivers,
+    const std::vector<std::unique_ptr<RTCRtpReceiver>>& rtp_receivers,
     const std::string& stream_id) {
-  for (const auto& receiver_entry : rtp_receivers) {
-    for (const auto& receiver_stream_id :
-         receiver_entry.second->state().stream_ids()) {
+  for (const auto& receiver : rtp_receivers) {
+    for (const auto& receiver_stream_id : receiver->state().stream_ids()) {
       if (stream_id == receiver_stream_id)
         return true;
     }
@@ -808,8 +807,8 @@
     std::vector<RTCRtpReceiver*> removed_receivers;
     for (auto it = handler_->rtp_receivers_.begin();
          it != handler_->rtp_receivers_.end(); ++it) {
-      if (ReceiverWasRemoved(*it->second, states.transceiver_states))
-        removed_receivers.push_back(it->second.get());
+      if (ReceiverWasRemoved(*(*it), states.transceiver_states))
+        removed_receivers.push_back(it->get());
     }
 
     // Process the addition of remote receivers/tracks.
@@ -826,10 +825,13 @@
   }
 
   bool ReceiverWasAdded(const RtpTransceiverState& transceiver_state) {
-    return !base::ContainsKey(
-        handler_->rtp_receivers_,
-        RTCRtpReceiver::getId(
-            transceiver_state.receiver_state()->webrtc_receiver().get()));
+    uintptr_t receiver_id = RTCRtpReceiver::getId(
+        transceiver_state.receiver_state()->webrtc_receiver().get());
+    for (const auto& receiver : handler_->rtp_receivers_) {
+      if (receiver->Id() == receiver_id)
+        return false;
+    }
+    return true;
   }
 
   bool ReceiverWasRemoved(
@@ -1666,8 +1668,6 @@
   auto transceiver_state = std::move(transceiver_states[0]);
 
   std::unique_ptr<blink::WebRTCRtpTransceiver> web_transceiver;
-  const blink::WebRTCRtpSender* web_sender = nullptr;
-  const blink::WebRTCRtpReceiver* web_receiver = nullptr;
   if (sdp_semantics_ == blink::WebRTCSdpSemantics::kPlanB) {
     // Plan B: Create sender only.
     DCHECK(transceiver_state.sender_state());
@@ -1678,21 +1678,19 @@
     DCHECK(sender_state.is_initialized());
     rtp_senders_.push_back(std::make_unique<RTCRtpSender>(
         native_peer_connection_, track_adapter_map_, std::move(sender_state)));
-    web_sender = rtp_senders_.back().get();
     web_transceiver = std::make_unique<RTCRtpSenderOnlyTransceiver>(
-        rtp_senders_.back()->ShallowCopy());
+        std::make_unique<RTCRtpSender>(*rtp_senders_.back().get()));
   } else {
     DCHECK_EQ(sdp_semantics_, blink::WebRTCSdpSemantics::kUnifiedPlan);
     // Unified Plan: Create or recycle a transceiver.
     auto transceiver = CreateOrUpdateTransceiver(std::move(transceiver_state));
-    web_sender = transceiver->content_sender();
-    web_receiver = transceiver->content_receiver();
     web_transceiver = std::move(transceiver);
   }
   if (peer_connection_tracker_) {
+    size_t transceiver_index = GetTransceiverIndex(*web_transceiver.get());
     peer_connection_tracker_->TrackAddTransceiver(
         this, PeerConnectionTracker::TransceiverUpdatedReason::kAddTrack,
-        web_sender, web_receiver);
+        *web_transceiver.get(), transceiver_index);
   }
   for (const auto& stream_id : rtp_senders_.back()->state().stream_ids()) {
     if (GetLocalStreamUsageCount(rtp_senders_, stream_id) == 1u) {
@@ -1765,9 +1763,13 @@
                              MediaStreamTrackMetricsKind(web_track),
                              web_track.Id().Utf8());
   if (peer_connection_tracker_) {
+    auto sender_only_transceiver =
+        std::make_unique<RTCRtpSenderOnlyTransceiver>(
+            std::make_unique<RTCRtpSender>(*it->get()));
+    size_t sender_index = GetTransceiverIndex(*sender_only_transceiver);
     peer_connection_tracker_->TrackRemoveTransceiver(
         this, PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack,
-        (*it).get(), nullptr);
+        *sender_only_transceiver.get(), sender_index);
   }
   std::vector<std::string> stream_ids = (*it)->state().stream_ids();
   rtp_senders_.erase(it);
@@ -1814,8 +1816,14 @@
   DCHECK_EQ(transceiver_states.size(), 1u);
   auto transceiver_state = std::move(transceiver_states[0]);
 
-  // Return the update transceiver state.
+  // Update the transceiver.
   auto transceiver = CreateOrUpdateTransceiver(std::move(transceiver_state));
+  if (peer_connection_tracker_) {
+    size_t transceiver_index = GetTransceiverIndex(*transceiver);
+    peer_connection_tracker_->TrackModifyTransceiver(
+        this, PeerConnectionTracker::TransceiverUpdatedReason::kRemoveTrack,
+        *transceiver.get(), transceiver_index);
+  }
   std::unique_ptr<blink::WebRTCRtpTransceiver> web_transceiver =
       std::move(transceiver);
   return web_transceiver;
@@ -2038,18 +2046,19 @@
   }
   uintptr_t receiver_id =
       RTCRtpReceiver::getId(receiver_state.webrtc_receiver().get());
-  DCHECK(rtp_receivers_.find(receiver_id) == rtp_receivers_.end());
-  const std::unique_ptr<RTCRtpReceiver>& rtp_receiver =
-      rtp_receivers_
-          .insert(std::make_pair(receiver_id, std::make_unique<RTCRtpReceiver>(
-                                                  native_peer_connection_,
-                                                  std::move(receiver_state))))
-          .first->second;
+  DCHECK(FindReceiver(receiver_id) == rtp_receivers_.end());
+  auto rtp_receiver = std::make_unique<RTCRtpReceiver>(
+      native_peer_connection_, std::move(receiver_state));
+  rtp_receivers_.push_back(std::make_unique<RTCRtpReceiver>(*rtp_receiver));
   if (peer_connection_tracker_) {
+    auto receiver_only_transceiver =
+        std::make_unique<RTCRtpReceiverOnlyTransceiver>(
+            std::make_unique<RTCRtpReceiver>(*rtp_receiver));
+    size_t receiver_index = GetTransceiverIndex(*receiver_only_transceiver);
     peer_connection_tracker_->TrackAddTransceiver(
         this,
         PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
-        nullptr, rtp_receiver.get());
+        *receiver_only_transceiver.get(), receiver_index);
   }
   if (!is_closed_)
     client_->DidAddReceiverPlanB(rtp_receiver->ShallowCopy());
@@ -2059,20 +2068,24 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnRemoveReceiverPlanB");
 
-  auto it = rtp_receivers_.find(receiver_id);
+  auto it = FindReceiver(receiver_id);
   DCHECK(it != rtp_receivers_.end());
-  auto receiver = it->second->ShallowCopy();
-  rtp_receivers_.erase(it);
+  auto receiver = std::make_unique<RTCRtpReceiver>(*(*it));
   // Update metrics.
   track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
                              MediaStreamTrackMetricsKind(receiver->Track()),
                              receiver->Track().Id().Utf8());
   if (peer_connection_tracker_) {
+    auto receiver_only_transceiver =
+        std::make_unique<RTCRtpReceiverOnlyTransceiver>(
+            std::make_unique<RTCRtpReceiver>(*receiver));
+    size_t receiver_index = GetTransceiverIndex(*receiver_only_transceiver);
     peer_connection_tracker_->TrackRemoveTransceiver(
         this,
         PeerConnectionTracker::TransceiverUpdatedReason::kSetRemoteDescription,
-        nullptr /* sender */, receiver.get() /* receiver */);
+        *receiver_only_transceiver.get(), receiver_index);
   }
+  rtp_receivers_.erase(it);
   for (const auto& stream_id : receiver->state().stream_ids()) {
     // This was the last occurence of the stream?
     if (!IsRemoteStream(rtp_receivers_, stream_id))
@@ -2088,13 +2101,47 @@
   DCHECK_EQ(sdp_semantics_, blink::WebRTCSdpSemantics::kUnifiedPlan);
   std::vector<std::unique_ptr<blink::WebRTCRtpTransceiver>> web_transceivers(
       transceiver_states.size());
+  PeerConnectionTracker::TransceiverUpdatedReason update_reason =
+      !is_remote_description ? PeerConnectionTracker::TransceiverUpdatedReason::
+                                   kSetLocalDescription
+                             : PeerConnectionTracker::TransceiverUpdatedReason::
+                                   kSetRemoteDescription;
   for (size_t i = 0; i < transceiver_states.size(); ++i) {
-    // TODO(hbos): Figure out if a transceiver was added, modified, removed or
-    // stayed the same and use the |peer_connection_tracker_| to track
-    // transceiver updates for debugging aid in chrome://webrtc-internals.
-    // https://crbug.com/864912
+    // Figure out if this transceiver is new or if setting the state modified
+    // the transceiver such that it should be logged by the
+    // |peer_connection_tracker_|.
+    uintptr_t transceiver_id = RTCRtpTransceiver::GetId(
+        transceiver_states[i].webrtc_transceiver().get());
+    auto it = FindTransceiver(transceiver_id);
+    bool transceiver_is_new = (it == rtp_transceivers_.end());
+    bool transceiver_was_modified = false;
+    if (!transceiver_is_new) {
+      const auto& previous_state = (*it)->state();
+      transceiver_was_modified =
+          previous_state.mid() != transceiver_states[i].mid() ||
+          previous_state.stopped() != transceiver_states[i].stopped() ||
+          previous_state.direction() != transceiver_states[i].direction() ||
+          previous_state.current_direction() !=
+              transceiver_states[i].current_direction();
+    }
+
+    // Update the transceiver.
     web_transceivers[i] =
         CreateOrUpdateTransceiver(std::move(transceiver_states[i]));
+
+    // Log a "transcieverAdded" or "transceiverModified" event in
+    // chrome://webrtc-internals if new or modified.
+    if (peer_connection_tracker_ &&
+        (transceiver_is_new || transceiver_was_modified)) {
+      size_t transceiver_index = GetTransceiverIndex(*web_transceivers[i]);
+      if (transceiver_is_new) {
+        peer_connection_tracker_->TrackAddTransceiver(
+            this, update_reason, *web_transceivers[i].get(), transceiver_index);
+      } else if (transceiver_was_modified) {
+        peer_connection_tracker_->TrackModifyTransceiver(
+            this, update_reason, *web_transceivers[i].get(), transceiver_index);
+      }
+    }
   }
   if (!is_closed_) {
     client_->DidModifyTransceivers(std::move(web_transceivers),
@@ -2203,6 +2250,15 @@
   return rtp_senders_.end();
 }
 
+std::vector<std::unique_ptr<RTCRtpReceiver>>::iterator
+RTCPeerConnectionHandler::FindReceiver(uintptr_t id) {
+  for (auto it = rtp_receivers_.begin(); it != rtp_receivers_.end(); ++it) {
+    if ((*it)->Id() == id)
+      return it;
+  }
+  return rtp_receivers_.end();
+}
+
 std::vector<std::unique_ptr<RTCRtpTransceiver>>::iterator
 RTCPeerConnectionHandler::FindTransceiver(uintptr_t id) {
   for (auto it = rtp_transceivers_.begin(); it != rtp_transceivers_.end();
@@ -2213,6 +2269,35 @@
   return rtp_transceivers_.end();
 }
 
+size_t RTCPeerConnectionHandler::GetTransceiverIndex(
+    const blink::WebRTCRtpTransceiver& web_transceiver) {
+  if (web_transceiver.ImplementationType() ==
+      blink::WebRTCRtpTransceiverImplementationType::kFullTransceiver) {
+    for (size_t i = 0; i < rtp_transceivers_.size(); ++i) {
+      if (web_transceiver.Id() == rtp_transceivers_[i]->Id())
+        return i;
+    }
+  } else if (web_transceiver.ImplementationType() ==
+             blink::WebRTCRtpTransceiverImplementationType::kPlanBSenderOnly) {
+    const auto web_sender = web_transceiver.Sender();
+    for (size_t i = 0; i < rtp_senders_.size(); ++i) {
+      if (web_sender->Id() == rtp_senders_[i]->Id())
+        return i;
+    }
+  } else {
+    RTC_DCHECK(
+        web_transceiver.ImplementationType() ==
+        blink::WebRTCRtpTransceiverImplementationType::kPlanBReceiverOnly);
+    const auto web_receiver = web_transceiver.Receiver();
+    for (size_t i = 0; i < rtp_receivers_.size(); ++i) {
+      if (web_receiver->Id() == rtp_receivers_[i]->Id())
+        return i;
+    }
+  }
+  NOTREACHED();
+  return 0u;
+}
+
 std::unique_ptr<RTCRtpTransceiver>
 RTCPeerConnectionHandler::CreateOrUpdateTransceiver(
     RtpTransceiverState transceiver_state) {
@@ -2234,18 +2319,19 @@
     rtp_transceivers_.push_back(transceiver->ShallowCopy());
     DCHECK(FindSender(RTCRtpSender::getId(webrtc_sender.get())) ==
            rtp_senders_.end());
-    rtp_senders_.push_back(transceiver->content_sender()->ShallowCopy());
-    uintptr_t receiver_id = RTCRtpReceiver::getId(webrtc_receiver.get());
-    DCHECK(rtp_receivers_.find(receiver_id) == rtp_receivers_.end());
-    rtp_receivers_.insert(std::make_pair(
-        receiver_id, transceiver->content_receiver()->ShallowCopy()));
+    rtp_senders_.push_back(
+        std::make_unique<RTCRtpSender>(*transceiver->content_sender()));
+    DCHECK(FindReceiver(RTCRtpReceiver::getId(webrtc_receiver.get())) ==
+           rtp_receivers_.end());
+    rtp_receivers_.push_back(
+        std::make_unique<RTCRtpReceiver>(*transceiver->content_receiver()));
   } else {
     // Update the transceiver. This also updates the sender and receiver.
     transceiver = (*it)->ShallowCopy();
     transceiver->set_state(std::move(transceiver_state));
     DCHECK(FindSender(RTCRtpSender::getId(webrtc_sender.get())) !=
            rtp_senders_.end());
-    DCHECK(rtp_receivers_.find(RTCRtpReceiver::getId(webrtc_receiver.get())) !=
+    DCHECK(FindReceiver(RTCRtpReceiver::getId(webrtc_receiver.get())) !=
            rtp_receivers_.end());
   }
   return transceiver;
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
index efd1fe0..639d170 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -275,8 +275,19 @@
       TransceiverStateSurfacer* transceiver_state_surfacer,
       bool* result);
   std::vector<std::unique_ptr<RTCRtpSender>>::iterator FindSender(uintptr_t id);
+  std::vector<std::unique_ptr<RTCRtpReceiver>>::iterator FindReceiver(
+      uintptr_t id);
   std::vector<std::unique_ptr<RTCRtpTransceiver>>::iterator FindTransceiver(
       uintptr_t id);
+  // For full transceiver implementations, returns the index of
+  // |rtp_transceivers_| that correspond to |web_transceiver|.
+  // For sender-only transceiver implementations, returns the index of
+  // |rtp_senders_| that correspond to |web_transceiver.Sender()|.
+  // For receiver-only transceiver implementations, returns the index of
+  // |rtp_receivers_| that correspond to |web_transceiver.Receiver()|.
+  // NOTREACHED()-crashes if no correspondent is found.
+  size_t GetTransceiverIndex(
+      const blink::WebRTCRtpTransceiver& web_transceiver);
   std::unique_ptr<RTCRtpTransceiver> CreateOrUpdateTransceiver(
       RtpTransceiverState transceiver_state);
 
@@ -325,10 +336,8 @@
   blink::WebRTCSdpSemantics sdp_semantics_;
   // Content layer correspondents of |webrtc::RtpSenderInterface|.
   std::vector<std::unique_ptr<RTCRtpSender>> rtp_senders_;
-  // Maps |RTCRtpReceiver::getId|s of |webrtc::RtpReceiverInterface|s to the
-  // corresponding content layer receivers. The set of receivers is needed in
-  // order to keep its associated track's and streams' adapters alive.
-  std::map<uintptr_t, std::unique_ptr<RTCRtpReceiver>> rtp_receivers_;
+  // Content layer correspondents of |webrtc::RtpReceiverInterface|.
+  std::vector<std::unique_ptr<RTCRtpReceiver>> rtp_receivers_;
   // Content layer correspondents of |webrtc::RtpTransceiverInterface|.
   std::vector<std::unique_ptr<RTCRtpTransceiver>> rtp_transceivers_;
 
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
index 7226e34..51a6af4 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler_unittest.cc
@@ -173,19 +173,19 @@
                     bool succeeded));
   MOCK_METHOD4(TrackAddTransceiver,
                void(RTCPeerConnectionHandler* pc_handler,
-                    PeerConnectionTracker::TransceiverUpdatedReason reason,
-                    const blink::WebRTCRtpSender* sender,
-                    const blink::WebRTCRtpReceiver* receiver));
+                    TransceiverUpdatedReason reason,
+                    const blink::WebRTCRtpTransceiver& transceiver,
+                    size_t transceiver_index));
   MOCK_METHOD4(TrackModifyTransceiver,
                void(RTCPeerConnectionHandler* pc_handler,
-                    PeerConnectionTracker::TransceiverUpdatedReason reason,
-                    const blink::WebRTCRtpSender* sender,
-                    const blink::WebRTCRtpReceiver* receiver));
+                    TransceiverUpdatedReason reason,
+                    const blink::WebRTCRtpTransceiver& transceiver,
+                    size_t transceiver_index));
   MOCK_METHOD4(TrackRemoveTransceiver,
                void(RTCPeerConnectionHandler* pc_handler,
-                    PeerConnectionTracker::TransceiverUpdatedReason reason,
-                    const blink::WebRTCRtpSender* sender,
-                    const blink::WebRTCRtpReceiver* receiver));
+                    TransceiverUpdatedReason reason,
+                    const blink::WebRTCRtpTransceiver& transceiver,
+                    size_t transceiver_index));
   MOCK_METHOD1(TrackOnIceComplete,
                void(RTCPeerConnectionHandler* pc_handler));
   MOCK_METHOD3(TrackCreateDataChannel,
diff --git a/content/renderer/media/webrtc/rtc_rtp_receiver.cc b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
index aecfc98..200b00b 100644
--- a/content/renderer/media/webrtc/rtc_rtp_receiver.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
@@ -218,10 +218,6 @@
   return *this;
 }
 
-std::unique_ptr<RTCRtpReceiver> RTCRtpReceiver::ShallowCopy() const {
-  return std::make_unique<RTCRtpReceiver>(*this);
-}
-
 const RtpReceiverState& RTCRtpReceiver::state() const {
   return internal_->state();
 }
@@ -230,6 +226,10 @@
   internal_->set_state(std::move(state));
 }
 
+std::unique_ptr<blink::WebRTCRtpReceiver> RTCRtpReceiver::ShallowCopy() const {
+  return std::make_unique<RTCRtpReceiver>(*this);
+}
+
 uintptr_t RTCRtpReceiver::Id() const {
   return getId(internal_->state().webrtc_receiver().get());
 }
@@ -257,7 +257,7 @@
 }
 
 RTCRtpReceiverOnlyTransceiver::RTCRtpReceiverOnlyTransceiver(
-    std::unique_ptr<RTCRtpReceiver> receiver)
+    std::unique_ptr<blink::WebRTCRtpReceiver> receiver)
     : receiver_(std::move(receiver)) {
   DCHECK(receiver_);
 }
@@ -270,18 +270,18 @@
 }
 
 uintptr_t RTCRtpReceiverOnlyTransceiver::Id() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return 0u;
 }
 
 blink::WebString RTCRtpReceiverOnlyTransceiver::Mid() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return blink::WebString();
 }
 
 std::unique_ptr<blink::WebRTCRtpSender> RTCRtpReceiverOnlyTransceiver::Sender()
     const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return nullptr;
 }
 
@@ -291,30 +291,30 @@
 }
 
 bool RTCRtpReceiverOnlyTransceiver::Stopped() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return false;
 }
 
 webrtc::RtpTransceiverDirection RTCRtpReceiverOnlyTransceiver::Direction()
     const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return webrtc::RtpTransceiverDirection::kSendOnly;
 }
 
 void RTCRtpReceiverOnlyTransceiver::SetDirection(
     webrtc::RtpTransceiverDirection direction) {
-  NOTREACHED();
+  NOTIMPLEMENTED();
 }
 
 base::Optional<webrtc::RtpTransceiverDirection>
 RTCRtpReceiverOnlyTransceiver::CurrentDirection() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return webrtc::RtpTransceiverDirection::kSendOnly;
 }
 
 base::Optional<webrtc::RtpTransceiverDirection>
 RTCRtpReceiverOnlyTransceiver::FiredDirection() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return webrtc::RtpTransceiverDirection::kSendOnly;
 }
 
diff --git a/content/renderer/media/webrtc/rtc_rtp_receiver.h b/content/renderer/media/webrtc/rtc_rtp_receiver.h
index ef9b92c..1eb373ad 100644
--- a/content/renderer/media/webrtc/rtc_rtp_receiver.h
+++ b/content/renderer/media/webrtc/rtc_rtp_receiver.h
@@ -107,13 +107,10 @@
 
   RTCRtpReceiver& operator=(const RTCRtpReceiver& other);
 
-  // Creates a shallow copy of the receiver, representing the same underlying
-  // webrtc receiver as the original.
-  std::unique_ptr<RTCRtpReceiver> ShallowCopy() const;
-
   const RtpReceiverState& state() const;
   void set_state(RtpReceiverState state);
 
+  std::unique_ptr<blink::WebRTCRtpReceiver> ShallowCopy() const override;
   uintptr_t Id() const override;
   const blink::WebMediaStreamTrack& Track() const override;
   blink::WebVector<blink::WebString> StreamIds() const override;
@@ -131,7 +128,8 @@
 class CONTENT_EXPORT RTCRtpReceiverOnlyTransceiver
     : public blink::WebRTCRtpTransceiver {
  public:
-  RTCRtpReceiverOnlyTransceiver(std::unique_ptr<RTCRtpReceiver> receiver);
+  RTCRtpReceiverOnlyTransceiver(
+      std::unique_ptr<blink::WebRTCRtpReceiver> receiver);
   ~RTCRtpReceiverOnlyTransceiver() override;
 
   blink::WebRTCRtpTransceiverImplementationType ImplementationType()
@@ -149,7 +147,7 @@
       const override;
 
  private:
-  std::unique_ptr<RTCRtpReceiver> receiver_;
+  std::unique_ptr<blink::WebRTCRtpReceiver> receiver_;
 };
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc/rtc_rtp_receiver_unittest.cc b/content/renderer/media/webrtc/rtc_rtp_receiver_unittest.cc
index 5526d11..ebe77e3 100644
--- a/content/renderer/media/webrtc/rtc_rtp_receiver_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_receiver_unittest.cc
@@ -123,7 +123,7 @@
   scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
       MockWebRtcAudioTrack::Create("webrtc_track");
   receiver_ = CreateReceiver(webrtc_track);
-  auto copy = receiver_->ShallowCopy();
+  auto copy = std::make_unique<RTCRtpReceiver>(*receiver_);
   EXPECT_EQ(receiver_->state().track_ref()->webrtc_track(), webrtc_track);
   const auto& webrtc_receiver = receiver_->state().webrtc_receiver();
   auto web_track_unique_id = receiver_->Track().UniqueId();
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.cc b/content/renderer/media/webrtc/rtc_rtp_sender.cc
index 7057550..a2d16ec 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.cc
@@ -362,10 +362,6 @@
   return *this;
 }
 
-std::unique_ptr<RTCRtpSender> RTCRtpSender::ShallowCopy() const {
-  return std::make_unique<RTCRtpSender>(*this);
-}
-
 const RtpSenderState& RTCRtpSender::state() const {
   return internal_->state();
 }
@@ -374,6 +370,10 @@
   internal_->set_state(std::move(state));
 }
 
+std::unique_ptr<blink::WebRTCRtpSender> RTCRtpSender::ShallowCopy() const {
+  return std::make_unique<RTCRtpSender>(*this);
+}
+
 uintptr_t RTCRtpSender::Id() const {
   return getId(internal_->state().webrtc_sender().get());
 }
@@ -432,7 +432,7 @@
 }
 
 RTCRtpSenderOnlyTransceiver::RTCRtpSenderOnlyTransceiver(
-    std::unique_ptr<RTCRtpSender> sender)
+    std::unique_ptr<blink::WebRTCRtpSender> sender)
     : sender_(std::move(sender)) {
   DCHECK(sender_);
 }
@@ -445,12 +445,12 @@
 }
 
 uintptr_t RTCRtpSenderOnlyTransceiver::Id() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return 0u;
 }
 
 blink::WebString RTCRtpSenderOnlyTransceiver::Mid() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return blink::WebString();
 }
 
@@ -461,34 +461,34 @@
 
 std::unique_ptr<blink::WebRTCRtpReceiver>
 RTCRtpSenderOnlyTransceiver::Receiver() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return nullptr;
 }
 
 bool RTCRtpSenderOnlyTransceiver::Stopped() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return false;
 }
 
 webrtc::RtpTransceiverDirection RTCRtpSenderOnlyTransceiver::Direction() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return webrtc::RtpTransceiverDirection::kSendOnly;
 }
 
 void RTCRtpSenderOnlyTransceiver::SetDirection(
     webrtc::RtpTransceiverDirection direction) {
-  NOTREACHED();
+  NOTIMPLEMENTED();
 }
 
 base::Optional<webrtc::RtpTransceiverDirection>
 RTCRtpSenderOnlyTransceiver::CurrentDirection() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return webrtc::RtpTransceiverDirection::kSendOnly;
 }
 
 base::Optional<webrtc::RtpTransceiverDirection>
 RTCRtpSenderOnlyTransceiver::FiredDirection() const {
-  NOTREACHED();
+  NOTIMPLEMENTED();
   return webrtc::RtpTransceiverDirection::kSendOnly;
 }
 
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.h b/content/renderer/media/webrtc/rtc_rtp_sender.h
index 8ba0c4f..7a96b39 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.h
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.h
@@ -114,18 +114,13 @@
       RtpSenderState state);
   RTCRtpSender(const RTCRtpSender& other);
   ~RTCRtpSender() override;
-
   RTCRtpSender& operator=(const RTCRtpSender& other);
 
-  // Creates a shallow copy of the sender, representing the same underlying
-  // webrtc sender as the original.
-  // TODO(hbos): Remove in favor of constructor. https://crbug.com/790007
-  std::unique_ptr<RTCRtpSender> ShallowCopy() const;
-
   const RtpSenderState& state() const;
   void set_state(RtpSenderState state);
 
   // blink::WebRTCRtpSender.
+  std::unique_ptr<blink::WebRTCRtpSender> ShallowCopy() const override;
   uintptr_t Id() const override;
   blink::WebMediaStreamTrack Track() const override;
   blink::WebVector<blink::WebString> StreamIds() const override;
@@ -157,7 +152,7 @@
 class CONTENT_EXPORT RTCRtpSenderOnlyTransceiver
     : public blink::WebRTCRtpTransceiver {
  public:
-  RTCRtpSenderOnlyTransceiver(std::unique_ptr<RTCRtpSender> sender);
+  RTCRtpSenderOnlyTransceiver(std::unique_ptr<blink::WebRTCRtpSender> sender);
   ~RTCRtpSenderOnlyTransceiver() override;
 
   blink::WebRTCRtpTransceiverImplementationType ImplementationType()
@@ -175,7 +170,7 @@
       const override;
 
  private:
-  std::unique_ptr<RTCRtpSender> sender_;
+  std::unique_ptr<blink::WebRTCRtpSender> sender_;
 };
 
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 9824bf6..86c1a111 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3451,6 +3451,30 @@
 // blink::WebLocalFrameClient implementation
 // ----------------------------------------
 
+bool RenderFrameImpl::IsPluginHandledExternally(
+    const blink::WebElement& plugin_element,
+    const blink::WebURL& url,
+    const blink::WebString& suggested_mime_type) {
+#if BUILDFLAG(ENABLE_PLUGINS)
+  if (!BrowserPluginManager::Get()) {
+    // BrowserPluginManager needs a RenderThreadImpl, but some renderer tests
+    // use a MockRenderThread instead.
+    return false;
+  }
+  // TODO(ekaramad): The instance ID is mostly used for GuestView attaching and
+  // lookup. See if this can be removed (https://crbug.com/659750).
+  // The instance ID will not be consumed if the contents cannot be rendered
+  // externally.
+  int32_t tentative_element_instance_id =
+      BrowserPluginManager::Get()->GetNextInstanceID();
+  return GetContentClient()->renderer()->IsPluginHandledByMimeHandlerView(
+      this, plugin_element, GURL(url), suggested_mime_type.Utf8(),
+      tentative_element_instance_id);
+#else
+  return false;
+#endif
+}
+
 blink::WebPlugin* RenderFrameImpl::CreatePlugin(
     const blink::WebPluginParams& params) {
   blink::WebPlugin* plugin = nullptr;
@@ -5956,8 +5980,7 @@
   if (IsTopLevelNavigation(frame_) &&
       render_view_->renderer_preferences_
           .browser_handles_all_top_level_requests) {
-    OpenURL(info, /*send_referrer=*/true,
-            /*is_history_navigation_in_new_child=*/false);
+    OpenURL(info, /*is_history_navigation_in_new_child=*/false);
     return blink::kWebNavigationPolicyIgnore;  // Suppress the load here.
   }
 
@@ -5986,8 +6009,7 @@
       // case JavaScript on the page is trying to interrupt the history
       // navigation.
       if (!info.is_client_redirect) {
-        OpenURL(info, /*send_referrer=*/true,
-                /*is_history_navigation_in_new_child=*/true);
+        OpenURL(info, /*is_history_navigation_in_new_child=*/true);
         // Suppress the load in Blink but mark the frame as loading.
         return blink::kWebNavigationPolicyHandledByClientForInitialHistory;
       } else {
@@ -6038,10 +6060,8 @@
       info.navigation_type == blink::kWebNavigationTypeOther;
 
   if (is_fork) {
-    // Open the URL via the browser, not via WebKit. Make sure the referrer is
-    // stripped.
-    OpenURL(info, /*send_referrer=*/false,
-            /*is_history_navigation_in_new_child=*/false);
+    // Open the URL via the browser, not via WebKit.
+    OpenURL(info, /*is_history_navigation_in_new_child=*/false);
     return blink::kWebNavigationPolicyIgnore;
   }
 
@@ -6050,8 +6070,6 @@
   // top-level navigations (not iframes). But we sometimes navigate to
   // about:blank to clear a tab, and we want to still allow that.
   if (!frame_->Parent() && !url.SchemeIs(url::kAboutScheme)) {
-    bool send_referrer = false;
-
     // All navigations to or from WebUI URLs or within WebUI-enabled
     // RenderProcesses must be handled by the browser process so that the
     // correct bindings and data sources can be registered.
@@ -6080,12 +6098,11 @@
       // Give the embedder a chance.
       should_fork = GetContentClient()->renderer()->ShouldFork(
           frame_, url, info.url_request.HttpMethod().Utf8(),
-          is_initial_navigation, false /* is_redirect */, &send_referrer);
+          is_initial_navigation, false /* is_redirect */);
     }
 
     if (should_fork) {
-      OpenURL(info, send_referrer,
-              /*is_history_navigation_in_new_child=*/false);
+      OpenURL(info, /*is_history_navigation_in_new_child=*/false);
       return blink::kWebNavigationPolicyIgnore;  // Suppress the load here.
     }
   }
@@ -6141,8 +6158,7 @@
                 blink::WebLocalFrameClient::CrossOriginRedirects::kFollow,
                 blob_url_token.PassHandle());
   } else {
-    OpenURL(info, /*send_referrer=*/true,
-            /*is_history_navigation_in_new_child=*/false);
+    OpenURL(info, /*is_history_navigation_in_new_child=*/false);
   }
   return blink::kWebNavigationPolicyIgnore;
 }
@@ -6440,7 +6456,6 @@
 #endif
 
 void RenderFrameImpl::OpenURL(const NavigationPolicyInfo& info,
-                              bool send_referrer,
                               bool is_history_navigation_in_new_child) {
   WebNavigationPolicy policy = info.default_policy;
   FrameHostMsg_OpenURL_Params params;
@@ -6449,9 +6464,8 @@
   params.resource_request_body =
       GetRequestBodyForWebURLRequest(info.url_request);
   params.extra_headers = GetWebURLRequestHeadersAsString(info.url_request);
-  params.referrer = send_referrer ? RenderViewImpl::GetReferrerFromRequest(
-                                        frame_, info.url_request)
-                                  : content::Referrer();
+  params.referrer =
+      RenderViewImpl::GetReferrerFromRequest(frame_, info.url_request);
   params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy);
   params.triggering_event_info = info.triggering_event_info;
   params.blob_url_token =
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 5ac3153..e5106d3 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -114,11 +114,14 @@
 namespace blink {
 class WebComputedAXTree;
 class WebContentDecryptionModule;
+class WebElement;
 class WebLayerTreeView;
 class WebLocalFrame;
 class WebPushClient;
 class WebRelatedAppsFetcher;
 class WebSecurityOrigin;
+class WebString;
+class WebURL;
 struct FramePolicy;
 struct WebContextMenuData;
 struct WebCursorInfo;
@@ -1077,7 +1080,6 @@
   // look for a matching FrameNavigationEntry in the last committed entry to use
   // instead of |url|.
   void OpenURL(const NavigationPolicyInfo& info,
-               bool send_referrer,
                bool is_history_navigation_in_new_child);
 
   // Creates a WebURLRequest to use fo the commit of a navigation.
@@ -1278,6 +1280,10 @@
 
   std::unique_ptr<blink::WebSocketHandshakeThrottle>
   CreateWebSocketHandshakeThrottle() override;
+  bool IsPluginHandledExternally(
+      const blink::WebElement& plugin_element,
+      const blink::WebURL& url,
+      const blink::WebString& suggested_mime_type) override;
 
   // Updates the state of this frame when asked to commit a navigation.
   void PrepareFrameForCommit(const GURL& url,
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index f94856c7..89fd620 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -414,7 +414,7 @@
   }
 
   const gfx::Size& GetPreferredSize() {
-    view()->CheckPreferredSize();
+    view()->UpdatePreferredSize();
     return view()->preferred_size_;
   }
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 74af840..b97c67a 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -569,7 +569,6 @@
   page_zoom_level_ = 0;
 
   nav_state_sync_timer_.SetTaskRunner(task_runner);
-  check_preferred_size_timer_.SetTaskRunner(std::move(task_runner));
 }
 
 RenderViewImpl::~RenderViewImpl() {
@@ -1667,17 +1666,7 @@
   for (auto& observer : observers_)
     observer.DidUpdateMainFrameLayout();
 
-  // We don't always want to set up a timer, only if we've been put in that
-  // mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
-  // message.
-  if (!send_preferred_size_changes_ || !webview())
-    return;
-
-  if (check_preferred_size_timer_.IsRunning())
-    return;
-  check_preferred_size_timer_.Start(FROM_HERE,
-                                    TimeDelta::FromMilliseconds(0), this,
-                                    &RenderViewImpl::CheckPreferredSize);
+  UpdatePreferredSize();
 }
 
 void RenderViewImpl::NavigateBackForwardSoon(int offset) {
@@ -1744,7 +1733,7 @@
   return gfx::RectF(bounding_box_in_window);
 }
 
-void RenderViewImpl::CheckPreferredSize() {
+void RenderViewImpl::UpdatePreferredSize() {
   // We don't always want to send the change messages over IPC, only if we've
   // been put in that mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
   // message.
@@ -1861,12 +1850,17 @@
     return;
   send_preferred_size_changes_ = true;
 
-  // Start off with an initial preferred size notification (in case
-  // |DidUpdateMainFrameLayout| was already called).
-  // TODO(pdr): |DidUpdateMainFrameLayout| should only be called with up-to-date
-  // layout but that may not be the case (see: NetworkServiceRestartBrowserTest.
-  // WindowOpenXHR). A lifecycle update should be done before this call.
-  DidUpdateMainFrameLayout();
+  if (!webview())
+    return;
+
+  // We need to ensure |UpdatePreferredSize| gets called. If a layout is needed,
+  // force an update here which will call |DidUpdateMainFrameLayout|.
+  webview()->UpdateLifecycle(WebWidget::LifecycleUpdate::kLayout);
+
+  // If a layout was not needed, |DidUpdateMainFrameLayout| will not be called.
+  // We explicitly update the preferred size here to ensure the preferred size
+  // notification is sent.
+  UpdatePreferredSize();
 }
 
 void RenderViewImpl::OnDisableScrollbarsForSmallWindows(
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index ded699a..10e897a 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -480,8 +480,9 @@
   // and put it in the same position in the .cc file.
 
   // Misc private functions ----------------------------------------------------
-  // Check whether the preferred size has changed.
-  void CheckPreferredSize();
+  // Check whether the preferred size has changed. This should only be called
+  // with up-to-date layout.
+  void UpdatePreferredSize();
 
 #if defined(OS_ANDROID)
   // Make the video capture devices (e.g. webcam) stop/resume delivering video
@@ -640,10 +641,6 @@
   // when layout() recomputes but doesn't actually change sizes.
   gfx::Size preferred_size_;
 
-  // Used to delay determining the preferred size (to avoid intermediate
-  // states for the sizes).
-  base::OneShotTimer check_preferred_size_timer_;
-
   // Used to indicate the zoom level to be used during subframe loads, since
   // they should match page zoom level.
   double page_zoom_level_ = 0;
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index 55cb92f7..697f3e3 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -56,80 +56,6 @@
 
 }  // namespace
 
-// Holds state for service worker clients.
-struct ServiceWorkerProviderContext::ProviderStateForClient {
-  explicit ProviderStateForClient(
-      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory)
-      : fallback_loader_factory(std::move(fallback_loader_factory)) {}
-  ~ProviderStateForClient() = default;
-
-  // |controller| will be set by SetController() and taken by TakeController().
-  blink::mojom::ServiceWorkerObjectInfoPtr controller;
-  // Keeps version id of the current controller service worker object.
-  int64_t controller_version_id = blink::mojom::kInvalidServiceWorkerVersionId;
-
-  // S13nServiceWorker:
-  // Used to intercept requests from the controllee and dispatch them
-  // as events to the controller ServiceWorker.
-  network::mojom::URLLoaderFactoryPtr subresource_loader_factory;
-
-  // S13nServiceWorker:
-  // Used when we create |subresource_loader_factory|.
-  scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory;
-
-  // S13nServiceWorker:
-  // The Client#id value of the client.
-  std::string client_id;
-
-  blink::mojom::ControllerServiceWorkerMode controller_mode =
-      blink::mojom::ControllerServiceWorkerMode::kNoController;
-
-  // Tracks feature usage for UseCounter.
-  std::set<blink::mojom::WebFeature> used_features;
-
-  // Corresponds to a ServiceWorkerContainer. We notify it when
-  // ServiceWorkerContainer#controller should be changed.
-  base::WeakPtr<WebServiceWorkerProviderImpl> web_service_worker_provider;
-
-  // Keeps ServiceWorkerWorkerClient pointers of dedicated or shared workers
-  // which are associated with the ServiceWorkerProviderContext.
-  // - If this ServiceWorkerProviderContext is for a Document, then
-  //   |worker_clients| contains all its dedicated workers.
-  // - If this ServiceWorkerProviderContext is for a SharedWorker (technically
-  //   speaking, for its shadow page), then |worker_clients| has one element:
-  //   the shared worker.
-  std::vector<mojom::ServiceWorkerWorkerClientPtr> worker_clients;
-
-  // For adding new ServiceWorkerWorkerClients.
-  mojo::BindingSet<mojom::ServiceWorkerWorkerClientRegistry>
-      worker_client_registry_bindings;
-
-  // S13nServiceWorker
-  // Used in |subresource_loader_factory| to get the connection to the
-  // controller service worker.
-  //
-  // |controller_endpoint| is a Mojo pipe to the controller service worker,
-  // and is to be passed to (i.e. taken by) a subresource loader factory when
-  // GetSubresourceLoaderFactory() is called for the first time when a valid
-  // controller exists.
-  //
-  // |controller_connector| is a Mojo pipe to the
-  // ControllerServiceWorkerConnector that is attached to the newly created
-  // subresource loader factory and lives on a background thread. This is
-  // populated when GetSubresourceLoader() creates the subresource loader
-  // factory and takes |controller_endpoint|.
-  mojom::ControllerServiceWorkerPtrInfo controller_endpoint;
-  mojom::ControllerServiceWorkerConnectorPtr controller_connector;
-
-  // For service worker clients. Map from registration id to JavaScript
-  // ServiceWorkerRegistration object.
-  std::map<int64_t, WebServiceWorkerRegistrationImpl*> registrations_;
-
-  // For service worker clients. Map from version id to JavaScript ServiceWorker
-  // object.
-  std::map<int64_t, WebServiceWorkerImpl*> workers_;
-};
-
 // For service worker clients.
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(
     int provider_id,
@@ -144,7 +70,7 @@
       binding_(this, std::move(request)),
       weak_factory_(this) {
   container_host_.Bind(std::move(host_ptr_info));
-  state_for_client_ = std::make_unique<ProviderStateForClient>(
+  state_for_client_ = std::make_unique<ServiceWorkerProviderStateForClient>(
       std::move(fallback_loader_factory));
 
   // Set up the URL loader factory for sending subresource requests to
@@ -330,7 +256,7 @@
 
 void ServiceWorkerProviderContext::DispatchNetworkQuiet() {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  ProviderStateForClient* state = state_for_client_.get();
+  ServiceWorkerProviderStateForClient* state = state_for_client_.get();
   DCHECK(state);
 
   // In non-S13nSW, this hint isn't needed because the browser process
@@ -362,7 +288,7 @@
     const std::vector<blink::mojom::WebFeature>& used_features,
     bool should_notify_controllerchange) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  ProviderStateForClient* state = state_for_client_.get();
+  ServiceWorkerProviderStateForClient* state = state_for_client_.get();
   DCHECK(state);
 
   state->controller = std::move(controller_info->object_info);
@@ -440,7 +366,7 @@
     blink::TransferableMessage message) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
 
-  ProviderStateForClient* state = state_for_client_.get();
+  ServiceWorkerProviderStateForClient* state = state_for_client_.get();
   DCHECK(state);
   if (state->web_service_worker_provider) {
     state->web_service_worker_provider->PostMessageToClient(std::move(source),
@@ -495,7 +421,7 @@
     blink::mojom::WebFeature feature) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(state_for_client_);
-  ProviderStateForClient* state = state_for_client_.get();
+  ServiceWorkerProviderStateForClient* state = state_for_client_.get();
 
   // ServiceWorkerProviderContext keeps track of features in order to propagate
   // it to WebServiceWorkerProviderClient, which actually records the
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h
index 405c40c..e8515eb 100644
--- a/content/renderer/service_worker/service_worker_provider_context.h
+++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -6,6 +6,9 @@
 #define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_CONTEXT_H_
 
 #include <memory>
+#include <set>
+#include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -15,6 +18,7 @@
 #include "content/common/service_worker/controller_service_worker.mojom.h"
 #include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_provider.mojom.h"
+#include "content/renderer/service_worker/service_worker_provider_state_for_client.h"
 #include "content/renderer/service_worker/web_service_worker_provider_impl.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -205,7 +209,6 @@
   friend class WebServiceWorkerImpl;
   friend class WebServiceWorkerRegistrationImpl;
   friend struct ServiceWorkerProviderContextDeleter;
-  struct ProviderStateForClient;
 
   ~ServiceWorkerProviderContext() override;
   void DestructOnMainThread() const;
@@ -264,7 +267,7 @@
   mojom::ServiceWorkerContainerHostAssociatedPtr container_host_;
 
   // State for service worker clients.
-  std::unique_ptr<ProviderStateForClient> state_for_client_;
+  std::unique_ptr<ServiceWorkerProviderStateForClient> state_for_client_;
 
   // NOTE: Add new members to |state_for_client_| if they are relevant only for
   // service worker clients. Not here!
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index f87c958..c3695033 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -5,6 +5,10 @@
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 
 #include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
@@ -18,7 +22,6 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/resource_type.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
-#include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "content/renderer/service_worker/web_service_worker_registration_impl.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
@@ -44,7 +47,11 @@
     : public blink::mojom::ServiceWorkerObjectHost {
  public:
   explicit MockServiceWorkerObjectHost(int64_t version_id)
-      : version_id_(version_id) {}
+      : version_id_(version_id) {
+    bindings_.set_connection_error_handler(
+        base::BindRepeating(&MockServiceWorkerObjectHost::OnConnectionError,
+                            base::Unretained(this)));
+  }
   ~MockServiceWorkerObjectHost() override = default;
 
   blink::mojom::ServiceWorkerObjectInfoPtr CreateObjectInfo() {
@@ -55,6 +62,16 @@
     return info;
   }
 
+  void OnConnectionError() {
+    if (error_callback_)
+      std::move(error_callback_).Run();
+  }
+
+  void RunOnConnectionError(base::OnceClosure error_callback) {
+    DCHECK(!error_callback_);
+    error_callback_ = std::move(error_callback);
+  }
+
   int GetBindingCount() const { return bindings_.size(); }
 
  private:
@@ -70,6 +87,7 @@
   const int64_t version_id_;
   mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerObjectHost> bindings_;
   blink::mojom::ServiceWorkerObjectAssociatedPtr remote_object_;
+  base::OnceClosure error_callback_;
 };
 
 class MockServiceWorkerRegistrationObjectHost
@@ -353,6 +371,11 @@
     return provider_context->ContainsServiceWorkerObjectForTesting(version_id);
   }
 
+  void FlushControllerConnector(
+      ServiceWorkerProviderContext* provider_context) {
+    provider_context->state_for_client_->controller_connector.FlushForTesting();
+  }
+
  protected:
   base::test::ScopedTaskEnvironment task_environment;
 
@@ -482,14 +505,27 @@
   EnableS13nServiceWorker();
   const int kProviderId = 10;
 
+  // Make the ServiceWorkerContainerHost implementation and
+  // ServiceWorkerContainer request.
+  mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr;
+  FakeServiceWorkerContainerHost host(
+      mojo::MakeRequestAssociatedWithDedicatedPipe(&host_ptr));
+  mojom::ServiceWorkerContainerAssociatedPtr container_ptr;
+  mojom::ServiceWorkerContainerAssociatedRequest container_request =
+      mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
+
   // (1) Test if setting the controller via the CTOR works.
   LOG(ERROR) << "1 test ctor";
+
+  // Make the object host for .controller.
   auto object_host1 =
       std::make_unique<MockServiceWorkerObjectHost>(200 /* version_id */);
-  ASSERT_EQ(0, object_host1->GetBindingCount());
+  EXPECT_EQ(0, object_host1->GetBindingCount());
   blink::mojom::ServiceWorkerObjectInfoPtr object_info1 =
       object_host1->CreateObjectInfo();
   EXPECT_EQ(1, object_host1->GetBindingCount());
+
+  // Make the ControllerServiceWorkerInfo.
   FakeControllerServiceWorker fake_controller1;
   auto controller_info1 = mojom::ControllerServiceWorkerInfo::New();
   mojom::ControllerServiceWorkerPtr controller_ptr1;
@@ -499,23 +535,15 @@
   controller_info1->object_info = std::move(object_info1);
   controller_info1->endpoint = controller_ptr1.PassInterface();
 
-  mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr;
-  FakeServiceWorkerContainerHost host(
-      mojo::MakeRequestAssociatedWithDedicatedPipe(&host_ptr));
-
-  mojom::ServiceWorkerContainerAssociatedPtr container_ptr;
-  mojom::ServiceWorkerContainerAssociatedRequest container_request =
-      mojo::MakeRequestAssociatedWithDedicatedPipe(&container_ptr);
+  // Make the ServiceWorkerProviderContext, pasing it the controller, container,
+  // and container host.
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
       kProviderId, blink::mojom::ServiceWorkerProviderType::kForWindow,
       std::move(container_request), host_ptr.PassInterface(),
       std::move(controller_info1), loader_factory_);
-  LOG(ERROR) << "1 RunUntilIdle after ctor";
-  base::RunLoop().RunUntilIdle();
-  LOG(ERROR) << "1 RunUntilIdle after ctor finished";
 
-  // Subresource loader factory must be available.
-  auto* subresource_loader_factory1 =
+  // The subresource loader factory must be available.
+  network::mojom::URLLoaderFactory* subresource_loader_factory1 =
       provider_context->GetSubresourceLoaderFactory();
   ASSERT_NE(nullptr, subresource_loader_factory1);
 
@@ -533,6 +561,8 @@
   // (2) Test if resetting the controller to a new one via SetController
   // works.
   LOG(ERROR) << "2 reset controller to new one";
+
+  // Setup the new controller.
   auto object_host2 =
       std::make_unique<MockServiceWorkerObjectHost>(201 /* version_id */);
   ASSERT_EQ(0, object_host2->GetBindingCount());
@@ -547,23 +577,35 @@
       blink::mojom::ControllerServiceWorkerMode::kControlled;
   controller_info2->object_info = std::move(object_info2);
   controller_info2->endpoint = controller_ptr2.PassInterface();
+
+  // Resetting the controller will trigger many things happening, including the
+  // object binding being broken.
+  base::RunLoop drop_binding_loop;
+  object_host1->RunOnConnectionError(drop_binding_loop.QuitClosure());
   container_ptr->SetController(std::move(controller_info2),
                                std::vector<blink::mojom::WebFeature>(), true);
-
-  // The controller is reset. References to the old controller must be
-  // released.
-  LOG(ERROR) << "2 RunUntilIdle after SetController";
-  base::RunLoop().RunUntilIdle();
-  LOG(ERROR) << "2 RunUntilIdle after SetController finished";
+  LOG(ERROR) << "2 FlushForTesting()";
+  container_ptr.FlushForTesting();
+  LOG(ERROR) << "2 FlushForTesting() finished";
+  LOG(ERROR) << "2 drop_binding_loop.Run()";
+  drop_binding_loop.Run();
+  LOG(ERROR) << "2 drop_binding_loop.Run() finished";
   EXPECT_EQ(0, object_host1->GetBindingCount());
 
   // Subresource loader factory must be available, and should be the same
   // one as we got before.
-  auto* subresource_loader_factory2 =
+  network::mojom::URLLoaderFactory* subresource_loader_factory2 =
       provider_context->GetSubresourceLoaderFactory();
   ASSERT_NE(nullptr, subresource_loader_factory2);
   EXPECT_EQ(subresource_loader_factory1, subresource_loader_factory2);
 
+  // The SetController() call results in another Mojo call to
+  // ControllerServiceWorkerConnector.UpdateController(). Flush that interface
+  // pointer to ensure the message was received.
+  LOG(ERROR) << "2 FlushControllerConnector()";
+  FlushControllerConnector(provider_context.get());
+  LOG(ERROR) << "2 FlushControllerConnector() finished";
+
   // Performing a request should reach the new controller.
   const GURL kURL2("https://www.example.com/foo2.png");
   base::RunLoop loop2;
@@ -579,14 +621,19 @@
 
   // (3) Test if resetting the controller to nullptr works.
   LOG(ERROR) << "3 reset controller to null";
+  base::RunLoop drop_binding_loop2;
+  object_host2->RunOnConnectionError(drop_binding_loop2.QuitClosure());
   container_ptr->SetController(mojom::ControllerServiceWorkerInfo::New(),
                                std::vector<blink::mojom::WebFeature>(), true);
 
   // The controller is reset. References to the old controller must be
   // released.
-  LOG(ERROR) << "3 RunUntilIdle()";
-  base::RunLoop().RunUntilIdle();
-  LOG(ERROR) << "3 RunUntilIdle() finished";
+  LOG(ERROR) << "3 FlushForTesting()";
+  container_ptr.FlushForTesting();
+  LOG(ERROR) << "3 FlushForTesting() finished";
+  LOG(ERROR) << "3 drop_binding_loop2.Run()";
+  drop_binding_loop2.Run();
+  LOG(ERROR) << "3 drop_binding_loop2.Run() finished";
   EXPECT_EQ(0, object_host2->GetBindingCount());
 
   // Subresource loader factory must not be available.
@@ -628,15 +675,22 @@
   controller_info4->endpoint = controller_ptr4.PassInterface();
   container_ptr->SetController(std::move(controller_info4),
                                std::vector<blink::mojom::WebFeature>(), true);
-  LOG(ERROR) << "4 RunUntilIdle()";
-  base::RunLoop().RunUntilIdle();
-  LOG(ERROR) << "4 RunUntilIdle() finished";
+  LOG(ERROR) << "4 FlushForTesting()";
+  container_ptr.FlushForTesting();
+  LOG(ERROR) << "4 FlushForTesting() finished";
 
   // Subresource loader factory must be available.
   auto* subresource_loader_factory4 =
       provider_context->GetSubresourceLoaderFactory();
   ASSERT_NE(nullptr, subresource_loader_factory4);
 
+  // The SetController() call results in another Mojo call to
+  // ControllerServiceWorkerConnector.UpdateController(). Flush that interface
+  // pointer to ensure the message was received.
+  LOG(ERROR) << "4 FlushControllerConnector()";
+  FlushControllerConnector(provider_context.get());
+  LOG(ERROR) << "4 FlushControllerConnector() finished";
+
   // Performing a request should reach the new controller.
   const GURL kURL4("https://www.example.com/foo4.png");
   base::RunLoop loop4;
diff --git a/content/renderer/service_worker/service_worker_provider_state_for_client.cc b/content/renderer/service_worker/service_worker_provider_state_for_client.cc
new file mode 100644
index 0000000..b5c043f0
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_provider_state_for_client.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/service_worker/service_worker_provider_state_for_client.h"
+
+#include <utility>
+
+namespace content {
+
+ServiceWorkerProviderStateForClient::ServiceWorkerProviderStateForClient(
+    scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory)
+    : fallback_loader_factory(std::move(fallback_loader_factory)) {}
+
+ServiceWorkerProviderStateForClient::~ServiceWorkerProviderStateForClient() =
+    default;
+
+}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_provider_state_for_client.h b/content/renderer/service_worker/service_worker_provider_state_for_client.h
new file mode 100644
index 0000000..dd93d3c
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_provider_state_for_client.h
@@ -0,0 +1,106 @@
+// 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 CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_STATE_FOR_CLIENT_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_STATE_FOR_CLIENT_H_
+
+#include <stdint.h>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/service_worker/controller_service_worker.mojom.h"
+#include "content/common/service_worker/service_worker_container.mojom.h"
+#include "content/common/service_worker/service_worker_provider.mojom.h"
+#include "content/renderer/service_worker/web_service_worker_impl.h"
+#include "content/renderer/service_worker/web_service_worker_provider_impl.h"
+#include "content/renderer/service_worker/web_service_worker_registration_impl.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/blink/public/platform/web_feature.mojom.h"
+
+namespace content {
+
+// Holds state for ServiceWorkerProviderContext instances for service worker
+// clients.
+struct ServiceWorkerProviderStateForClient {
+  explicit ServiceWorkerProviderStateForClient(
+      scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory);
+  ~ServiceWorkerProviderStateForClient();
+
+  // |controller| will be set by SetController() and taken by TakeController().
+  blink::mojom::ServiceWorkerObjectInfoPtr controller;
+  // Keeps version id of the current controller service worker object.
+  int64_t controller_version_id = blink::mojom::kInvalidServiceWorkerVersionId;
+
+  // S13nServiceWorker:
+  // Used to intercept requests from the controllee and dispatch them
+  // as events to the controller ServiceWorker.
+  network::mojom::URLLoaderFactoryPtr subresource_loader_factory;
+
+  // S13nServiceWorker:
+  // Used when we create |subresource_loader_factory|.
+  scoped_refptr<network::SharedURLLoaderFactory> fallback_loader_factory;
+
+  // S13nServiceWorker:
+  // The Client#id value of the client.
+  std::string client_id;
+
+  blink::mojom::ControllerServiceWorkerMode controller_mode =
+      blink::mojom::ControllerServiceWorkerMode::kNoController;
+
+  // Tracks feature usage for UseCounter.
+  std::set<blink::mojom::WebFeature> used_features;
+
+  // Corresponds to a ServiceWorkerContainer. We notify it when
+  // ServiceWorkerContainer#controller should be changed.
+  base::WeakPtr<WebServiceWorkerProviderImpl> web_service_worker_provider;
+
+  // Keeps ServiceWorkerWorkerClient pointers of dedicated or shared workers
+  // which are associated with the ServiceWorkerProviderContext.
+  // - If this ServiceWorkerProviderContext is for a Document, then
+  //   |worker_clients| contains all its dedicated workers.
+  // - If this ServiceWorkerProviderContext is for a SharedWorker (technically
+  //   speaking, for its shadow page), then |worker_clients| has one element:
+  //   the shared worker.
+  std::vector<mojom::ServiceWorkerWorkerClientPtr> worker_clients;
+
+  // For adding new ServiceWorkerWorkerClients.
+  mojo::BindingSet<mojom::ServiceWorkerWorkerClientRegistry>
+      worker_client_registry_bindings;
+
+  // S13nServiceWorker
+  // Used in |subresource_loader_factory| to get the connection to the
+  // controller service worker.
+  //
+  // |controller_endpoint| is a Mojo pipe to the controller service worker,
+  // and is to be passed to (i.e. taken by) a subresource loader factory when
+  // GetSubresourceLoaderFactory() is called for the first time when a valid
+  // controller exists.
+  //
+  // |controller_connector| is a Mojo pipe to the
+  // ControllerServiceWorkerConnector that is attached to the newly created
+  // subresource loader factory and lives on a background thread. This is
+  // populated when GetSubresourceLoader() creates the subresource loader
+  // factory and takes |controller_endpoint|.
+  mojom::ControllerServiceWorkerPtrInfo controller_endpoint;
+  mojom::ControllerServiceWorkerConnectorPtr controller_connector;
+
+  // For service worker clients. Map from registration id to JavaScript
+  // ServiceWorkerRegistration object.
+  std::map<int64_t, WebServiceWorkerRegistrationImpl*> registrations_;
+
+  // For service worker clients. Map from version id to JavaScript ServiceWorker
+  // object.
+  std::map<int64_t, WebServiceWorkerImpl*> workers_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_STATE_FOR_CLIENT_H_
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc
index f4deb7b2..917d2def 100644
--- a/content/shell/renderer/shell_content_renderer_client.cc
+++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -194,11 +194,9 @@
                                             const GURL& url,
                                             const std::string& http_method,
                                             bool is_initial_navigation,
-                                            bool is_server_redirect,
-                                            bool* send_referrer) {
+                                            bool is_server_redirect) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kContentShellAlwaysFork)) {
-    *send_referrer = true;
     return true;
   }
   return false;
diff --git a/content/shell/renderer/shell_content_renderer_client.h b/content/shell/renderer/shell_content_renderer_client.h
index 41cc6bb8..908fa684 100644
--- a/content/shell/renderer/shell_content_renderer_client.h
+++ b/content/shell/renderer/shell_content_renderer_client.h
@@ -53,8 +53,7 @@
                   const GURL& url,
                   const std::string& http_method,
                   bool is_initial_navigation,
-                  bool is_server_redirect,
-                  bool* send_referrer) override;
+                  bool is_server_redirect) override;
 
 #if BUILDFLAG(ENABLE_MOJO_CDM)
   void AddSupportedKeySystems(
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 9266e3b..70f3441 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -196,6 +196,8 @@
     "accessibility_browser_test_utils.h",
     "appcache_test_helper.cc",
     "appcache_test_helper.h",
+    "barrier_builder.cc",
+    "barrier_builder.h",
     "content_browser_sanity_checker.cc",
     "content_browser_sanity_checker.h",
     "content_test_suite.cc",
@@ -524,6 +526,7 @@
     "//gin",
     "//media",
     "//net",
+    "//services/catalog:lib",
     "//skia",
     "//testing/gtest",
     "//ui/accessibility:ax_enums_mojo",
@@ -537,6 +540,10 @@
     deps += [ "//content/public/browser" ]
   }
 
+  if (is_chromeos) {
+    deps += [ ":content_browsertests_catalog_source" ]
+  }
+
   if (use_aura && toolkit_views) {
     deps += [ "//ui/views" ]
   }
@@ -1137,6 +1144,7 @@
 
   if (is_chromeos) {
     deps += [ "//chromeos" ]
+    data_deps += [ "//services/ui/test_ws" ]
   }
 
   if (use_aura && !is_win) {
@@ -1220,6 +1228,21 @@
   }
 }
 
+if (is_chromeos) {
+  catalog("content_browsertests_catalog") {
+    testonly = true
+
+    standalone_services = [ "//services/ui/test_ws:manifest" ]
+  }
+
+  catalog_cpp_source("content_browsertests_catalog_source") {
+    testonly = true
+
+    catalog = ":content_browsertests_catalog"
+    generated_function_name = "content::CreateContentBrowserTestsCatalog"
+  }
+}
+
 test("content_unittests") {
   # See comment at the top of //content/BUILD.gn for why this is disabled in
   # component builds.
@@ -1378,6 +1401,8 @@
     "../browser/indexed_db/mock_mojo_indexed_db_callbacks.h",
     "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc",
     "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h",
+    "../browser/indexed_db/scopes/disjoint_range_lock_manager_unittest.cc",
+    "../browser/indexed_db/scopes/scopes_lock_manager_unittest.cc",
     "../browser/loader/cross_site_document_resource_handler_unittest.cc",
     "../browser/loader/data_pipe_to_source_stream_unittest.cc",
     "../browser/loader/detachable_resource_handler_unittest.cc",
diff --git a/content/test/barrier_builder.cc b/content/test/barrier_builder.cc
new file mode 100644
index 0000000..db1eab5
--- /dev/null
+++ b/content/test/barrier_builder.cc
@@ -0,0 +1,46 @@
+// 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 "content/test/barrier_builder.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+
+namespace content {
+
+// The callbacks returned by |AddClosure| can get called after destruction of
+// BarrierBuilder, so there needs to be an internal class to hold the final
+// callback.
+class BarrierBuilder::InternalBarrierBuilder
+    : public base::RefCountedThreadSafe<
+          BarrierBuilder::InternalBarrierBuilder> {
+ public:
+  InternalBarrierBuilder(base::OnceClosure done_closure)
+      : done_runner_(std::move(done_closure)) {}
+
+ private:
+  friend class base::RefCountedThreadSafe<
+      BarrierBuilder::InternalBarrierBuilder>;
+
+  ~InternalBarrierBuilder() = default;
+
+  base::ScopedClosureRunner done_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(InternalBarrierBuilder);
+};
+
+BarrierBuilder::BarrierBuilder(base::OnceClosure done_closure)
+    : internal_barrier_(
+          new BarrierBuilder::InternalBarrierBuilder(std::move(done_closure))) {
+}
+
+BarrierBuilder::~BarrierBuilder() = default;
+
+base::OnceClosure BarrierBuilder::AddClosure() {
+  return base::BindOnce(
+      [](scoped_refptr<BarrierBuilder::InternalBarrierBuilder>) {},
+      internal_barrier_);
+}
+
+}  // namespace content
diff --git a/content/test/barrier_builder.h b/content/test/barrier_builder.h
new file mode 100644
index 0000000..3947885
--- /dev/null
+++ b/content/test/barrier_builder.h
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_TEST_BARRIER_BUILDER_H_
+#define CONTENT_TEST_BARRIER_BUILDER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace content {
+
+// A BarrierBuilder helps create a barrier for a large, complex, or variable
+// number of steps.
+//
+// Example usage:
+//
+// base::RunLoop loop;
+// {
+//   BarrierBuilder barrier(loop.QuitClosure());
+//   AsyncMethod(barrier.AddClosure());
+//   AsyncMethod(barrier.AddClosure());
+// }
+// loop.Run();
+//
+// Once all closures returned by AddClosure AND the BarrierBuilder object are
+// all destroyed, the |done_closure| is called. The |done_closure| will
+// be invoked on the thread that calls the last step closure, or on the thread
+// where BarrierBuilder goes out of scope (if that happens after all closures
+// are called).
+class BarrierBuilder {
+ public:
+  explicit BarrierBuilder(base::OnceClosure done_closure);
+  ~BarrierBuilder();
+
+  // Returns a closure that can be used in the same way that a barrier closure
+  // would be used. Furthermore, each callback returned by AddClosure() should
+  // eventually be run, or else 'done_closure' will never be run.
+  base::OnceClosure AddClosure();
+
+ private:
+  class InternalBarrierBuilder;
+
+  scoped_refptr<InternalBarrierBuilder> internal_barrier_;
+
+  DISALLOW_COPY_AND_ASSIGN(BarrierBuilder);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_TEST_BARRIER_BUILDER_H_
diff --git a/content/test/content_test_launcher.cc b/content/test/content_test_launcher.cc
index dfcccf4..9942528 100644
--- a/content/test/content_test_launcher.cc
+++ b/content/test/content_test_launcher.cc
@@ -21,6 +21,7 @@
 #include "content/shell/app/shell_main_delegate.h"
 #include "content/shell/common/shell_switches.h"
 #include "media/base/media_switches.h"
+#include "services/catalog/catalog.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/base/ui_features.h"
@@ -40,6 +41,10 @@
 #include "ui/base/ui_base_paths.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "content/test/content_browsertests_catalog_source.h"
+#endif
+
 namespace content {
 
 #if defined(OS_ANDROID)
@@ -88,6 +93,11 @@
     InitializeMojo();
 #endif
 
+#if defined(OS_CHROMEOS)
+    catalog::Catalog::SetDefaultCatalogManifest(
+        content::CreateContentBrowserTestsCatalog());
+#endif
+
     ContentTestSuiteBase::Initialize();
   }
 
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 58ee341..1beb27a 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -373,6 +373,8 @@
     self.Fail('conformance/textures/canvas/' +
         'tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html',
         ['passthrough', 'opengl'], bug=602688)
+    self.Fail('deqp/functional/gles3/shadercommonfunction.html',
+        ['passthrough', 'opengl'], bug=795030)
 
     # Passthrough command decoder / OpenGL / Windows
     self.Fail('deqp/functional/gles3/fbocompleteness.html',
@@ -421,13 +423,19 @@
         ['linux', 'passthrough', 'opengl', 'nvidia'], bug=814905)
     self.Fail('deqp/functional/gles3/shaderoperator/common_functions.html',
         ['linux', 'passthrough', 'opengl', 'nvidia'], bug=793055)
-    self.Fail('deqp/functional/gles3/shadercommonfunction.html',
-        ['linux', 'passthrough', 'opengl', 'nvidia'], bug=793055)
-    self.Fail('deqp/functional/gles3/shadercommonfunction.html',
-        ['win', 'nvidia', 'opengl'], bug=795030)
     self.Fail('deqp/functional/gles3/shaderpackingfunction.html',
         ['linux', 'passthrough', 'opengl', 'nvidia'], bug=794341)
 
+    # Passthrough command decoder / Linux / OpenGL / Intel
+    self.Fail('conformance2/renderbuffers/' +
+        'multisampled-depth-renderbuffer-initialization.html',
+        ['linux', 'passthrough', 'opengl', 'intel'], bug=2760) # ANGLE bug
+    self.Fail('conformance2/renderbuffers/' +
+        'multisampled-stencil-renderbuffer-initialization.html',
+        ['linux', 'passthrough', 'opengl', 'intel'], bug=2760) # ANGLE bug
+    self.Fail('conformance2/textures/misc/tex-mipmap-levels.html',
+        ['linux', 'passthrough', 'opengl', 'intel'], bug=2761) # ANGLE bug
+
     # Regressions in 10.12.4.
     self.Fail('conformance2/textures/misc/tex-base-level-bug.html',
         ['sierra'], bug=705865)
diff --git a/device/gamepad/gamepad_consumer.h b/device/gamepad/gamepad_consumer.h
index f80183d..b91095a5 100644
--- a/device/gamepad/gamepad_consumer.h
+++ b/device/gamepad/gamepad_consumer.h
@@ -15,9 +15,11 @@
   GamepadConsumer();
   virtual ~GamepadConsumer();
 
-  virtual void OnGamepadConnected(unsigned index, const Gamepad& gamepad) = 0;
-  virtual void OnGamepadDisconnected(unsigned index,
+  virtual void OnGamepadConnected(uint32_t index, const Gamepad& gamepad) = 0;
+  virtual void OnGamepadDisconnected(uint32_t index,
                                      const Gamepad& gamepad) = 0;
+  virtual void OnGamepadButtonOrAxisChanged(uint32_t index,
+                                            const Gamepad& gamepad) = 0;
 };
 
 }  // namespace device
diff --git a/device/gamepad/gamepad_haptics_manager.cc b/device/gamepad/gamepad_haptics_manager.cc
index 656f350..8171275 100644
--- a/device/gamepad/gamepad_haptics_manager.cc
+++ b/device/gamepad/gamepad_haptics_manager.cc
@@ -24,7 +24,7 @@
 }
 
 void GamepadHapticsManager::PlayVibrationEffectOnce(
-    int pad_index,
+    uint32_t pad_index,
     mojom::GamepadHapticEffectType type,
     mojom::GamepadEffectParametersPtr params,
     PlayVibrationEffectOnceCallback callback) {
@@ -33,7 +33,7 @@
 }
 
 void GamepadHapticsManager::ResetVibrationActuator(
-    int pad_index,
+    uint32_t pad_index,
     ResetVibrationActuatorCallback callback) {
   GamepadService::GetInstance()->ResetVibrationActuator(pad_index,
                                                         std::move(callback));
diff --git a/device/gamepad/gamepad_haptics_manager.h b/device/gamepad/gamepad_haptics_manager.h
index 6c31e36d..a95d6569 100644
--- a/device/gamepad/gamepad_haptics_manager.h
+++ b/device/gamepad/gamepad_haptics_manager.h
@@ -20,11 +20,11 @@
   static void Create(mojom::GamepadHapticsManagerRequest request);
 
   // mojom::GamepadHapticsManager implementation.
-  void PlayVibrationEffectOnce(int pad_index,
+  void PlayVibrationEffectOnce(uint32_t pad_index,
                                mojom::GamepadHapticEffectType,
                                mojom::GamepadEffectParametersPtr,
                                PlayVibrationEffectOnceCallback) override;
-  void ResetVibrationActuator(int pad_index,
+  void ResetVibrationActuator(uint32_t pad_index,
                               ResetVibrationActuatorCallback) override;
 
  private:
diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc
index 27ba975..63d3d377 100644
--- a/device/gamepad/gamepad_monitor.cc
+++ b/device/gamepad/gamepad_monitor.cc
@@ -27,18 +27,24 @@
                           std::move(request));
 }
 
-void GamepadMonitor::OnGamepadConnected(unsigned index,
+void GamepadMonitor::OnGamepadConnected(uint32_t index,
                                         const Gamepad& gamepad) {
   if (gamepad_observer_)
     gamepad_observer_->GamepadConnected(index, gamepad);
 }
 
-void GamepadMonitor::OnGamepadDisconnected(unsigned index,
+void GamepadMonitor::OnGamepadDisconnected(uint32_t index,
                                            const Gamepad& gamepad) {
   if (gamepad_observer_)
     gamepad_observer_->GamepadDisconnected(index, gamepad);
 }
 
+void GamepadMonitor::OnGamepadButtonOrAxisChanged(uint32_t index,
+                                                  const Gamepad& gamepad) {
+  if (gamepad_observer_)
+    gamepad_observer_->GamepadButtonOrAxisChanged(index, gamepad);
+}
+
 void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) {
   DCHECK(!is_started_);
   is_started_ = true;
diff --git a/device/gamepad/gamepad_monitor.h b/device/gamepad/gamepad_monitor.h
index 7ee56f5..8e62bf3a8 100644
--- a/device/gamepad/gamepad_monitor.h
+++ b/device/gamepad/gamepad_monitor.h
@@ -22,8 +22,10 @@
   static void Create(mojom::GamepadMonitorRequest request);
 
   // GamepadConsumer implementation.
-  void OnGamepadConnected(unsigned index, const Gamepad& gamepad) override;
-  void OnGamepadDisconnected(unsigned index, const Gamepad& gamepad) override;
+  void OnGamepadConnected(uint32_t index, const Gamepad& gamepad) override;
+  void OnGamepadDisconnected(uint32_t index, const Gamepad& gamepad) override;
+  void OnGamepadButtonOrAxisChanged(uint32_t index,
+                                    const Gamepad& gamepad) override;
 
   // mojom::GamepadMonitor implementation.
   void GamepadStartPolling(GamepadStartPollingCallback callback) override;
diff --git a/device/gamepad/gamepad_pad_state_provider.cc b/device/gamepad/gamepad_pad_state_provider.cc
index 5c793748..11f1f37 100644
--- a/device/gamepad/gamepad_pad_state_provider.cc
+++ b/device/gamepad/gamepad_pad_state_provider.cc
@@ -20,7 +20,7 @@
 GamepadPadStateProvider::GamepadPadStateProvider() {
   pad_states_.reset(new PadState[Gamepads::kItemsLengthCap]);
 
-  for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i)
+  for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i)
     ClearPadState(pad_states_.get()[i]);
 }
 
@@ -50,8 +50,8 @@
   return empty_slot;
 }
 
-PadState* GamepadPadStateProvider::GetConnectedPadState(int pad_index) {
-  if (pad_index < 0 || pad_index >= (int)Gamepads::kItemsLengthCap)
+PadState* GamepadPadStateProvider::GetConnectedPadState(uint32_t pad_index) {
+  if (pad_index >= Gamepads::kItemsLengthCap)
     return nullptr;
 
   PadState& pad_state = pad_states_.get()[pad_index];
diff --git a/device/gamepad/gamepad_pad_state_provider.h b/device/gamepad/gamepad_pad_state_provider.h
index 0824b93..8ffbfe42 100644
--- a/device/gamepad/gamepad_pad_state_provider.h
+++ b/device/gamepad/gamepad_pad_state_provider.h
@@ -91,7 +91,7 @@
   // Gets a PadState object for a connected gamepad by specifying its index in
   // the pad_states_ array. Returns NULL if there is no connected gamepad at
   // that index.
-  PadState* GetConnectedPadState(int pad_index);
+  PadState* GetConnectedPadState(uint32_t pad_index);
 
  protected:
   void ClearPadState(PadState& state);
diff --git a/device/gamepad/gamepad_platform_data_fetcher_linux.cc b/device/gamepad/gamepad_platform_data_fetcher_linux.cc
index a8d351b..f3ad3a00 100644
--- a/device/gamepad/gamepad_platform_data_fetcher_linux.cc
+++ b/device/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -288,11 +288,7 @@
 }
 
 void GamepadPlatformDataFetcherLinux::ReadDeviceData(size_t index) {
-  // Linker does not like CHECK_LT(index, Gamepads::kItemsLengthCap). =/
-  if (index >= Gamepads::kItemsLengthCap) {
-    CHECK(false);
-    return;
-  }
+  CHECK_LT(index, Gamepads::kItemsLengthCap);
 
   GamepadDeviceLinux* device = GetDeviceWithJoydevIndex(index);
   if (!device)
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index ed7fcfa..fb42a34 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -97,7 +97,7 @@
 }
 
 void GamepadProvider::PlayVibrationEffectOnce(
-    int pad_index,
+    uint32_t pad_index,
     mojom::GamepadHapticEffectType type,
     mojom::GamepadEffectParametersPtr params,
     mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
@@ -120,7 +120,7 @@
 }
 
 void GamepadProvider::ResetVibrationActuator(
-    int pad_index,
+    uint32_t pad_index,
     mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
   PadState* pad_state = GetConnectedPadState(pad_index);
   if (!pad_state) {
@@ -284,7 +284,7 @@
     devices_changed_ = false;
   }
 
-  for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i)
+  for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i)
     pad_states_.get()[i].is_active = false;
 
   // Loop through each registered data fetcher and poll its gamepad data.
@@ -300,7 +300,7 @@
   // Send out disconnect events using the last polled data before we wipe it out
   // in the mapping step.
   if (ever_had_user_gesture_) {
-    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
+    for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
       PadState& state = pad_states_.get()[i];
 
       if (!state.is_newly_active && !state.is_active &&
@@ -319,7 +319,7 @@
     // Acquire the SeqLock. There is only ever one writer to this data.
     // See gamepad_shared_buffer.h.
     gamepad_shared_buffer_->WriteBegin();
-    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
+    for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
       PadState& state = pad_states_.get()[i];
       // Must run through the map+sanitize here or CheckForUserGesture may fail.
       MapAndSanitizeGamepadData(&state, &buffer->items[i], sanitize_);
@@ -328,7 +328,7 @@
   }
 
   if (ever_had_user_gesture_) {
-    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
+    for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
       PadState& state = pad_states_.get()[i];
 
       if (state.is_newly_active && buffer->items[i].connected) {
@@ -348,7 +348,7 @@
   // CheckForUserGesture call above. If we don't clear |is_newly_active| here,
   // we will notify again for the same gamepad on the next polling cycle.
   if (did_notify) {
-    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i)
+    for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i)
       pad_states_.get()[i].is_newly_active = false;
   }
 
@@ -374,7 +374,7 @@
 }
 
 void GamepadProvider::OnGamepadConnectionChange(bool connected,
-                                                int index,
+                                                uint32_t index,
                                                 const Gamepad& pad) {
   if (connection_change_client_)
     connection_change_client_->OnGamepadConnectionChange(connected, index, pad);
diff --git a/device/gamepad/gamepad_provider.h b/device/gamepad/gamepad_provider.h
index 03e31de..35a856ea8 100644
--- a/device/gamepad/gamepad_provider.h
+++ b/device/gamepad/gamepad_provider.h
@@ -35,7 +35,7 @@
 class DEVICE_GAMEPAD_EXPORT GamepadConnectionChangeClient {
  public:
   virtual void OnGamepadConnectionChange(bool connected,
-                                         int index,
+                                         uint32_t index,
                                          const Gamepad& pad) = 0;
 };
 
@@ -59,13 +59,13 @@
   void GetCurrentGamepadData(Gamepads* data);
 
   void PlayVibrationEffectOnce(
-      int pad_index,
+      uint32_t pad_index,
       mojom::GamepadHapticEffectType,
       mojom::GamepadEffectParametersPtr,
       mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback);
 
   void ResetVibrationActuator(
-      int pad_index,
+      uint32_t pad_index,
       mojom::GamepadHapticsManager::ResetVibrationActuatorCallback);
 
   // Pause and resume the background polling thread. Can be called from any
@@ -106,7 +106,9 @@
   void DoPoll();
   void ScheduleDoPoll();
 
-  void OnGamepadConnectionChange(bool connected, int index, const Gamepad& pad);
+  void OnGamepadConnectionChange(bool connected,
+                                 uint32_t index,
+                                 const Gamepad& pad);
 
   // Checks the gamepad state to see if the user has interacted with it. Returns
   // true if any user gesture observers were notified.
diff --git a/device/gamepad/gamepad_service.cc b/device/gamepad/gamepad_service.cc
index 5eab297..37aa3070 100644
--- a/device/gamepad/gamepad_service.cc
+++ b/device/gamepad/gamepad_service.cc
@@ -72,7 +72,7 @@
       const std::vector<bool>& old_connected_state = consumer_state_it->second;
       Gamepads gamepads;
       provider_->GetCurrentGamepadData(&gamepads);
-      for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
+      for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
         const Gamepad& gamepad = gamepads.items[i];
         if (gamepad.connected) {
           info.consumer->OnGamepadConnected(i, gamepad);
@@ -109,7 +109,7 @@
     Gamepads gamepads;
     provider_->GetCurrentGamepadData(&gamepads);
     std::vector<bool> connected_state(Gamepads::kItemsLengthCap);
-    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i)
+    for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i)
       connected_state[i] = gamepads.items[i].connected;
     inactive_consumer_state_[consumer] = connected_state;
   }
@@ -136,7 +136,7 @@
 }
 
 void GamepadService::OnGamepadConnectionChange(bool connected,
-                                               int index,
+                                               uint32_t index,
                                                const Gamepad& pad) {
   if (connected) {
     main_thread_task_runner_->PostTask(
@@ -149,7 +149,7 @@
   }
 }
 
-void GamepadService::OnGamepadConnected(int index, const Gamepad& pad) {
+void GamepadService::OnGamepadConnected(uint32_t index, const Gamepad& pad) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
   for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
@@ -159,7 +159,7 @@
   }
 }
 
-void GamepadService::OnGamepadDisconnected(int index, const Gamepad& pad) {
+void GamepadService::OnGamepadDisconnected(uint32_t index, const Gamepad& pad) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
   for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
@@ -170,7 +170,7 @@
 }
 
 void GamepadService::PlayVibrationEffectOnce(
-    int pad_index,
+    uint32_t pad_index,
     mojom::GamepadHapticEffectType type,
     mojom::GamepadEffectParametersPtr params,
     mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
@@ -187,7 +187,7 @@
 }
 
 void GamepadService::ResetVibrationActuator(
-    int pad_index,
+    uint32_t pad_index,
     mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
@@ -220,7 +220,7 @@
       info.did_observe_user_gesture = true;
       Gamepads gamepads;
       provider_->GetCurrentGamepadData(&gamepads);
-      for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
+      for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
         const Gamepad& pad = gamepads.items[i];
         if (pad.connected)
           info.consumer->OnGamepadConnected(i, pad);
diff --git a/device/gamepad/gamepad_service.h b/device/gamepad/gamepad_service.h
index 7485786..12723ac4b 100644
--- a/device/gamepad/gamepad_service.h
+++ b/device/gamepad/gamepad_service.h
@@ -77,16 +77,16 @@
   void Terminate();
 
   // Called on IO thread when a gamepad is connected.
-  void OnGamepadConnected(int index, const Gamepad& pad);
+  void OnGamepadConnected(uint32_t index, const Gamepad& pad);
 
   // Called on IO thread when a gamepad is disconnected.
-  void OnGamepadDisconnected(int index, const Gamepad& pad);
+  void OnGamepadDisconnected(uint32_t index, const Gamepad& pad);
 
   // Request playback of a haptic effect on the specified gamepad. Once effect
   // playback is complete or is preempted by a different effect, the callback
   // will be called.
   void PlayVibrationEffectOnce(
-      int pad_index,
+      uint32_t pad_index,
       mojom::GamepadHapticEffectType,
       mojom::GamepadEffectParametersPtr,
       mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback);
@@ -95,7 +95,7 @@
   // effects are currently being played, they are preempted and vibration is
   // stopped.
   void ResetVibrationActuator(
-      int pad_index,
+      uint32_t pad_index,
       mojom::GamepadHapticsManager::ResetVibrationActuatorCallback);
 
  private:
@@ -116,7 +116,7 @@
   void OnUserGesture();
 
   void OnGamepadConnectionChange(bool connected,
-                                 int index,
+                                 uint32_t index,
                                  const Gamepad& pad) override;
 
   void SetSanitizationEnabled(bool sanitize);
diff --git a/device/gamepad/gamepad_service_unittest.cc b/device/gamepad/gamepad_service_unittest.cc
index b8d9b9d..a2a72fc7 100644
--- a/device/gamepad/gamepad_service_unittest.cc
+++ b/device/gamepad/gamepad_service_unittest.cc
@@ -25,12 +25,14 @@
  public:
   ConnectionListener() { ClearCounters(); }
 
-  void OnGamepadConnected(unsigned index, const Gamepad& gamepad) override {
+  void OnGamepadConnected(uint32_t index, const Gamepad& gamepad) override {
     connected_counter_++;
   }
-  void OnGamepadDisconnected(unsigned index, const Gamepad& gamepad) override {
+  void OnGamepadDisconnected(uint32_t index, const Gamepad& gamepad) override {
     disconnected_counter_++;
   }
+  void OnGamepadButtonOrAxisChanged(uint32_t index,
+                                    const Gamepad& gamepad) override {}
 
   void ClearCounters() {
     connected_counter_ = 0;
diff --git a/device/gamepad/gamepad_test_helpers.cc b/device/gamepad/gamepad_test_helpers.cc
index 8edd6068..f6147ca 100644
--- a/device/gamepad/gamepad_test_helpers.cc
+++ b/device/gamepad/gamepad_test_helpers.cc
@@ -21,7 +21,7 @@
   {
     base::AutoLock lock(lock_);
 
-    for (unsigned int i = 0; i < Gamepads::kItemsLengthCap; ++i) {
+    for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
       if (test_data_.items[i].connected) {
         PadState* pad = GetPadState(i);
         if (pad)
diff --git a/device/gamepad/gamepad_user_gesture.cc b/device/gamepad/gamepad_user_gesture.cc
index 6ae7a3142..6fdf0a5 100644
--- a/device/gamepad/gamepad_user_gesture.cc
+++ b/device/gamepad/gamepad_user_gesture.cc
@@ -18,7 +18,7 @@
 namespace device {
 
 bool GamepadsHaveUserGesture(const Gamepads& gamepads) {
-  for (unsigned int i = 0; i < Gamepads::kItemsLengthCap; i++) {
+  for (size_t i = 0; i < Gamepads::kItemsLengthCap; i++) {
     const Gamepad& pad = gamepads.items[i];
 
     // If the device is physically connected, then check the buttons and axes
@@ -33,14 +33,13 @@
       if (pad.display_id != 0)
         return true;
 
-      for (unsigned int button_index = 0; button_index < pad.buttons_length;
+      for (size_t button_index = 0; button_index < pad.buttons_length;
            button_index++) {
         if (pad.buttons[button_index].pressed)
           return true;
       }
 
-      for (unsigned int axes_index = 0; axes_index < pad.axes_length;
-           axes_index++) {
+      for (size_t axes_index = 0; axes_index < pad.axes_length; axes_index++) {
         if (fabs(pad.axes[axes_index]) > kAxisMoveAmountThreshold)
           return true;
       }
diff --git a/device/gamepad/public/cpp/BUILD.gn b/device/gamepad/public/cpp/BUILD.gn
index 26af5f7..18a0da7 100644
--- a/device/gamepad/public/cpp/BUILD.gn
+++ b/device/gamepad/public/cpp/BUILD.gn
@@ -17,6 +17,7 @@
   sources = [
     "gamepad.cc",
     "gamepad.h",
+    "gamepads.cc",
     "gamepads.h",
   ]
   # Do not add deps here per the above comment.
diff --git a/device/gamepad/public/cpp/gamepad.cc b/device/gamepad/public/cpp/gamepad.cc
index bd5bf4ed..1eec089 100644
--- a/device/gamepad/public/cpp/gamepad.cc
+++ b/device/gamepad/public/cpp/gamepad.cc
@@ -6,6 +6,11 @@
 
 namespace device {
 
+const size_t Gamepad::kIdLengthCap;
+const size_t Gamepad::kMappingLengthCap;
+const size_t Gamepad::kAxesLengthCap;
+const size_t Gamepad::kButtonsLengthCap;
+
 Gamepad::Gamepad()
     : connected(false),
       timestamp(0),
diff --git a/device/gamepad/public/cpp/gamepads.cc b/device/gamepad/public/cpp/gamepads.cc
new file mode 100644
index 0000000..82f8c70
--- /dev/null
+++ b/device/gamepad/public/cpp/gamepads.cc
@@ -0,0 +1,11 @@
+// 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 "device/gamepad/public/cpp/gamepads.h"
+
+namespace device {
+
+const size_t Gamepads::kItemsLengthCap;
+
+}  // namespace device
diff --git a/device/gamepad/public/mojom/gamepad.mojom b/device/gamepad/public/mojom/gamepad.mojom
index 415395f..1d51cdac 100644
--- a/device/gamepad/public/mojom/gamepad.mojom
+++ b/device/gamepad/public/mojom/gamepad.mojom
@@ -67,8 +67,19 @@
 };
 
 interface GamepadObserver {
-  GamepadConnected(int32 index, Gamepad gamepad);
-  GamepadDisconnected(int32 index, Gamepad gamepad);
+  // Called when a gamepad is connected. |index| is the index of the gamepad in
+  // the gamepad array, and |gamepad| is a reference to the connected gamepad.
+  GamepadConnected(uint32 index, Gamepad gamepad);
+
+  // Called when a gamepad is disconnected. |index| is the former index of the
+  // gamepad in the gamepad array, and |gamepad| is a reference to the
+  // connected gamepad.
+  GamepadDisconnected(uint32 index, Gamepad gamepad);
+
+  // Called when a button or axis is changed on a connected gamepad. |index| is
+  // the index of the gamepad in the gamepad array, and |gamepad| is a reference
+  // to the gamepad.
+  GamepadButtonOrAxisChanged(uint32 index, Gamepad gamepad);
 };
 
 // Asks the browser process to start polling, and return a shared memory
@@ -102,9 +113,9 @@
 };
 
 interface GamepadHapticsManager {
-  PlayVibrationEffectOnce(int32 pad_index,
+  PlayVibrationEffectOnce(uint32 pad_index,
                           GamepadHapticEffectType type,
                           GamepadEffectParameters params)
       => (GamepadHapticsResult result);
-  ResetVibrationActuator(int32 pad_index) => (GamepadHapticsResult result);
+  ResetVibrationActuator(uint32 pad_index) => (GamepadHapticsResult result);
 };
diff --git a/docs/speed/perf_lab_platforms.md b/docs/speed/perf_lab_platforms.md
index 341d13d..97b6ecb67 100644
--- a/docs/speed/perf_lab_platforms.md
+++ b/docs/speed/perf_lab_platforms.md
@@ -13,6 +13,7 @@
    7](https://build.chromium.org/p/chromium.perf/builders/Android%20Nexus7v2%20Perf)
  * [Android
    One](https://build.chromium.org/p/chromium.perf/builders/Android%20One%20Perf)
+ * [Android Go](https://ci.chromium.org/buildbot/chromium.perf/android-go-perf/)
 
 ## Mac
 
diff --git a/docs/tab_helpers.md b/docs/tab_helpers.md
index ce4bcf5..b5807c38 100644
--- a/docs/tab_helpers.md
+++ b/docs/tab_helpers.md
@@ -63,8 +63,6 @@
 
   DISALLOW_COPY_AND_ASSIGN(TitleLoggerTabHelper);
 };
-
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(TitleLoggerTabHelper);
 ```
 
 We want each tab to have this `WebContentsObserver` attached to it, so that it
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index 1c7ad758..3cec0911 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -62,11 +62,11 @@
       target_client_(std::move(client)),
       proxied_client_binding_(this),
       weak_factory_(this) {
-  // If there is a client error, remove this request from the proxy. |factory_|
-  // outlives this class, so base::Unretained is safe.
+  // If there is a client error, clean up the request.
   target_client_.set_connection_error_handler(base::BindOnce(
-      &WebRequestProxyingURLLoaderFactory::RemoveRequest,
-      base::Unretained(factory_), network_service_request_id_, request_id_));
+      &WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
+      weak_factory_.GetWeakPtr(),
+      network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
 }
 
 WebRequestProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() {
@@ -79,6 +79,7 @@
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::Restart() {
+  request_completed_ = false;
   // Derive a new WebRequestInfo value any time |Restart()| is called, because
   // the details in |request_| may have changed e.g. if we've been redirected.
   info_.emplace(
@@ -496,6 +497,7 @@
       redirect_info.new_url);
   target_client_->OnReceiveRedirect(redirect_info, current_response_);
   request_.url = redirect_info.new_url;
+  request_completed_ = true;
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::
@@ -529,13 +531,14 @@
 
   continuation.Run(net::OK);
 }
-
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError(
     const network::URLLoaderCompletionStatus& status) {
-  target_client_->OnComplete(status);
-  ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
-      factory_->browser_context_, factory_->info_map_, &info_.value(),
-      true /* started */, status.error_code);
+  if (!request_completed_) {
+    target_client_->OnComplete(status);
+    ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
+        factory_->browser_context_, factory_->info_map_, &info_.value(),
+        true /* started */, status.error_code);
+  }
 
   // Deletes |this|.
   factory_->RemoveRequest(network_service_request_id_, request_id_);
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 32650bac..d8c3fee 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -163,6 +163,8 @@
     // lifetime.
     base::Optional<net::AuthCredentials> auth_credentials_;
 
+    bool request_completed_ = false;
+
     base::WeakPtrFactory<InProgressRequest> weak_factory_;
 
     DISALLOW_COPY_AND_ASSIGN(InProgressRequest);
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index a9b7ce30..ad2d4da 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -440,6 +440,7 @@
   INPUT_METHOD_PRIVATE_ON_FOCUS,
   SYSTEM_POWER_SOURCE_ONPOWERCHANGED,
   WEB_REQUEST_ON_ACTION_IGNORED,
+  ARC_APPS_PRIVATE_ON_INSTALLED,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc
index 208b7e4..6fbfd3d 100644
--- a/extensions/browser/updater/extension_downloader.cc
+++ b/extensions/browser/updater/extension_downloader.cc
@@ -20,9 +20,11 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "base/version.h"
 #include "components/update_client/update_query_params.h"
+#include "content/public/browser/file_url_loader.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/browser/extension_file_task_runner.h"
@@ -37,12 +39,12 @@
 #include "net/base/backoff_entry.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
-#include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 using base::Time;
 using base::TimeDelta;
@@ -112,15 +114,21 @@
                                 kMaxRetries + 1);                         \
   }
 
-bool ShouldRetryRequest(const net::URLRequestStatus& status,
-                        int response_code) {
-  // Retry if the response code is a server error, or the request failed because
-  // of network errors as opposed to file errors.
-  return (response_code >= 500 && status.is_success()) ||
-         status.status() == net::URLRequestStatus::FAILED ||
-         // Note: URLRequestJob::OnSuspend() results in a canceled status; if
-         // the request is suspended, we should retry.
-         status.status() == net::URLRequestStatus::CANCELED;
+bool ShouldRetryRequest(network::SimpleURLLoader* loader) {
+  DCHECK(loader);
+
+  // Since HTTP errors are now presented as ERR_FAILED by default, this will
+  // let both network and HTTP errors through.
+  if (loader->NetError() == net::OK)
+    return false;
+
+  // If it failed without receiving response headers, retry.
+  if (!loader->ResponseInfo() || !loader->ResponseInfo()->headers)
+    return true;
+
+  // If a response code was received, only retry on 5xx codes (server errors).
+  int response_code = loader->ResponseInfo()->headers->response_code();
+  return response_code >= 500 && response_code < 600;
 }
 
 // This parses and updates a URL query such that the value of the |authuser|
@@ -200,25 +208,27 @@
 
 ExtensionDownloader::ExtensionDownloader(
     ExtensionDownloaderDelegate* delegate,
-    net::URLRequestContextGetter* request_context,
-    service_manager::Connector* connector)
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    service_manager::Connector* connector,
+    const base::FilePath& profile_path)
     : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
       delegate_(delegate),
-      request_context_(request_context),
+      url_loader_factory_(std::move(url_loader_factory)),
+      profile_path_for_url_loader_factory_(profile_path),
       connector_(connector),
       manifests_queue_(
           &kDefaultBackoffPolicy,
-          base::BindRepeating(&ExtensionDownloader::CreateManifestFetcher,
+          base::BindRepeating(&ExtensionDownloader::CreateManifestLoader,
                               base::Unretained(this))),
       extensions_queue_(
           &kDefaultBackoffPolicy,
-          base::BindRepeating(&ExtensionDownloader::CreateExtensionFetcher,
+          base::BindRepeating(&ExtensionDownloader::CreateExtensionLoader,
                               base::Unretained(this))),
       extension_cache_(nullptr),
       token_service_(nullptr),
       weak_ptr_factory_(this) {
   DCHECK(delegate_);
-  DCHECK(request_context_.get());
+  DCHECK(url_loader_factory_);
 }
 
 ExtensionDownloader::~ExtensionDownloader() {
@@ -239,7 +249,7 @@
 
   // If the extension updates itself from the gallery, ignore any update URL
   // data.  At the moment there is no extra data that an extension can
-  // communicate to the the gallery update servers.
+  // communicate to the gallery update servers.
   std::string update_url_data;
   if (!ManifestURL::UpdatesFromGallery(&extension))
     extra.update_url_data = delegate_->GetUpdateUrlData(extension.id());
@@ -487,7 +497,21 @@
   }
 }
 
-void ExtensionDownloader::CreateManifestFetcher() {
+network::mojom::URLLoaderFactory* ExtensionDownloader::GetURLLoaderFactoryToUse(
+    const GURL& url) {
+  if (!url.SchemeIsFile()) {
+    DCHECK(url_loader_factory_);
+    return url_loader_factory_.get();
+  }
+
+  // file:// URL support.
+  auto file_url_loader_factory =
+      content::CreateFileURLLoaderFactory(profile_path_for_url_loader_factory_);
+  file_url_loader_factory_ = std::move(file_url_loader_factory);
+  return file_url_loader_factory_.get();
+}
+
+void ExtensionDownloader::CreateManifestLoader() {
   const ManifestFetchData* active_request = manifests_queue_.active_request();
   std::vector<base::StringPiece> id_vector(
       active_request->extension_ids().begin(),
@@ -531,69 +555,61 @@
             }
           }
         })");
-  manifest_fetcher_ =
-      net::URLFetcher::Create(kManifestFetcherId, active_request->full_url(),
-                              net::URLFetcher::GET, this, traffic_annotation);
-  manifest_fetcher_->SetRequestContext(request_context_.get());
-  manifest_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
-                                  net::LOAD_DO_NOT_SAVE_COOKIES |
-                                  net::LOAD_DISABLE_CACHE);
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = active_request->full_url(),
+  resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
+                                 net::LOAD_DO_NOT_SAVE_COOKIES |
+                                 net::LOAD_DISABLE_CACHE;
 
   // Send traffic-management headers to the webstore.
   // https://bugs.chromium.org/p/chromium/issues/detail?id=647516
   if (extension_urls::IsWebstoreUpdateUrl(active_request->full_url())) {
-    manifest_fetcher_->AddExtraRequestHeader(base::StringPrintf(
-        "%s: %s", kUpdateInteractivityHeader,
-        active_request->foreground_check() ? kUpdateInteractivityForeground
-                                           : kUpdateInteractivityBackground));
-    manifest_fetcher_->AddExtraRequestHeader(
-        base::StringPrintf("%s: %s", kUpdateAppIdHeader, id_list.c_str()));
-    manifest_fetcher_->AddExtraRequestHeader(base::StringPrintf(
-        "%s: %s-%s", kUpdateUpdaterHeader,
-        UpdateQueryParams::GetProdIdString(UpdateQueryParams::CRX),
-        UpdateQueryParams::GetProdVersion().c_str()));
+    resource_request->headers.SetHeader(kUpdateInteractivityHeader,
+                                        active_request->foreground_check()
+                                            ? kUpdateInteractivityForeground
+                                            : kUpdateInteractivityBackground);
+    resource_request->headers.SetHeader(kUpdateAppIdHeader, id_list);
+    resource_request->headers.SetHeader(
+        kUpdateUpdaterHeader,
+        base::StringPrintf(
+            "%s-%s", UpdateQueryParams::GetProdIdString(UpdateQueryParams::CRX),
+            UpdateQueryParams::GetProdVersion().c_str()));
   }
 
+  manifest_loader_ = network::SimpleURLLoader::Create(
+      std::move(resource_request), traffic_annotation);
   // Update checks can be interrupted if a network change is detected; this is
   // common for the retail mode AppPack on ChromeOS. Retrying once should be
   // enough to recover in those cases; let the fetcher retry up to 3 times
   // just in case. http://crosbug.com/130602
-  manifest_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
-  manifest_fetcher_->Start();
+  const int kMaxRetries = 3;
+  manifest_loader_->SetRetryOptions(
+      kMaxRetries,
+      network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
+
+  network::mojom::URLLoaderFactory* url_loader_factory_to_use =
+      GetURLLoaderFactoryToUse(active_request->full_url());
+  manifest_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory_to_use,
+      base::BindOnce(&ExtensionDownloader::OnManifestLoadComplete,
+                     base::Unretained(this)));
 }
 
-void ExtensionDownloader::OnURLFetchComplete(const net::URLFetcher* source) {
-  VLOG(2) << source->GetResponseCode() << " " << source->GetURL();
+void ExtensionDownloader::OnManifestLoadComplete(
+    std::unique_ptr<std::string> response_body) {
+  GURL url = manifest_loader_->GetFinalURL();
+  int response_code = -1;
+  if (manifest_loader_->ResponseInfo() &&
+      manifest_loader_->ResponseInfo()->headers)
+    response_code = manifest_loader_->ResponseInfo()->headers->response_code();
 
-  if (source == manifest_fetcher_.get()) {
-    std::string data;
-    source->GetResponseAsString(&data);
-    OnManifestFetchComplete(source->GetURL(),
-                            source->GetStatus(),
-                            source->GetResponseCode(),
-                            source->GetBackoffDelay(),
-                            data);
-  } else if (source == extension_fetcher_.get()) {
-    OnCRXFetchComplete(source,
-                       source->GetURL(),
-                       source->GetStatus(),
-                       source->GetResponseCode(),
-                       source->GetBackoffDelay());
-  } else {
-    NOTREACHED();
-  }
-}
+  VLOG(2) << response_code << " " << url;
 
-void ExtensionDownloader::OnManifestFetchComplete(
-    const GURL& url,
-    const net::URLRequestStatus& status,
-    int response_code,
-    const base::TimeDelta& backoff_delay,
-    const std::string& data) {
+  const base::TimeDelta& backoff_delay = base::TimeDelta::FromMilliseconds(0);
+
   // We want to try parsing the manifest, and if it indicates updates are
   // available, we want to fire off requests to fetch those updates.
-  if (status.status() == net::URLRequestStatus::SUCCESS &&
-      (response_code == 200 || (url.SchemeIsFile() && data.length() > 0))) {
+  if (response_body && !response_body->empty()) {
     RETRY_HISTOGRAM("ManifestFetchSuccess",
                     manifests_queue_.active_request_failure_count(),
                     url);
@@ -601,11 +617,11 @@
     auto callback = base::BindOnce(&ExtensionDownloader::HandleManifestResults,
                                    weak_ptr_factory_.GetWeakPtr(),
                                    manifests_queue_.reset_active_request());
-    ParseUpdateManifest(connector_, data, std::move(callback));
+    ParseUpdateManifest(connector_, *response_body, std::move(callback));
   } else {
     VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec()
             << "' response code:" << response_code;
-    if (ShouldRetryRequest(status, response_code) &&
+    if (ShouldRetryRequest(manifest_loader_.get()) &&
         manifests_queue_.active_request_failure_count() < kMaxRetries) {
       manifests_queue_.RetryRequest(backoff_delay);
     } else {
@@ -618,7 +634,8 @@
           ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED);
     }
   }
-  manifest_fetcher_.reset();
+  manifest_loader_.reset();
+  file_url_loader_factory_.reset();
   manifests_queue_.reset_active_request();
 
   // If we have any pending manifest requests, fire off the next one.
@@ -905,8 +922,44 @@
   }
 }
 
-void ExtensionDownloader::CreateExtensionFetcher() {
+void ExtensionDownloader::CreateExtensionLoader() {
   const ExtensionFetch* fetch = extensions_queue_.active_request();
+  extension_loader_resource_request_ =
+      std::make_unique<network::ResourceRequest>();
+  extension_loader_resource_request_->url = fetch->url;
+
+  int load_flags = net::LOAD_DISABLE_CACHE;
+  bool is_secure = fetch->url.SchemeIsCryptographic();
+  if (fetch->credentials != ExtensionFetch::CREDENTIALS_COOKIES || !is_secure) {
+    load_flags |= net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  }
+  extension_loader_resource_request_->load_flags = load_flags;
+
+  if (fetch->credentials == ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN &&
+      is_secure) {
+    if (access_token_.empty()) {
+      // We should try OAuth2, but we have no token cached. This
+      // ExtensionLoader will be started once the token fetch is complete,
+      // in either OnTokenFetchSuccess or OnTokenFetchFailure.
+      DCHECK(token_service_);
+      DCHECK(!webstore_account_callback_.is_null());
+      OAuth2TokenService::ScopeSet webstore_scopes;
+      webstore_scopes.insert(kWebstoreOAuth2Scope);
+      access_token_request_ = token_service_->StartRequest(
+          webstore_account_callback_.Run(), webstore_scopes, this);
+      return;
+    }
+    extension_loader_resource_request_->headers.SetHeader(
+        net::HttpRequestHeaders::kAuthorization,
+        base::StringPrintf("Bearer %s", access_token_.c_str()));
+  }
+
+  VLOG(2) << "Starting load of " << fetch->url << " for " << fetch->id;
+
+  StartExtensionLoader();
+}
+
+void ExtensionDownloader::StartExtensionLoader() {
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("extension_crx_fetcher", R"(
         semantics {
@@ -937,66 +990,44 @@
             }
           }
         })");
-  extension_fetcher_ =
-      net::URLFetcher::Create(kExtensionFetcherId, fetch->url,
-                              net::URLFetcher::GET, this, traffic_annotation);
-  extension_fetcher_->SetRequestContext(request_context_.get());
-  extension_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
 
-  int load_flags = net::LOAD_DISABLE_CACHE;
-  bool is_secure = fetch->url.SchemeIsCryptographic();
-  if (fetch->credentials != ExtensionFetch::CREDENTIALS_COOKIES || !is_secure) {
-    load_flags |= net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
-  }
-  extension_fetcher_->SetLoadFlags(load_flags);
+  last_extension_loader_resource_request_headers_for_testing_ =
+      extension_loader_resource_request_->headers;
+  last_extension_loader_load_flags_for_testing_ =
+      extension_loader_resource_request_->load_flags;
 
-  // Download CRX files to a temp file. The blacklist is small and will be
-  // processed in memory, so it is fetched into a string.
-  if (fetch->id != kBlacklistAppID) {
-    extension_fetcher_->SaveResponseToTemporaryFile(
-        GetExtensionFileTaskRunner());
-  }
+  network::mojom::URLLoaderFactory* url_loader_factory_to_use =
+      GetURLLoaderFactoryToUse(extension_loader_resource_request_->url);
+  extension_loader_ = network::SimpleURLLoader::Create(
+      std::move(extension_loader_resource_request_), traffic_annotation);
+  const int kMaxRetries = 3;
+  extension_loader_->SetRetryOptions(
+      kMaxRetries,
+      network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
 
-  if (fetch->credentials == ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN &&
-      is_secure) {
-    if (access_token_.empty()) {
-      // We should try OAuth2, but we have no token cached. This
-      // ExtensionFetcher will be started once the token fetch is complete,
-      // in either OnTokenFetchSuccess or OnTokenFetchFailure.
-      DCHECK(token_service_);
-      DCHECK(!webstore_account_callback_.is_null());
-      OAuth2TokenService::ScopeSet webstore_scopes;
-      webstore_scopes.insert(kWebstoreOAuth2Scope);
-      access_token_request_ = token_service_->StartRequest(
-          webstore_account_callback_.Run(), webstore_scopes, this);
-      return;
-    }
-    extension_fetcher_->AddExtraRequestHeader(
-        base::StringPrintf("%s: Bearer %s",
-                           net::HttpRequestHeaders::kAuthorization,
-                           access_token_.c_str()));
-  }
-
-  VLOG(2) << "Starting fetch of " << fetch->url << " for " << fetch->id;
-  extension_fetcher_->Start();
+  extension_loader_->DownloadToTempFile(
+      url_loader_factory_to_use,
+      base::BindOnce(&ExtensionDownloader::OnExtensionLoadComplete,
+                     base::Unretained(this)));
 }
 
-void ExtensionDownloader::OnCRXFetchComplete(
-    const net::URLFetcher* source,
-    const GURL& url,
-    const net::URLRequestStatus& status,
-    int response_code,
-    const base::TimeDelta& backoff_delay) {
+void ExtensionDownloader::OnExtensionLoadComplete(base::FilePath crx_path) {
+  GURL url = extension_loader_->GetFinalURL();
+  net::URLRequestStatus status =
+      net::URLRequestStatus::FromError(extension_loader_->NetError());
+  int response_code = -1;
+  if (extension_loader_->ResponseInfo() &&
+      extension_loader_->ResponseInfo()->headers) {
+    response_code = extension_loader_->ResponseInfo()->headers->response_code();
+  }
+  const base::TimeDelta& backoff_delay = base::TimeDelta::FromMilliseconds(0);
+
   ExtensionFetch& active_request = *extensions_queue_.active_request();
   const std::string& id = active_request.id;
-  if (status.status() == net::URLRequestStatus::SUCCESS &&
-      (response_code == 200 || url.SchemeIsFile())) {
+  if (!crx_path.empty()) {
     RETRY_HISTOGRAM("CrxFetchSuccess",
                     extensions_queue_.active_request_failure_count(),
                     url);
-    base::FilePath crx_path;
-    // Take ownership of the file at |crx_path|.
-    CHECK(source->GetResponseAsFilePath(true, &crx_path));
     std::unique_ptr<ExtensionFetch> fetch_data =
         extensions_queue_.reset_active_request();
     if (extension_cache_) {
@@ -1015,14 +1046,16 @@
   } else if (IterateFetchCredentialsAfterFailure(
                  &active_request, status, response_code)) {
     extensions_queue_.RetryRequest(backoff_delay);
+    delegate_->OnExtensionDownloadRetryForTests();
   } else {
     const std::set<int>& request_ids = active_request.request_ids;
     const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id];
     VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
             << "' response code:" << response_code;
-    if (ShouldRetryRequest(status, response_code) &&
+    if (ShouldRetryRequest(extension_loader_.get()) &&
         extensions_queue_.active_request_failure_count() < kMaxRetries) {
       extensions_queue_.RetryRequest(backoff_delay);
+      delegate_->OnExtensionDownloadRetryForTests();
     } else {
       RETRY_HISTOGRAM("CrxFetchFailure",
                       extensions_queue_.active_request_failure_count(),
@@ -1036,7 +1069,8 @@
     extensions_queue_.reset_active_request();
   }
 
-  extension_fetcher_.reset();
+  extension_loader_.reset();
+  file_url_loader_factory_.reset();
 
   // If there are any pending downloads left, start the next one.
   extensions_queue_.StartNextRequest();
@@ -1070,10 +1104,8 @@
     ExtensionFetch* fetch,
     const net::URLRequestStatus& status,
     int response_code) {
-  bool auth_failure = status.status() == net::URLRequestStatus::CANCELED ||
-                      (status.status() == net::URLRequestStatus::SUCCESS &&
-                       (response_code == net::HTTP_UNAUTHORIZED ||
-                        response_code == net::HTTP_FORBIDDEN));
+  bool auth_failure = response_code == net::HTTP_UNAUTHORIZED ||
+                      response_code == net::HTTP_FORBIDDEN;
   if (!auth_failure) {
     return false;
   }
@@ -1130,11 +1162,10 @@
     const std::string& access_token,
     const base::Time& expiration_time) {
   access_token_ = access_token;
-  extension_fetcher_->AddExtraRequestHeader(
-      base::StringPrintf("%s: Bearer %s",
-                         net::HttpRequestHeaders::kAuthorization,
-                         access_token_.c_str()));
-  extension_fetcher_->Start();
+  extension_loader_resource_request_->headers.SetHeader(
+      net::HttpRequestHeaders::kAuthorization,
+      base::StringPrintf("Bearer %s", access_token_.c_str()));
+  StartExtensionLoader();
 }
 
 void ExtensionDownloader::OnGetTokenFailure(
@@ -1142,7 +1173,7 @@
     const GoogleServiceAuthError& error) {
   // If we fail to get an access token, kick the pending fetch and let it fall
   // back on cookies.
-  extension_fetcher_->Start();
+  StartExtensionLoader();
 }
 
 ManifestFetchData* ExtensionDownloader::CreateManifestFetchData(
diff --git a/extensions/browser/updater/extension_downloader.h b/extensions/browser/updater/extension_downloader.h
index 40b6646..731a42f 100644
--- a/extensions/browser/updater/extension_downloader.h
+++ b/extensions/browser/updater/extension_downloader.h
@@ -22,15 +22,22 @@
 #include "extensions/browser/updater/safe_manifest_parser.h"
 #include "extensions/common/extension.h"
 #include "google_apis/gaia/oauth2_token_service.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "net/http/http_request_headers.h"
 #include "url/gurl.h"
 
 namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
 class URLRequestStatus;
 }
 
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+namespace mojom {
+class URLLoaderFactory;
+}
+struct ResourceRequest;
+}  // namespace network
+
 namespace service_manager {
 class Connector;
 }
@@ -53,8 +60,7 @@
 // the crx file when updates are found. It uses a |ExtensionDownloaderDelegate|
 // that takes ownership of the downloaded crx files, and handles events during
 // the update check.
-class ExtensionDownloader : public net::URLFetcherDelegate,
-                            public OAuth2TokenService::Consumer {
+class ExtensionDownloader : public OAuth2TokenService::Consumer {
  public:
   // A closure which constructs a new ExtensionDownloader to be owned by the
   // caller.
@@ -68,9 +74,11 @@
 
   // |delegate| is stored as a raw pointer and must outlive the
   // ExtensionDownloader.
-  ExtensionDownloader(ExtensionDownloaderDelegate* delegate,
-                      net::URLRequestContextGetter* request_context,
-                      service_manager::Connector* connector);
+  ExtensionDownloader(
+      ExtensionDownloaderDelegate* delegate,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      service_manager::Connector* connector,
+      const base::FilePath& profile_path = base::FilePath());
   ~ExtensionDownloader() override;
 
   // Adds |extension| to the list of extensions to check for updates.
@@ -239,18 +247,15 @@
   // Begins an update check.
   void StartUpdateCheck(std::unique_ptr<ManifestFetchData> fetch_data);
 
-  // Called by RequestQueue when a new manifest fetch request is started.
-  void CreateManifestFetcher();
+  // Returns the URLLoaderFactory instance to be used, depending on whether
+  // the URL being handled is file:// or not.
+  network::mojom::URLLoaderFactory* GetURLLoaderFactoryToUse(const GURL& url);
 
-  // net::URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  // Called by RequestQueue when a new manifest load request is started.
+  void CreateManifestLoader();
 
   // Handles the result of a manifest fetch.
-  void OnManifestFetchComplete(const GURL& url,
-                               const net::URLRequestStatus& status,
-                               int response_code,
-                               const base::TimeDelta& backoff_delay,
-                               const std::string& data);
+  void OnManifestLoadComplete(std::unique_ptr<std::string> response_body);
 
   // Once a manifest is parsed, this starts fetches of any relevant crx files.
   // If |results| is null, it means something went wrong when parsing it.
@@ -275,15 +280,12 @@
   // Begins (or queues up) download of an updated extension.
   void FetchUpdatedExtension(std::unique_ptr<ExtensionFetch> fetch_data);
 
-  // Called by RequestQueue when a new extension fetch request is started.
-  void CreateExtensionFetcher();
+  // Called by RequestQueue when a new extension load request is started.
+  void CreateExtensionLoader();
+  void StartExtensionLoader();
 
   // Handles the result of a crx fetch.
-  void OnCRXFetchComplete(const net::URLFetcher* source,
-                          const GURL& url,
-                          const net::URLRequestStatus& status,
-                          int response_code,
-                          const base::TimeDelta& backoff_delay);
+  void OnExtensionLoadComplete(base::FilePath crx_path);
 
   // Invokes OnExtensionDownloadFailed() on the |delegate_| for each extension
   // in the set, with |error| as the reason for failure.
@@ -344,8 +346,14 @@
   // ExtensionDownloader, and that fills in optional ping and update url data.
   ExtensionDownloaderDelegate* delegate_;
 
-  // The request context to use for the URLFetchers.
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
+  // The URL loader factory to use for the SimpleURLLoaders.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+  // The URL loader factory exclusively used to load file:// URLs.
+  std::unique_ptr<network::mojom::URLLoaderFactory> file_url_loader_factory_;
+
+  // The profile path used to load file:// URLs. It can be invalid.
+  base::FilePath profile_path_for_url_loader_factory_;
 
   // The connector to the ServiceManager.
   service_manager::Connector* connector_;
@@ -361,9 +369,10 @@
                             std::vector<std::unique_ptr<ManifestFetchData>>>;
   FetchMap fetches_preparing_;
 
-  // Outstanding url fetch requests for manifests and updates.
-  std::unique_ptr<net::URLFetcher> manifest_fetcher_;
-  std::unique_ptr<net::URLFetcher> extension_fetcher_;
+  // Outstanding url loader requests for manifests and updates.
+  std::unique_ptr<network::SimpleURLLoader> manifest_loader_;
+  std::unique_ptr<network::SimpleURLLoader> extension_loader_;
+  std::unique_ptr<network::ResourceRequest> extension_loader_resource_request_;
 
   // Pending manifests and extensions to be fetched when the appropriate fetcher
   // is available.
@@ -401,6 +410,10 @@
   // to update URLs which match this domain. Defaults to empty (no domain).
   std::string ping_enabled_domain_;
 
+  net::HttpRequestHeaders
+      last_extension_loader_resource_request_headers_for_testing_;
+  int last_extension_loader_load_flags_for_testing_ = 0;
+
   // Used to create WeakPtrs to |this|.
   base::WeakPtrFactory<ExtensionDownloader> weak_ptr_factory_;
 
diff --git a/extensions/browser/updater/extension_downloader_delegate.cc b/extensions/browser/updater/extension_downloader_delegate.cc
index 5ccf9c9..3dce580 100644
--- a/extensions/browser/updater/extension_downloader_delegate.cc
+++ b/extensions/browser/updater/extension_downloader_delegate.cc
@@ -25,6 +25,8 @@
     const std::set<int>& request_id) {
 }
 
+void ExtensionDownloaderDelegate::OnExtensionDownloadRetryForTests() {}
+
 bool ExtensionDownloaderDelegate::GetPingDataForExtension(
     const std::string& id,
     ManifestFetchData::PingData* ping) {
diff --git a/extensions/browser/updater/extension_downloader_delegate.h b/extensions/browser/updater/extension_downloader_delegate.h
index 4e5c8854..0331b248 100644
--- a/extensions/browser/updater/extension_downloader_delegate.h
+++ b/extensions/browser/updater/extension_downloader_delegate.h
@@ -102,6 +102,11 @@
                                            const std::set<int>& request_ids,
                                            const InstallCallback& callback) = 0;
 
+  // Invoked when an extension fails to load, but a retry is triggered.
+  // It allows unittests to easily set up and verify resourse request and
+  // load results between a failure / retry sequence.
+  virtual void OnExtensionDownloadRetryForTests();
+
   // The remaining methods are used by the ExtensionDownloader to retrieve
   // information about extensions from the delegate.
 
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index 3191579..fbdd8920 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -431,7 +431,8 @@
       "B6C2EFAB3EC3BF6EF03701408B6B09A67B2D0069",  // http://crbug.com/642141
       "96FF2FFA5C9173C76D47184B3E86D267B37781DE",  // http://crbug.com/642141
       "0136FCB13DB29FD5CD442F56E59E53B61F1DF96F",  // http://crbug.com/642141
-      "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F"   // PDF Viewer
+      "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F",  // PDF Viewer
+      "75C7F4B720314B6CB1B5817CD86089DB95CD2461"   // Chromevox on chromecast
     ]
   },
   "nativeMessaging": {
diff --git a/extensions/shell/browser/api/identity/DEPS b/extensions/shell/browser/api/identity/DEPS
new file mode 100644
index 0000000..ea8149d
--- /dev/null
+++ b/extensions/shell/browser/api/identity/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+services/network/public/cpp",
+]
diff --git a/extensions/shell/browser/api/identity/identity_api.cc b/extensions/shell/browser/api/identity/identity_api.cc
index cc04be29..5e20632 100644
--- a/extensions/shell/browser/api/identity/identity_api.cc
+++ b/extensions/shell/browser/api/identity/identity_api.cc
@@ -112,8 +112,8 @@
 
   // Use the logging-in-user access token to mint an access token for this app.
   mint_token_flow_->Start(
-      content::BrowserContext::GetDefaultStoragePartition(browser_context())->
-          GetURLRequestContext(),
+      content::BrowserContext::GetDefaultStoragePartition(browser_context())
+          ->GetURLLoaderFactoryForBrowserProcess(),
       access_token);
 }
 
diff --git a/extensions/shell/browser/api/identity/identity_api_unittest.cc b/extensions/shell/browser/api/identity/identity_api_unittest.cc
index d9e7e45c..55b7bcb 100644
--- a/extensions/shell/browser/api/identity/identity_api_unittest.cc
+++ b/extensions/shell/browser/api/identity/identity_api_unittest.cc
@@ -14,6 +14,7 @@
 #include "extensions/common/value_builder.h"
 #include "extensions/shell/browser/shell_oauth2_token_service.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace extensions {
 namespace shell {
@@ -43,7 +44,7 @@
   ~MockOAuth2MintTokenFlow() override {}
 
   // OAuth2ApiCallFlow:
-  void Start(net::URLRequestContextGetter* context,
+  void Start(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
              const std::string& access_token) override {
     EXPECT_EQ("logged-in-user-token", access_token);
     delegate_->OnMintTokenSuccess("app-access-token", 12345);
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn
index 4567d96..9ceb65e0 100644
--- a/google_apis/BUILD.gn
+++ b/google_apis/BUILD.gn
@@ -245,6 +245,7 @@
     "gaia/ubertoken_fetcher_unittest.cc",
     "google_api_keys_unittest.cc",
     "google_api_keys_unittest.h",
+    "test/run_all_unittests.cc",
   ]
 
   data = [
@@ -257,7 +258,7 @@
     ":google_apis",
     ":test_support",
     "//base",
-    "//base/test:run_all_unittests",
+    "//base/test:test_support",
     "//mojo/core/embedder",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
index 378092e6..383752a 100644
--- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc
+++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -23,7 +23,6 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/mock_url_fetcher_factory.h"
 #include "google_apis/google_api_keys.h"
-#include "mojo/core/embedder/embedder.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
@@ -127,8 +126,6 @@
   GURL deprecated_client_login_to_oauth2_url_;
 
  protected:
-  void SetUp() override { mojo::core::Init(); }
-
   void OnResourceIntercepted(const network::ResourceRequest& resource) {
     received_requests_.push_back(resource);
   }
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
index 10c59b8e..b1ae6b5 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
@@ -14,7 +14,6 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
-#include "mojo/core/embedder/embedder.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -80,7 +79,6 @@
     url_loader_factory_.SetInterceptor(base::BindRepeating(
         &URLLoaderFactoryInterceptor::Intercept,
         base::Unretained(&url_loader_factory_interceptor_)));
-    mojo::core::Init();
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/google_apis/gaia/oauth2_api_call_flow.cc b/google_apis/gaia/oauth2_api_call_flow.cc
index f74f63d..86b8b75 100644
--- a/google_apis/gaia/oauth2_api_call_flow.cc
+++ b/google_apis/gaia/oauth2_api_call_flow.cc
@@ -13,20 +13,15 @@
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_status.h"
-
-using net::URLFetcher;
-using net::URLFetcherDelegate;
-using net::URLRequestContextGetter;
-using net::URLRequestStatus;
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 namespace {
-static const char kAuthorizationHeaderFormat[] =
-    "Authorization: Bearer %s";
+static const char kAuthorizationValueFormat[] = "Bearer %s";
 
-static std::string MakeAuthorizationHeader(const std::string& auth_token) {
-  return base::StringPrintf(kAuthorizationHeaderFormat, auth_token.c_str());
+static std::string MakeAuthorizationValue(const std::string& auth_token) {
+  return base::StringPrintf(kAuthorizationValueFormat, auth_token.c_str());
 }
 }  // namespace
 
@@ -35,27 +30,34 @@
 
 OAuth2ApiCallFlow::~OAuth2ApiCallFlow() {}
 
-void OAuth2ApiCallFlow::Start(net::URLRequestContextGetter* context,
-                              const std::string& access_token) {
+void OAuth2ApiCallFlow::Start(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    const std::string& access_token) {
   CHECK(state_ == INITIAL);
   state_ = API_CALL_STARTED;
 
-  url_fetcher_ = CreateURLFetcher(context, access_token);
-  url_fetcher_->Start();  // OnURLFetchComplete will be called.
+  url_loader_ = CreateURLLoader(access_token);
+  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory.get(),
+      base::BindOnce(&OAuth2ApiCallFlow::OnURLLoadComplete,
+                     base::Unretained(this)));
 }
 
-void OAuth2ApiCallFlow::EndApiCall(const net::URLFetcher* source) {
+void OAuth2ApiCallFlow::EndApiCall(std::unique_ptr<std::string> body) {
   CHECK_EQ(API_CALL_STARTED, state_);
+  std::unique_ptr<network::SimpleURLLoader> source = std::move(url_loader_);
 
-  URLRequestStatus status = source->GetStatus();
-  int status_code = source->GetResponseCode();
-  if (!status.is_success() ||
+  int status_code = 0;
+  if (source->ResponseInfo() && source->ResponseInfo()->headers)
+    status_code = source->ResponseInfo()->headers->response_code();
+  if (source->NetError() != net::OK ||
       (status_code != net::HTTP_OK && status_code != net::HTTP_NO_CONTENT)) {
     state_ = ERROR_STATE;
-    ProcessApiCallFailure(source);
+    ProcessApiCallFailure(source->NetError(), source->ResponseInfo(),
+                          std::move(body));
   } else {
     state_ = API_CALL_DONE;
-    ProcessApiCallSuccess(source);
+    ProcessApiCallSuccess(source->ResponseInfo(), std::move(body));
   }
 }
 
@@ -63,47 +65,52 @@
   return "application/x-www-form-urlencoded";
 }
 
-net::URLFetcher::RequestType OAuth2ApiCallFlow::GetRequestTypeForBody(
-    const std::string& body) {
-  return body.empty() ? URLFetcher::GET : URLFetcher::POST;
+std::string OAuth2ApiCallFlow::GetRequestTypeForBody(const std::string& body) {
+  return body.empty() ? "GET" : "POST";
 }
 
-void OAuth2ApiCallFlow::OnURLFetchComplete(const net::URLFetcher* source) {
-  CHECK(source);
+void OAuth2ApiCallFlow::OnURLLoadComplete(std::unique_ptr<std::string> body) {
   CHECK_EQ(API_CALL_STARTED, state_);
-  EndApiCall(source);
+  EndApiCall(std::move(body));
 }
 
-std::unique_ptr<URLFetcher> OAuth2ApiCallFlow::CreateURLFetcher(
-    net::URLRequestContextGetter* context,
+std::unique_ptr<network::SimpleURLLoader> OAuth2ApiCallFlow::CreateURLLoader(
     const std::string& access_token) {
   std::string body = CreateApiCallBody();
-  net::URLFetcher::RequestType request_type = GetRequestTypeForBody(body);
+  std::string request_type = GetRequestTypeForBody(body);
   net::NetworkTrafficAnnotationTag traffic_annotation =
       CompleteNetworkTrafficAnnotation("oauth2_api_call_flow",
                                        GetNetworkTrafficAnnotationTag(), R"(
           policy {
             cookies_allowed: NO
           })");
-  std::unique_ptr<URLFetcher> result = net::URLFetcher::Create(
-      0, CreateApiCallUrl(), request_type, this, traffic_annotation);
 
-  gaia::MarkURLFetcherAsGaia(result.get());
-  result->SetRequestContext(context);
-  result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
-                       net::LOAD_DO_NOT_SAVE_COOKIES);
-  result->AddExtraRequestHeader(MakeAuthorizationHeader(access_token));
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = CreateApiCallUrl();
+  request->method = request_type;
+  request->load_flags =
+      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  request->headers.SetHeader("Authorization",
+                             MakeAuthorizationValue(access_token));
+  std::unique_ptr<network::SimpleURLLoader> result =
+      network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
+
+  // TODO(https://crbug.com/808498) re-add data use measurement once
+  // SimpleURLLoader supports it. Previously:
+  //     gaia::MarkURLFetcherAsGaia(result.get());
+
   // Fetchers are sometimes cancelled because a network change was detected,
   // especially at startup and after sign-in on ChromeOS. Retrying once should
   // be enough in those cases; let the fetcher retry up to 3 times just in case.
   // http://crbug.com/163710
-  result->SetAutomaticallyRetryOnNetworkChanges(3);
+  result->SetRetryOptions(3, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
+  result->SetAllowHttpErrorResults(true);
 
   // Even if the the body is empty, we still set the Content-Type because an
   // empty string may be a meaningful value. For example, a Protocol Buffer
   // message with only default values will be serialized as an empty string.
-  if (request_type != net::URLFetcher::GET)
-    result->SetUploadData(CreateApiCallBodyContentType(), body);
+  if (request_type != "GET")
+    result->AttachStringForUpload(body, CreateApiCallBodyContentType());
 
   return result;
 }
diff --git a/google_apis/gaia/oauth2_api_call_flow.h b/google_apis/gaia/oauth2_api_call_flow.h
index 34cbbdba..e3e214ab 100644
--- a/google_apis/gaia/oauth2_api_call_flow.h
+++ b/google_apis/gaia/oauth2_api_call_flow.h
@@ -9,32 +9,30 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
+namespace network {
+struct ResourceResponseHead;
+class SimpleURLLoader;
+class SharedURLLoaderFactory;
 }
 
 // Base class for all classes that implement a flow to call OAuth2 enabled APIs,
 // given an access token to the service.  This class abstracts the basic steps
 // and exposes template methods for sub-classes to implement for API specific
 // details.
-class OAuth2ApiCallFlow : public net::URLFetcherDelegate {
+class OAuth2ApiCallFlow {
  public:
   OAuth2ApiCallFlow();
 
-  ~OAuth2ApiCallFlow() override;
+  virtual ~OAuth2ApiCallFlow();
 
   // Start the flow.
-  virtual void Start(net::URLRequestContextGetter* context,
-                     const std::string& access_token);
-
-  // net::URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  virtual void Start(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& access_token);
 
  protected:
   // Template methods for sub-classes.
@@ -46,15 +44,18 @@
 
   // Returns the request type (e.g. GET, POST) for the |body| that will be sent
   // with the request.
-  virtual net::URLFetcher::RequestType GetRequestTypeForBody(
-      const std::string& body);
+  virtual std::string GetRequestTypeForBody(const std::string& body);
 
   // Sub-classes can expose an appropriate observer interface by implementing
   // these template methods.
-  // Called when the API call finished successfully.
-  virtual void ProcessApiCallSuccess(const net::URLFetcher* source) = 0;
-  // Called when the API call failed.
-  virtual void ProcessApiCallFailure(const net::URLFetcher* source) = 0;
+  // Called when the API call finished successfully. |body| may be null.
+  virtual void ProcessApiCallSuccess(const network::ResourceResponseHead* head,
+                                     std::unique_ptr<std::string> body) = 0;
+
+  // Called when the API call failed. |head| or |body| might be null.
+  virtual void ProcessApiCallFailure(int net_error,
+                                     const network::ResourceResponseHead* head,
+                                     std::unique_ptr<std::string> body) = 0;
 
   virtual net::PartialNetworkTrafficAnnotationTag
   GetNetworkTrafficAnnotationTag() = 0;
@@ -67,20 +68,22 @@
     ERROR_STATE
   };
 
-  // Creates an instance of URLFetcher that does not send or save cookies.
+  // Called when loading has finished.
+  void OnURLLoadComplete(std::unique_ptr<std::string> body);
+
+  // Creates an instance of SimpleURLLoader that does not send or save cookies.
   // Template method CreateApiCallUrl is used to get the URL.
   // Template method CreateApiCallBody is used to get the body.
-  // The URLFether's method will be GET if body is empty, POST otherwise.
-  std::unique_ptr<net::URLFetcher> CreateURLFetcher(
-      net::URLRequestContextGetter* context,
+  // The http method will be GET if body is empty, POST otherwise.
+  std::unique_ptr<network::SimpleURLLoader> CreateURLLoader(
       const std::string& access_token);
 
   // Helper methods to implement the state machine for the flow.
   void BeginApiCall();
-  void EndApiCall(const net::URLFetcher* source);
+  void EndApiCall(std::unique_ptr<std::string> body);
 
   State state_;
-  std::unique_ptr<net::URLFetcher> url_fetcher_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
 
   DISALLOW_COPY_AND_ASSIGN(OAuth2ApiCallFlow);
 };
diff --git a/google_apis/gaia/oauth2_api_call_flow_unittest.cc b/google_apis/gaia/oauth2_api_call_flow_unittest.cc
index 5aabf4b..cd7a481 100644
--- a/google_apis/gaia/oauth2_api_call_flow_unittest.cc
+++ b/google_apis/gaia/oauth2_api_call_flow_unittest.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/time/time.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -20,24 +21,13 @@
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_fetcher_factory.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using net::HttpRequestHeaders;
-using net::ScopedURLFetcherFactory;
-using net::TestURLFetcher;
-using net::URLFetcher;
-using net::URLFetcherDelegate;
-using net::URLFetcherFactory;
-using net::URLRequestContextGetter;
-using net::URLRequestStatus;
 using testing::_;
 using testing::ByMove;
 using testing::Return;
@@ -55,33 +45,6 @@
   return GURL("https://www.googleapis.com/someapi");
 }
 
-// Replaces the global URLFetcher factory so the test can return a custom
-// URLFetcher to complete requests.
-class MockUrlFetcherFactory : public ScopedURLFetcherFactory,
-                              public URLFetcherFactory {
- public:
-  MockUrlFetcherFactory()
-      : ScopedURLFetcherFactory(this) {
-  }
-  ~MockUrlFetcherFactory() override {}
-
-  MOCK_METHOD5(CreateURLFetcherMock,
-               std::unique_ptr<URLFetcher>(
-                   int id,
-                   const GURL& url,
-                   URLFetcher::RequestType request_type,
-                   URLFetcherDelegate* d,
-                   net::NetworkTrafficAnnotationTag traffic_annotation));
-
-  std::unique_ptr<URLFetcher> CreateURLFetcher(
-      int id,
-      const GURL& url,
-      URLFetcher::RequestType request_type,
-      URLFetcherDelegate* d,
-      net::NetworkTrafficAnnotationTag traffic_annotation) override {
-    return CreateURLFetcherMock(id, url, request_type, d, traffic_annotation);
-  }
-};
 
 class MockApiCallFlow : public OAuth2ApiCallFlow {
  public:
@@ -90,8 +53,13 @@
 
   MOCK_METHOD0(CreateApiCallUrl, GURL());
   MOCK_METHOD0(CreateApiCallBody, std::string());
-  MOCK_METHOD1(ProcessApiCallSuccess, void(const URLFetcher* source));
-  MOCK_METHOD1(ProcessApiCallFailure, void(const URLFetcher* source));
+  MOCK_METHOD2(ProcessApiCallSuccess,
+               void(const network::ResourceResponseHead* head,
+                    std::unique_ptr<std::string> body));
+  MOCK_METHOD3(ProcessApiCallFailure,
+               void(int net_error,
+                    const network::ResourceResponseHead* head,
+                    std::unique_ptr<std::string> body));
   MOCK_METHOD1(ProcessNewAccessToken, void(const std::string& access_token));
   MOCK_METHOD1(ProcessMintAccessTokenFailure,
                void(const GoogleServiceAuthError& error));
@@ -107,78 +75,77 @@
 class OAuth2ApiCallFlowTest : public testing::Test {
  protected:
   OAuth2ApiCallFlowTest()
-      : request_context_getter_(
-            base::MakeRefCounted<net::TestURLRequestContextGetter>(
-                message_loop_.task_runner())) {}
+      : shared_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {}
 
-  std::unique_ptr<TestURLFetcher> CreateURLFetcher(const GURL& url,
-                                                   bool fetch_succeeds,
-                                                   int response_code,
-                                                   const std::string& body) {
-    auto url_fetcher = std::make_unique<TestURLFetcher>(0, url, &flow_);
+  void AddFetchResult(const GURL& url,
+                      bool fetch_succeeds,
+                      net::HttpStatusCode response_code,
+                      const std::string& body) {
     net::Error error = fetch_succeeds ? net::OK : net::ERR_FAILED;
-    url_fetcher->set_status(URLRequestStatus::FromError(error));
 
-    if (response_code != 0)
-      url_fetcher->set_response_code(response_code);
-
-    if (!body.empty())
-      url_fetcher->SetResponseString(body);
-
-    return url_fetcher;
+    network::ResourceResponseHead http_head =
+        network::CreateResourceResponseHead(response_code);
+    test_url_loader_factory_.AddResponse(
+        url, http_head, body, network::URLLoaderCompletionStatus(error));
   }
 
-  TestURLFetcher* SetupApiCall(bool succeeds, net::HttpStatusCode status) {
+  void SetupApiCall(bool succeeds, net::HttpStatusCode status) {
     std::string body(CreateBody());
     GURL url(CreateApiUrl());
     EXPECT_CALL(flow_, CreateApiCallBody()).WillOnce(Return(body));
     EXPECT_CALL(flow_, CreateApiCallUrl()).WillOnce(Return(url));
-    std::unique_ptr<TestURLFetcher> url_fetcher =
-        CreateURLFetcher(url, succeeds, status, std::string());
-    TestURLFetcher* url_fetcher_ptr = url_fetcher.get();
-    EXPECT_CALL(factory_, CreateURLFetcherMock(_, url, _, _, _))
-        .WillOnce(Return(ByMove(std::move(url_fetcher))));
-    return url_fetcher_ptr;
+
+    AddFetchResult(url, succeeds, status, std::string());
   }
 
   base::MessageLoop message_loop_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
   StrictMock<MockApiCallFlow> flow_;
-  MockUrlFetcherFactory factory_;
 };
 
 TEST_F(OAuth2ApiCallFlowTest, ApiCallSucceedsHttpOk) {
-  TestURLFetcher* url_fetcher = SetupApiCall(true, net::HTTP_OK);
-  EXPECT_CALL(flow_, ProcessApiCallSuccess(url_fetcher));
-  flow_.Start(request_context_getter_.get(), kAccessToken);
-  flow_.OnURLFetchComplete(url_fetcher);
+  SetupApiCall(true, net::HTTP_OK);
+  EXPECT_CALL(flow_, ProcessApiCallSuccess(_, _));
+  flow_.Start(shared_factory_, kAccessToken);
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(OAuth2ApiCallFlowTest, ApiCallSucceedsHttpNoContent) {
-  TestURLFetcher* url_fetcher = SetupApiCall(true, net::HTTP_NO_CONTENT);
-  EXPECT_CALL(flow_, ProcessApiCallSuccess(url_fetcher));
-  flow_.Start(request_context_getter_.get(), kAccessToken);
-  flow_.OnURLFetchComplete(url_fetcher);
+  SetupApiCall(true, net::HTTP_NO_CONTENT);
+  EXPECT_CALL(flow_, ProcessApiCallSuccess(_, _));
+  flow_.Start(shared_factory_, kAccessToken);
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(OAuth2ApiCallFlowTest, ApiCallFailure) {
-  TestURLFetcher* url_fetcher = SetupApiCall(true, net::HTTP_UNAUTHORIZED);
-  EXPECT_CALL(flow_, ProcessApiCallFailure(url_fetcher));
-  flow_.Start(request_context_getter_.get(), kAccessToken);
-  flow_.OnURLFetchComplete(url_fetcher);
+  SetupApiCall(true, net::HTTP_UNAUTHORIZED);
+  EXPECT_CALL(flow_, ProcessApiCallFailure(_, _, _));
+  flow_.Start(shared_factory_, kAccessToken);
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(OAuth2ApiCallFlowTest, ExpectedHTTPHeaders) {
   std::string body = CreateBody();
   GURL url(CreateApiUrl());
 
-  TestURLFetcher* url_fetcher = SetupApiCall(true, net::HTTP_OK);
-  flow_.Start(request_context_getter_.get(), kAccessToken);
-  HttpRequestHeaders headers;
-  url_fetcher->GetExtraRequestHeaders(&headers);
+  SetupApiCall(true, net::HTTP_OK);
+  // ... never mind the HTTP response part of the setup --- don't want
+  // TestURLLoaderFactory replying to it just yet as it would prevent examining
+  // the request headers.
+  test_url_loader_factory_.ClearResponses();
+
+  flow_.Start(shared_factory_, kAccessToken);
+  const std::vector<network::TestURLLoaderFactory::PendingRequest>& pending =
+      *test_url_loader_factory_.pending_requests();
+  ASSERT_EQ(1u, pending.size());
+  EXPECT_EQ(url, pending[0].request.url);
+
   std::string auth_header;
-  EXPECT_TRUE(headers.GetHeader("Authorization", &auth_header));
+  EXPECT_TRUE(
+      pending[0].request.headers.GetHeader("Authorization", &auth_header));
   EXPECT_EQ("Bearer access_token", auth_header);
-  EXPECT_EQ(url, url_fetcher->GetOriginalURL());
-  EXPECT_EQ(body, url_fetcher->upload_data());
+  EXPECT_EQ(body, network::GetUploadData(pending[0].request));
 }
diff --git a/google_apis/gaia/oauth2_mint_token_flow.cc b/google_apis/gaia/oauth2_mint_token_flow.cc
index a8d9324..a99a51b 100644
--- a/google_apis/gaia/oauth2_mint_token_flow.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow.cc
@@ -21,13 +21,8 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "net/base/escape.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_status.h"
-
-using net::URLFetcher;
-using net::URLRequestContextGetter;
-using net::URLRequestStatus;
+#include "net/base/net_errors.h"
+#include "services/network/public/cpp/resource_response.h"
 
 namespace {
 
@@ -59,25 +54,33 @@
 const char kError[] = "error";
 const char kMessage[] = "message";
 
-static GoogleServiceAuthError CreateAuthError(const net::URLFetcher* source) {
-  URLRequestStatus status = source->GetStatus();
-  if (status.status() == URLRequestStatus::CANCELED) {
+static GoogleServiceAuthError CreateAuthError(
+    int net_error,
+    const network::ResourceResponseHead* head,
+    std::unique_ptr<std::string> body) {
+  if (net_error == net::ERR_ABORTED) {
     return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
   }
-  if (status.status() == URLRequestStatus::FAILED) {
-    DLOG(WARNING) << "Server returned error: errno " << status.error();
-    return GoogleServiceAuthError::FromConnectionError(status.error());
+  if (net_error != net::OK) {
+    DLOG(WARNING) << "Server returned error: errno " << net_error;
+    return GoogleServiceAuthError::FromConnectionError(net_error);
   }
 
   std::string response_body;
-  source->GetResponseAsString(&response_body);
+  if (body)
+    response_body = std::move(*body);
+
   std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
   base::DictionaryValue* response;
   if (!value.get() || !value->GetAsDictionary(&response)) {
+    int http_response_code = -1;
+    if (head && head->headers)
+      http_response_code = head->headers->response_code();
     return GoogleServiceAuthError::FromUnexpectedServiceResponse(
-        base::StringPrintf(
-            "Not able to parse a JSON object from a service response. "
-            "HTTP Status of the response is: %d", source->GetResponseCode()));
+        base::StringPrintf("Not able to parse a JSON object from "
+                           "a service response. "
+                           "HTTP Status of the response is: %d",
+                           http_response_code));
   }
   base::DictionaryValue* error;
   if (!response->GetDictionary(kError, &error)) {
@@ -183,9 +186,11 @@
 }
 
 void OAuth2MintTokenFlow::ProcessApiCallSuccess(
-    const net::URLFetcher* source) {
+    const network::ResourceResponseHead* head,
+    std::unique_ptr<std::string> body) {
   std::string response_body;
-  source->GetResponseAsString(&response_body);
+  if (body)
+    response_body = std::move(*body);
   std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body);
   base::DictionaryValue* dict = NULL;
   if (!value.get() || !value->GetAsDictionary(&dict)) {
@@ -223,8 +228,10 @@
 }
 
 void OAuth2MintTokenFlow::ProcessApiCallFailure(
-    const net::URLFetcher* source) {
-  ReportFailure(CreateAuthError(source));
+    int net_error,
+    const network::ResourceResponseHead* head,
+    std::unique_ptr<std::string> body) {
+  ReportFailure(CreateAuthError(net_error, head, std::move(body)));
 }
 
 // static
diff --git a/google_apis/gaia/oauth2_mint_token_flow.h b/google_apis/gaia/oauth2_mint_token_flow.h
index d1f3ca5..4a50391d8 100644
--- a/google_apis/gaia/oauth2_mint_token_flow.h
+++ b/google_apis/gaia/oauth2_mint_token_flow.h
@@ -22,10 +22,6 @@
 class DictionaryValue;
 }
 
-namespace content {
-class URLFetcher;
-}
-
 // IssueAdvice: messages to show to the user to get a user's approval.
 // The structure is as follows:
 // * Description 1
@@ -107,8 +103,11 @@
   GURL CreateApiCallUrl() override;
   std::string CreateApiCallBody() override;
 
-  void ProcessApiCallSuccess(const net::URLFetcher* source) override;
-  void ProcessApiCallFailure(const net::URLFetcher* source) override;
+  void ProcessApiCallSuccess(const network::ResourceResponseHead* head,
+                             std::unique_ptr<std::string> body) override;
+  void ProcessApiCallFailure(int net_error,
+                             const network::ResourceResponseHead* head,
+                             std::unique_ptr<std::string> body) override;
   net::PartialNetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag()
       override;
 
diff --git a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
index 57894a1..c714b1a 100644
--- a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
@@ -16,14 +16,11 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "net/base/net_errors.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_status.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using net::TestURLFetcher;
-using net::URLFetcher;
-using net::URLRequestStatus;
 using testing::_;
 using testing::StrictMock;
 
@@ -299,71 +296,70 @@
 }
 
 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallSuccess) {
+  network::ResourceResponseHead head_200 =
+      network::CreateResourceResponseHead(net::HTTP_OK);
+
   {  // No body.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString(std::string());
     CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
     EXPECT_CALL(delegate_, OnMintTokenFailure(_));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(&head_200, nullptr);
   }
   {  // Bad json.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString("foo");
     CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
     EXPECT_CALL(delegate_, OnMintTokenFailure(_));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(&head_200,
+                                 std::make_unique<std::string>("foo"));
   }
   {  // Valid json: no access token.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString(kTokenResponseNoAccessToken);
     CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
     EXPECT_CALL(delegate_, OnMintTokenFailure(_));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(
+        &head_200, std::make_unique<std::string>(kTokenResponseNoAccessToken));
   }
   {  // Valid json: good token response.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString(kValidTokenResponse);
     CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
     EXPECT_CALL(delegate_, OnMintTokenSuccess("at1", 3600));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(
+        &head_200, std::make_unique<std::string>(kValidTokenResponse));
   }
   {  // Valid json: no description.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString(kIssueAdviceResponseNoDescription);
     CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
     EXPECT_CALL(delegate_, OnMintTokenFailure(_));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(
+        &head_200,
+        std::make_unique<std::string>(kIssueAdviceResponseNoDescription));
   }
   {  // Valid json: no detail.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString(kIssueAdviceResponseNoDetail);
     CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
     EXPECT_CALL(delegate_, OnMintTokenFailure(_));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(
+        &head_200, std::make_unique<std::string>(kIssueAdviceResponseNoDetail));
   }
   {  // Valid json: good issue advice response.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.SetResponseString(kValidIssueAdviceResponse);
     CreateFlow(OAuth2MintTokenFlow::MODE_ISSUE_ADVICE);
     IssueAdviceInfo ia(CreateIssueAdvice());
     EXPECT_CALL(delegate_, OnIssueAdviceSuccess(ia));
-    flow_->ProcessApiCallSuccess(&url_fetcher);
+    flow_->ProcessApiCallSuccess(
+        &head_200, std::make_unique<std::string>(kValidIssueAdviceResponse));
   }
 }
 
 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallFailure) {
+  network::ResourceResponseHead head;
   {  // Null delegate should work fine.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.set_status(URLRequestStatus::FromError(net::ERR_FAILED));
     CreateFlow(NULL, OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE, "");
-    flow_->ProcessApiCallFailure(&url_fetcher);
+    flow_->ProcessApiCallFailure(net::ERR_FAILED, &head, nullptr);
   }
 
   {  // Non-null delegate.
-    TestURLFetcher url_fetcher(1, GURL("http://www.google.com"), NULL);
-    url_fetcher.set_status(URLRequestStatus::FromError(net::ERR_FAILED));
     CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
     EXPECT_CALL(delegate_, OnMintTokenFailure(_));
-    flow_->ProcessApiCallFailure(&url_fetcher);
+    flow_->ProcessApiCallFailure(net::ERR_FAILED, &head, nullptr);
+  }
+
+  {  // Null head might happen.
+    CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
+    EXPECT_CALL(delegate_, OnMintTokenFailure(_));
+    flow_->ProcessApiCallFailure(net::ERR_FAILED, nullptr, nullptr);
   }
 }
diff --git a/google_apis/gaia/oauth2_token_service_unittest.cc b/google_apis/gaia/oauth2_token_service_unittest.cc
index 12da58b9..2a1cdc8b 100644
--- a/google_apis/gaia/oauth2_token_service_unittest.cc
+++ b/google_apis/gaia/oauth2_token_service_unittest.cc
@@ -17,7 +17,6 @@
 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "google_apis/gaia/oauth2_token_service_test_util.h"
-#include "mojo/core/embedder/embedder.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -72,7 +71,6 @@
 class OAuth2TokenServiceTest : public testing::Test {
  public:
   void SetUp() override {
-    mojo::core::Init();
     auto delegate = std::make_unique<FakeOAuth2TokenServiceDelegate>();
     test_url_loader_factory_ = delegate->test_url_loader_factory();
     oauth2_service_ =
diff --git a/google_apis/gaia/ubertoken_fetcher_unittest.cc b/google_apis/gaia/ubertoken_fetcher_unittest.cc
index 867c108..4c202ee 100644
--- a/google_apis/gaia/ubertoken_fetcher_unittest.cc
+++ b/google_apis/gaia/ubertoken_fetcher_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "google_apis/gaia/fake_oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
-#include "mojo/core/embedder/embedder.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -57,8 +56,6 @@
                 &url_loader_factory_)) {}
 
   void SetUp() override {
-    mojo::core::Init();
-
     fetcher_ = std::make_unique<UbertokenFetcher>(&token_service_, &consumer_,
                                                   GaiaConstants::kChromeSource,
                                                   test_shared_loader_factory_);
diff --git a/google_apis/test/DEPS b/google_apis/test/DEPS
new file mode 100644
index 0000000..9243dcd6
--- /dev/null
+++ b/google_apis/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/core/embedder",
+]
diff --git a/google_apis/test/run_all_unittests.cc b/google_apis/test/run_all_unittests.cc
new file mode 100644
index 0000000..939a23ce
--- /dev/null
+++ b/google_apis/test/run_all_unittests.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/core/embedder/embedder.h"
+
+int main(int argc, char** argv) {
+  base::TestSuite test_suite(argc, argv);
+
+  mojo::core::Init();
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index b26f444..73122ce 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -13225,32 +13225,30 @@
                                          int width,
                                          int height) {
   TRACE_EVENT0("gpu", "GLES2DecoderImpl::ClearLevelUsingGL");
+  GLenum fb_target = GetDrawFramebufferTarget();
   GLuint fb = 0;
   api()->glGenFramebuffersEXTFn(1, &fb);
-  api()->glBindFramebufferEXTFn(GL_DRAW_FRAMEBUFFER_EXT, fb);
+  api()->glBindFramebufferEXTFn(fb_target, fb);
 
   bool have_color = (channels & GLES2Util::kRGBA) != 0;
   if (have_color) {
-    api()->glFramebufferTexture2DEXTFn(GL_DRAW_FRAMEBUFFER_EXT,
-                                       GL_COLOR_ATTACHMENT0, target,
+    api()->glFramebufferTexture2DEXTFn(fb_target, GL_COLOR_ATTACHMENT0, target,
                                        texture->service_id(), level);
   }
   bool have_depth = (channels & GLES2Util::kDepth) != 0;
   if (have_depth) {
-    api()->glFramebufferTexture2DEXTFn(GL_DRAW_FRAMEBUFFER_EXT,
-                                       GL_DEPTH_ATTACHMENT, target,
+    api()->glFramebufferTexture2DEXTFn(fb_target, GL_DEPTH_ATTACHMENT, target,
                                        texture->service_id(), level);
   }
   bool have_stencil = (channels & GLES2Util::kStencil) != 0;
   if (have_stencil) {
-    api()->glFramebufferTexture2DEXTFn(GL_DRAW_FRAMEBUFFER_EXT,
-                                       GL_STENCIL_ATTACHMENT, target,
+    api()->glFramebufferTexture2DEXTFn(fb_target, GL_STENCIL_ATTACHMENT, target,
                                        texture->service_id(), level);
   }
   // Attempt to do the clear only if the framebuffer is complete. ANGLE
   // promises a depth only attachment ok.
   bool result = false;
-  if (api()->glCheckFramebufferStatusEXTFn(GL_DRAW_FRAMEBUFFER_EXT) ==
+  if (api()->glCheckFramebufferStatusEXTFn(fb_target) ==
       GL_FRAMEBUFFER_COMPLETE) {
     api()->glColorMaskFn(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
     api()->glClearColorFn(0.0, 0.0, 0.0, 0.0);
@@ -13272,11 +13270,10 @@
   }
   RestoreClearState();
   api()->glDeleteFramebuffersEXTFn(1, &fb);
-  Framebuffer* framebuffer =
-      GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+  Framebuffer* framebuffer = GetFramebufferInfoForTarget(fb_target);
   GLuint fb_service_id =
       framebuffer ? framebuffer->service_id() : GetBackbufferServiceId();
-  api()->glBindFramebufferEXTFn(GL_DRAW_FRAMEBUFFER_EXT, fb_service_id);
+  api()->glBindFramebufferEXTFn(fb_target, fb_service_id);
   return result;
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
index 8edf06d..790b54d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
@@ -2266,9 +2266,11 @@
 
   SetupDefaultProgram();
   SetupAllNeededVertexBuffers();
-  const GLenum attachment = GL_DEPTH_ATTACHMENT;
-  const GLenum target = GL_TEXTURE_2D;
-  const GLint level = 0;
+  constexpr GLenum attachment = GL_DEPTH_ATTACHMENT;
+  constexpr GLenum target = GL_TEXTURE_2D;
+  constexpr GLint level = 0;
+  // Note that the target framebuffer will be GL_FRAMEBUFFER_EXT for ES2.
+  constexpr GLenum fb_target = GL_FRAMEBUFFER_EXT;
   DoBindTexture(target, client_texture_id_, kServiceTextureId);
 
   // Create a depth texture.
@@ -2289,19 +2291,15 @@
   DoEnableDisable(GL_SCISSOR_TEST, false);
 
   EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
-  EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _))
+  EXPECT_CALL(*gl_, BindFramebufferEXT(fb_target, _))
       .Times(1)
       .RetiresOnSaturation();
 
-  EXPECT_CALL(*gl_,
-              FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT,
-                                      attachment,
-                                      target,
-                                      kServiceTextureId,
-                                      level))
+  EXPECT_CALL(*gl_, FramebufferTexture2DEXT(fb_target, attachment, target,
+                                            kServiceTextureId, level))
       .Times(1)
       .RetiresOnSaturation();
-  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT))
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(fb_target))
       .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
       .RetiresOnSaturation();
 
@@ -2323,7 +2321,7 @@
                                         0, 0, 32, 32);
 
   EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
-  EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0))
+  EXPECT_CALL(*gl_, BindFramebufferEXT(fb_target, 0))
       .Times(1)
       .RetiresOnSaturation();
 
@@ -2339,8 +2337,7 @@
 
 TEST_P(GLES2DecoderManualInitTest, DrawClearsLargeTexture) {
   InitState init;
-  init.extensions = "GL_ANGLE_depth_texture";
-  init.gl_version = "OpenGL ES 2.0";
+  init.gl_version = "OpenGL ES 3.0";
   init.has_alpha = true;
   init.has_depth = true;
   init.request_alpha = true;
@@ -2350,9 +2347,11 @@
 
   SetupDefaultProgram();
   SetupAllNeededVertexBuffers();
-  const GLenum attachment = GL_COLOR_ATTACHMENT0;
-  const GLenum target = GL_TEXTURE_2D;
-  const GLint level = 0;
+  constexpr GLenum attachment = GL_COLOR_ATTACHMENT0;
+  constexpr GLenum target = GL_TEXTURE_2D;
+  constexpr GLint level = 0;
+  // Note that the target framebuffer will be GL_DRAW_FRAMEBUFFER_EXT for ES3.
+  constexpr GLenum fb_target = GL_DRAW_FRAMEBUFFER_EXT;
   DoBindTexture(target, client_texture_id_, kServiceTextureId);
 
   // Create an RGBA texture.
@@ -2365,15 +2364,15 @@
   DoEnableDisable(GL_SCISSOR_TEST, false);
 
   EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
-  EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _))
+  EXPECT_CALL(*gl_, BindFramebufferEXT(fb_target, _))
       .Times(1)
       .RetiresOnSaturation();
 
-  EXPECT_CALL(*gl_, FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, attachment,
-                                            target, kServiceTextureId, level))
+  EXPECT_CALL(*gl_, FramebufferTexture2DEXT(fb_target, attachment, target,
+                                            kServiceTextureId, level))
       .Times(1)
       .RetiresOnSaturation();
-  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT))
+  EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(fb_target))
       .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
       .RetiresOnSaturation();
 
@@ -2395,7 +2394,7 @@
                                         0, 0, 32, 32);
 
   EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
-  EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0))
+  EXPECT_CALL(*gl_, BindFramebufferEXT(fb_target, 0))
       .Times(1)
       .RetiresOnSaturation();
 
diff --git a/headless/lib/browser/headless_print_manager.cc b/headless/lib/browser/headless_print_manager.cc
index 42bd9266..876da57 100644
--- a/headless/lib/browser/headless_print_manager.cc
+++ b/headless/lib/browser/headless_print_manager.cc
@@ -18,8 +18,6 @@
 #include "printing/print_job_constants.h"
 #include "printing/units.h"
 
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(headless::HeadlessPrintManager);
-
 namespace headless {
 
 struct HeadlessPrintManager::FrameDispatchHelper {
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index fe1b407..3485def 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -2638,6 +2638,7 @@
     }
     builders { mixins: "win-try" name: "win7_chromium_rel_loc_exp" }
     builders { mixins: "win-try" name: "win-annotator-rel" }
+    builders { mixins: "win-try" name: "win-asan" }
     builders { mixins: "win-try" name: "win-jumbo-rel" }
     builders { mixins: "win-angle-try" name: "win_angle_rel_ng" }
     builders { mixins: "win-angle-try" name: "win_angle_compile_x64_rel_ng" }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 5a4b63d..cdbc382 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -593,12 +593,6 @@
     short_name: "cro"
   }
   builders {
-    name: "buildbot/chromium.memory/win-asan"
-    name: "buildbucket/luci.chromium.ci/win-asan"
-    category: "chromium.memory|win"
-    short_name: "asn"
-  }
-  builders {
     name: "buildbot/chromium.memory/Mac ASan 64 Builder"
     name: "buildbucket/luci.chromium.ci/Mac ASan 64 Builder"
     category: "chromium.memory|mac"
@@ -678,6 +672,12 @@
     short_name: "tst"
   }
   builders {
+    name: "buildbot/chromium.memory/Android CFI"
+    name: "buildbucket/luci.chromium.ci/Android CFI"
+    category: "chromium.memory|android"
+    short_name: "cfi"
+  }
+  builders {
     name: "buildbot/chromium.webkit/WebKit Win Builder"
     category: "chromium.webkit|win rel|builder"
     short_name: "32"
@@ -1039,10 +1039,16 @@
   refs: "refs/heads/master"
   manifest_name: "REVISION"
   builders {
-    name: "buildbot/chromium.memory/Android CFI"
-    name: "buildbucket/luci.chromium.ci/Android CFI"
-    category: "android"
-    short_name: "cfi"
+    name: "buildbot/chromium.memory/Mac ASan 64 Builder"
+    name: "buildbucket/luci.chromium.ci/Mac ASan 64 Builder"
+    category: "mac|asan"
+    short_name: "bld"
+  }
+  builders {
+    name: "buildbot/chromium.memory/Mac ASan 64 Tests (1)"
+    name: "buildbucket/luci.chromium.ci/Mac ASan 64 Tests (1)"
+    category: "mac|asan"
+    short_name: "tst"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Linux TSan Builder"
@@ -1070,18 +1076,6 @@
     short_name: "sbx"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Builder"
-    name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Builder"
-    category: "linux|msan|cros"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Tests"
-    name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Tests"
-    category: "linux|msan|cros"
-    short_name: "tst"
-  }
-  builders {
     name: "buildbot/chromium.memory/Linux MSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux MSan Builder"
     category: "linux|msan"
@@ -1100,29 +1094,35 @@
     short_name: "cfi"
   }
   builders {
-    name: "buildbot/chromium.memory/Mac ASan 64 Builder"
-    name: "buildbucket/luci.chromium.ci/Mac ASan 64 Builder"
-    category: "asan|mac"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbot/chromium.memory/Mac ASan 64 Tests (1)"
-    name: "buildbucket/luci.chromium.ci/Mac ASan 64 Tests (1)"
-    category: "asan|mac"
-    short_name: "tst"
-  }
-  builders {
     name: "buildbot/chromium.memory/Linux Chromium OS ASan LSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux Chromium OS ASan LSan Builder"
-    category: "asan|cros"
+    category: "cros|asan"
     short_name: "bld"
   }
   builders {
     name: "buildbot/chromium.memory/Linux Chromium OS ASan LSan Tests (1)"
     name: "buildbucket/luci.chromium.ci/Linux Chromium OS ASan LSan Tests (1)"
-    category: "asan|cros"
+    category: "cros|asan"
     short_name: "tst"
   }
+  builders {
+    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Builder"
+    name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Builder"
+    category: "cros|msan"
+    short_name: "bld"
+  }
+  builders {
+    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Tests"
+    name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Tests"
+    category: "cros|msan"
+    short_name: "tst"
+  }
+  builders {
+    name: "buildbot/chromium.memory/Android CFI"
+    name: "buildbucket/luci.chromium.ci/Android CFI"
+    category: "android"
+    short_name: "cfi"
+  }
 }
 
 consoles {
diff --git a/infra/config/global/tricium-prod.cfg b/infra/config/global/tricium-prod.cfg
index 5e0b78c7..cde7591 100644
--- a/infra/config/global/tricium-prod.cfg
+++ b/infra/config/global/tricium-prod.cfg
@@ -22,7 +22,6 @@
     project: "chromium/src"
     git_url: "https://chromium.googlesource.com/chromium/src"
   }
-  disable_reporting: true
 }
 
 service_account: "tricium-prod@appspot.gserviceaccount.com"
diff --git a/ios/build/bots/chromium.clang/ToTiOS.json b/ios/build/bots/chromium.clang/ToTiOS.json
index ba49f729..cf777fe 100644
--- a/ios/build/bots/chromium.clang/ToTiOS.json
+++ b/ios/build/bots/chromium.clang/ToTiOS.json
@@ -2,7 +2,7 @@
   "comments": [
     "Clang tip-of-tree builder for iOS."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "ios_enable_code_signing=false",
     "is_component_build=false",
@@ -19,7 +19,6 @@
     "LLVM_FORCE_HEAD_REVISION": "1"
   },
   "configuration": "Release",
-  "sdk": "iphoneos11.0",
   "tests": [
   ]
 }
diff --git a/ios/build/bots/chromium.clang/clang_tot_device.json b/ios/build/bots/chromium.clang/clang_tot_device.json
index ee05ba0..d2e8148 100644
--- a/ios/build/bots/chromium.clang/clang_tot_device.json
+++ b/ios/build/bots/chromium.clang/clang_tot_device.json
@@ -2,7 +2,7 @@
   "comments": [
     "Clang tip-of-tree builder for iOS device."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "is_debug=false",
     "llvm_force_head_revision=true",
@@ -33,92 +33,108 @@
     "LLVM_FORCE_HEAD_REVISION": "1"
   },
   "configuration": "Release",
-  "sdk": "iphoneos11.2",
   "device check": false,
   "tests": [
     {
       "app": "base_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "boringssl_crypto_tests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "boringssl_ssl_tests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "components_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "crypto_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "gfx_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "google_apis_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "ios_chrome_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "ios_net_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "ios_web_inttests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "ios_web_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "ios_web_view_inttests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "net_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "skia_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "sql_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "ui_base_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     },
     {
       "app": "url_unittests",
       "device type": "iPhone 6s",
+      "xcode build version": "9C40b",
       "os": "10.2"
     }
   ],
diff --git a/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json b/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
index dc04c67a..44b4629 100644
--- a/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
+++ b/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
@@ -3,7 +3,7 @@
     "Goma canary builder for iOS.",
     "It is chromium.mac/ios-device.json + use_goma_canary, clobber."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "additional_target_cpus=[ \"arm64\" ]",
     "goma_dir=\"$(goma_dir)\"",
@@ -19,7 +19,6 @@
   ],
   "configuration": "Release",
   "explain": true,
-  "sdk": "iphoneos11.0",
   "tests": [
   ],
   "clobber": true,
diff --git a/ios/build/bots/chromium.fyi/ios-simulator.json b/ios/build/bots/chromium.fyi/ios-simulator.json
index 0dfd1f7..bdb6e49 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator.json
@@ -1,8 +1,8 @@
 {
   "comments": [
-    "Runs tests on FYI ios-simualtor."
+    "Runs tests on FYI on the latest simulators."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "goma_dir=\"$(goma_dir)\"",
@@ -14,7 +14,6 @@
     "use_goma=true"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator11.2",
   "tests": [
     {
       "include": "common_tests.json",
@@ -22,15 +21,13 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
-      "comments": [
-        "Xcode 9.2 requires Mac OS 10.12+, but we still have 10.11 on some",
-        "bots. Once all swarming bots are upgraded, dimensions can be removed."
-      ],
+      "os": "12.0",
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
+
     },
     {
       "app": "ios_chrome_integration_egtests",
@@ -38,11 +35,12 @@
         "--enable-features=CredentialManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "xctest": true,
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -53,10 +51,10 @@
       "device type": "iPad Air 2",
       "os": "10.3",
       "xctest": true,
-      "xcode build version": "8E3004b",
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -65,11 +63,12 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "xctest": true,
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -78,11 +77,12 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "xctest": true,
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -91,11 +91,12 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "xctest": true,
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -104,11 +105,12 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "xctest": true,
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -117,11 +119,12 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "xctest": true,
       "dimensions": [
-        { "os": "Mac-10.12", "pool": "Chrome" },
-        { "os": "Mac-10.13", "pool": "Chrome" }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     }
   ]
diff --git a/ios/build/bots/chromium.fyi/ios12-beta-simulator.json b/ios/build/bots/chromium.fyi/ios12-beta-simulator.json
index bb093ac..ec81317b 100644
--- a/ios/build/bots/chromium.fyi/ios12-beta-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios12-beta-simulator.json
@@ -3,7 +3,7 @@
     "Run tests on iOS12beta track on 64-bit iOS 12 simulators.",
     "Note: Xcode 10 requires OSX 10.13.4 hence 'host os'"
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "additional_target_cpus=[\"x86\"]",
@@ -20,91 +20,143 @@
       "device type": "iPhone X",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6 Plus",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 5s",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPad Pro",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 6 Plus",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 5s",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 5s",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "12.0",
       "xcode build version": "10L221o",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     }
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios12-sdk-device.json b/ios/build/bots/chromium.fyi/ios12-sdk-device.json
index 31f04da0..245ea403 100644
--- a/ios/build/bots/chromium.fyi/ios12-sdk-device.json
+++ b/ios/build/bots/chromium.fyi/ios12-sdk-device.json
@@ -20,7 +20,6 @@
   ],
   "configuration": "Release",
   "explain": true,
-  "sdk": "iphoneos12.0",
   "tests": [
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios12-sdk-simulator.json b/ios/build/bots/chromium.fyi/ios12-sdk-simulator.json
index 4d2b5eb0..11d5fa7e 100644
--- a/ios/build/bots/chromium.fyi/ios12-sdk-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios12-sdk-simulator.json
@@ -19,121 +19,196 @@
     "all"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator12.0",
   "tests": [
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 7",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 7",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     }
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios12-sdk-xcode-clang.json b/ios/build/bots/chromium.fyi/ios12-sdk-xcode-clang.json
index a1707f2..1435e15 100644
--- a/ios/build/bots/chromium.fyi/ios12-sdk-xcode-clang.json
+++ b/ios/build/bots/chromium.fyi/ios12-sdk-xcode-clang.json
@@ -25,7 +25,6 @@
     "all"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator12.0",
   "tests": [
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-device-xcode-clang.json b/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
index 07f5c2c..e1aa48f 100644
--- a/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
+++ b/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
@@ -3,7 +3,7 @@
     "Builder for 32-bit devices.",
     "Build is performed with gn+ninja."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10l213o",
   "gn_args": [
     "additional_target_cpus=[ \"arm64\" ]",
     "goma_dir=\"$(goma_dir)\"",
@@ -15,14 +15,10 @@
     "use_goma=true",
     "use_xcode_clang=true"
   ],
-  "env": {
-    "IOS_TOOLCHAIN_REVISION": "9M214v-1"
-  },
   "additional_compile_targets": [
     "all"
   ],
   "configuration": "Release",
-  "sdk": "iphoneos11.0",
   "tests": [
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-device.json b/ios/build/bots/chromium.mac/ios-device.json
index 16801ae..b85b4b4f 100644
--- a/ios/build/bots/chromium.mac/ios-device.json
+++ b/ios/build/bots/chromium.mac/ios-device.json
@@ -4,7 +4,7 @@
     "Build is performed with gn+ninja.",
     "If modified, please change chromium.fyi/ios-device-goma-canary-clobber.json too."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "additional_target_cpus=[ \"arm64\" ]",
     "goma_dir=\"$(goma_dir)\"",
@@ -20,7 +20,6 @@
   ],
   "configuration": "Release",
   "explain": true,
-  "sdk": "iphoneos11.0",
   "tests": [
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-simulator-full-configs.json b/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
index d7fb96a..2928cab 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-full-configs.json
@@ -1,9 +1,9 @@
 {
   "comments": [
-    "Runs tests on 64-bit iOS 10 and 11  tests on iPad, iPhone,",
+    "Runs tests on 64-bit iOS 10, 11 and 12 tests on iPad, iPhone,",
     "@3x, and @2x on main waterfall ios-simulator-full-configs."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "goma_dir=\"$(goma_dir)\"",
@@ -18,56 +18,61 @@
     "all"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator11.2",
   "tests": [
     {
       "include": "eg_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "10.3",
-      "xcode build version": "8E3004b",
       "shards": 1,
       "shard size": 8,
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 7",
-      "os": "11.2",
+      "os": "11.4",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "eg_tests.json",
+      "device type": "iPhone 7",
+      "os": "12.0",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
-      "os": "11.2",
+      "os": "11.4",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "eg_tests.json",
+      "device type": "iPad Air 2",
+      "os": "12.0",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
@@ -75,34 +80,34 @@
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "xcode build version": "8E3004b",
       "shards": 1,
       "shard size": 8,
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
-      "os": "11.2",
+      "os": "11.4",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "eg_tests.json",
+      "device type": "iPhone X",
+      "os": "12.0",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
@@ -110,34 +115,34 @@
       "include": "eg_cq_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "xcode build version": "8E3004b",
       "shards": 1,
       "shard size": 8,
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
-      "os": "11.2",
+      "os": "11.4",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "eg_cq_tests.json",
+      "device type": "iPhone X",
+      "os": "12.0",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     }
diff --git a/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json b/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
index 30191fc..6d6ac51 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
@@ -1,9 +1,10 @@
 {
   "comments": [
-    "Tests for 64-bit iOS 11.2 simulators.",
+    "Tests for 64-bit Xcode Clang for iOS 12.0 simulators.",
+    "This 'xcode build version' must exist in GOMA",
     "Build is performed with gn+ninja."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10l213o",
   "use xcode build version": true,
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
@@ -24,7 +25,6 @@
     "all"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator11.2",
   "tests": [
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-simulator.json b/ios/build/bots/chromium.mac/ios-simulator.json
index 47b1b3d..7cb4604 100644
--- a/ios/build/bots/chromium.mac/ios-simulator.json
+++ b/ios/build/bots/chromium.mac/ios-simulator.json
@@ -1,10 +1,10 @@
 {
   "comments": [
-    "Runs tests on 64-bit iOS 10 and 11 tests",
+    "Runs tests on 64-bit iOS 10.3 and 11.4 and 12.0 tests",
     "on iPad, iPhone, @3x, and @2x on main and CQ ios-simulator.",
-    "Note: Xcode 9.2 requires Mac OS 10.12.6 or higher, hence 'host os'."
+    "Note: Xcode 10 requires Mac OS 10.13.4 or higher, hence 'host os'."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "goma_dir=\"$(goma_dir)\"",
@@ -19,69 +19,92 @@
     "all"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator11.2",
   "tests": [
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s Plus",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "device type": "iPhone 6s Plus",
+      "os": "11.4",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "device type": "iPhone 6s",
+      "os": "11.4",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "common_tests.json",
+      "device type": "iPhone 6s",
+      "os": "11.4",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ],
+      "priority": 29
+    },
+    {
+      "include": "screen_size_dependent_tests.json",
+      "device type": "iPad Air 2",
+      "os": "11.4",
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
@@ -89,16 +112,10 @@
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "xcode build version": "8E3004b",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
@@ -106,32 +123,21 @@
       "include": "common_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "xcode build version": "8E3004b",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
-      "os": "11.2",
+      "os": "11.4",
       "dimensions": [
-        {
-          "os": "Mac-10.12",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ],
       "priority": 29
     }
diff --git a/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json b/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json
index 8a5a538..555bb8ce 100644
--- a/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json
+++ b/ios/build/bots/chromium.mac/ios-uirefresh-simulator.json
@@ -2,7 +2,7 @@
   "comments": [
     "UIRefresh tests for iPhone simulator."
   ],
-  "xcode build version": "9C40b",
+  "xcode build version": "10L221o",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "additional_target_cpus=[\"x86\"]",
@@ -20,16 +20,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone 5s",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -38,16 +33,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone X",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -56,16 +46,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -74,16 +59,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone 6",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -92,16 +72,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -110,16 +85,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone X",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -128,16 +98,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -146,16 +111,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPhone X",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     },
     {
@@ -164,16 +124,11 @@
         "--disable-features=UIRefreshPhase1"
       ],
       "device type": "iPad Air",
-      "os": "11.2",
+      "os": "12.0",
       "dimensions": [
-        {
-          "os": "Mac-10.13.4",
-          "pool": "Chrome"
-        },
-        {
-          "os": "Mac-10.13.5",
-          "pool": "Chrome"
-        }
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
       ]
     }
   ]
diff --git a/ios/build/bots/chromium.mac/ios12-sdk-simulator.json b/ios/build/bots/chromium.mac/ios12-sdk-simulator.json
index aaa3a367..a35164d 100644
--- a/ios/build/bots/chromium.mac/ios12-sdk-simulator.json
+++ b/ios/build/bots/chromium.mac/ios12-sdk-simulator.json
@@ -4,7 +4,7 @@
     "on iPad, iPhone, @3x, and @2x on main and CQ ios12-beta-simulator.",
     "Note: Xcode 10.3 requires Mac OS 10.13.X or higher, hence 'host os'."
   ],
-  "xcode build version": "10l213o",
+  "xcode build version": "10L221o",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "goma_dir=\"$(goma_dir)\"",
@@ -19,121 +19,196 @@
     "all"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator12.0",
   "tests": [
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 7",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone 7",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_tests.json",
       "device type": "iPhone X",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone X",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPhone 6s",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "screen_size_dependent_tests.json",
       "device type": "iPad Air 2",
       "os": "10.3",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
       "os": "12.0",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     },
     {
       "include": "eg_cq_tests.json",
       "device type": "iPhone 6s",
       "os": "11.4",
-      "host os": "Mac-10.13.5"
+      "dimensions": [
+        { "os": "Mac-10.13.4", "pool": "Chrome" },
+        { "os": "Mac-10.13.5", "pool": "Chrome" },
+        { "os": "Mac-10.13.6", "pool": "Chrome" }
+      ]
     }
   ]
 }
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index cea315e..d99228edc 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -789,6 +789,9 @@
       <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_READING_LIST_TEXT" desc="Feature in the settings for the user to enable/disable, to sync reading list links between devices. [iOS only]">
         Reading List
       </message>
+      <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_SETTINGS_TEXT" desc="Feature in the settings for the user to enable/disable, to sync settings data between devices. [iOS only]">
+        Settings
+      </message>
       <message name="IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_EVERYTHING" desc="Feature in the settings for the user enable or disable all the Google sync features. [iOS only]">
         Use sync and all services
       </message>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_bn.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_bn.xtb
index 56cc741a..f230237 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_bn.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_bn.xtb
@@ -23,6 +23,7 @@
 <translation id="3605252743693911722">আপনার বুকমার্ক, পাসওয়ার্ড, এবং অন্যান্য জিনিস আপনার সমস্ত ডিভাইসে পেতে Chromium এ সাইন-ইন করুন।</translation>
 <translation id="3805899903892079518">আপনার ফটো এবং ভিডিওগুলিতে Chromium এর অ্যাক্সেস নেই৷ iOS সেটিংস &gt; গোপনীয়তা &gt; ফটোগুলিতে অ্যাক্সেস সক্ষম করুন৷</translation>
 <translation id="4024541897090868497">আপনার সব ডিভাইসে আপনার ট্যাবগুলি পেতে, Chromium এ সাইন-ইন করুন।</translation>
+<translation id="4157467675761413638">Chromium টিপ। ট্যাবে আরও বিকল্পের জন্য, আপনার স্ক্রিনের নিচে অথবা উপরে থাকা টুলবারে দেখানো ট্যাবটি প্রেস করে ধরে থাকুন।</translation>
 <translation id="4241912885070669028"><ph name="SIGNOUT_MANAGED_DOMAIN" /> পরিচালিত একটি অ্যাকাউন্ট থেকে আপনি সাইন আউট করছেন৷ এটি এই ডিভাইস থেকে আপনার Chromium ডেটা মুছে ফেলবে, কিন্তু আপনার Google অ্যাকাউন্টে ডেটা থেকে যাবে৷</translation>
 <translation id="4272892696084633551">Chromium-এর ফিচার এবং পারফরম্যান্স উন্নত করতে সাহায্য করুন</translation>
 <translation id="4555020257205549924">যখন এই বৈশিষ্ট্যটি চালু করা হয় তখন Chromium, Google অনুবাদ ব্যবহার করে অন্যান্য ভাষায় লিখিত পৃষ্ঠাগুলি অনুবাদ করার অফার করবে৷ <ph name="BEGIN_LINK" />আরও জানুন<ph name="END_LINK" /></translation>
@@ -45,6 +46,7 @@
 <translation id="7357211569052832586">Chromium এবং সিঙ্ক করা ডিভাইসগুলি থেকে নির্বাচিত ডেটা সরিয়ে ফেলা হয়েছে। আপনার Google অ্যাকাউন্টের সার্চ এবং অন্যান্য Google পরিষেবাগুলি থেকে অ্যাক্টিভিটির মত অন্যান্য ধরনের ব্রাউজিং ইতিহাস history.google.com এ থাকতে পারে।</translation>
 <translation id="7400689562045506105">সব জায়গায় Chromium ব্যবহার করুন</translation>
 <translation id="7674213385180944843">সেটিংস &gt; গোপনীয়তা &gt; ক্যামেরা &gt; Chromium খুলুন এবং ক্যামেরা চালু করুন।</translation>
+<translation id="7746854981345936341">Chromium টিপ। কিছু বোতাম এখন আপনার স্ক্রিনে নিচের দিকে রয়েছে যেমন, ব্যাক, ফরওয়ার্ড এবং সার্চ বোতাম।</translation>
 <translation id="786327964234957808">আপনি সিঙ্ক অ্যাকাউন্টগুলিকে <ph name="USER_EMAIL1" /> থেকে <ph name="USER_EMAIL2" /> এ সুইচ করছেন। আপনার বিদ্যমান Chromium ডেটা <ph name="DOMAIN" /> দ্বারা পরিচালিত হয়। এটি এই ডিভাইস থেকে আপনার ডেটা মুছে দেবে, কিন্তু <ph name="USER_EMAIL1" /> এ আপনার ডেটা থাকবে।</translation>
 <translation id="8175055321229419309">টিপ: <ph name="BEGIN_LINK" />Chromium কে আপনার ডকে সরান<ph name="END_LINK" /></translation>
 <translation id="8252885722420466166">আপনার অবস্থানের উপর ভিত্তি করে Chromium এ আরও ভাল Google অভিজ্ঞতা লাভ করুন৷</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_es-419.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_es-419.xtb
index 9a7af27..23f4f1b7 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_es-419.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_es-419.xtb
@@ -23,6 +23,7 @@
 <translation id="3605252743693911722">Accede a tu cuenta en Chromium para obtener tus favoritos, contraseñas y mucho más desde todos tus dispositivos.</translation>
 <translation id="3805899903892079518">Chromium no tiene acceso a tus fotos o videos. Habilita el acceso en Configuración de iOS &gt; Privacidad &gt; Fotos.</translation>
 <translation id="4024541897090868497">Para obtener tus pestañas en todos los dispositivos, accede a Chromium.</translation>
+<translation id="4157467675761413638">Sugerencia de Chromium: Para obtener más opciones de pestañas, mantén presionado el botón Mostrar pestañas de la barra de herramientas, que se encuentra en la parte inferior o superior de la pantalla.</translation>
 <translation id="4241912885070669028">Estás saliendo de una cuenta que administra <ph name="SIGNOUT_MANAGED_DOMAIN" />. Con esta acción, tus datos de Chromium se borrarán en este dispositivo, pero permanecerán en tu cuenta de Google.</translation>
 <translation id="4272892696084633551">Ayudar a mejorar las funciones y el rendimiento de Chromium</translation>
 <translation id="4555020257205549924">Si activas esta función, Chromium te preguntará si deseas usar Google Traductor para traducir páginas en otros idiomas. <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /></translation>
@@ -45,6 +46,7 @@
 <translation id="7357211569052832586">Los datos seleccionados se quitaron de Chromium y los dispositivos sincronizados. Es posible que tu cuenta de Google tenga otros formularios del historial de navegación, como las búsquedas y la actividad de otros servicios de Google en history.google.com.</translation>
 <translation id="7400689562045506105">Usa Chromium en todas partes</translation>
 <translation id="7674213385180944843">Abre Configuración &gt; Privacidad &gt; Cámara &gt; Chromium y activa la cámara.</translation>
+<translation id="7746854981345936341">Sugerencia de Chromium: Algunos botones ahora están en la parte inferior de la pantalla, como Retroceder, Avanzar y Buscar.</translation>
 <translation id="786327964234957808">La cuenta de sincronización cambiará de <ph name="USER_EMAIL1" /> a <ph name="USER_EMAIL2" />. El dominio <ph name="DOMAIN" /> administra tus datos existentes de Chromium. Esta acción borrará los datos de este dispositivo, pero permanecerán en <ph name="USER_EMAIL1" />.</translation>
 <translation id="8175055321229419309">Sugerencia: <ph name="BEGIN_LINK" />Lleva Chromium a tu Dock<ph name="END_LINK" /></translation>
 <translation id="8252885722420466166">Obtén una mejor experiencia de Google en Chromium según tu ubicación.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_te.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_te.xtb
index 9645a98..ced8655 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_te.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_te.xtb
@@ -23,6 +23,7 @@
 <translation id="3605252743693911722">మీ పరికరాలన్నింటిలో మీ బుక్‌మార్క్‌లు, పాస్‌వర్డ్‌లు మరియు మరిన్నింటిని పొందడం కోసం Chromiumకు సైన్ ఇన్ చేయండి.</translation>
 <translation id="3805899903892079518">Chromium మీ ఫోటోలు లేదా వీడియోలకు ప్రాప్యతను కలిగి లేదు. iOS సెట్టింగ్‌లు &gt; గోప్యత &gt; ఫోటోల్లో ప్రాప్యతను ప్రారంభించండి.</translation>
 <translation id="4024541897090868497">మీ అన్ని పరికరాల్లో మీ ట్యాబ్‌లను పొందడం కోసం, Chromiumకి సైన్ ఇన్ చేయండి.</translation>
+<translation id="4157467675761413638">Chromium చిట్కా. మరిన్ని ట్యాబ్ ఎంపికల కోసం, మీ స్క్రీన్‌లో పైన కాని దిగువన కాని ఉండే సాధనాల బార్‌లో ట్యాబ్‌లను చూపు బటన్‌ను నొక్కి పట్టుకోండి.</translation>
 <translation id="4241912885070669028">మీరు <ph name="SIGNOUT_MANAGED_DOMAIN" /> నిర్వహణలో ఉన్న ఖాతా నుండి సైన్ అవుట్ చేస్తున్నారు. దీని వలన మీ Chromium డేటా ఈ పరికరం నుండి తొలగించబడుతుంది, కానీ మీ డేటా మీ Google ఖాతాలో అలాగే ఉంటుంది.</translation>
 <translation id="4272892696084633551">Chromium ఫీచర్‌లు మరియు పనితీరును మెరుగుపరచడంలో సహాయపడండి</translation>
 <translation id="4555020257205549924">ఈ లక్షణం ప్రారంభించినప్పుడు, Chromium ఇతర భాషల్లో వ్రాసిన పేజీలకు Google అనువాదం ఉపయోగించి అనువాదాన్ని ఆఫర్ చేస్తుంది. <ph name="BEGIN_LINK" />మరింత తెలుసుకోండి<ph name="END_LINK" /></translation>
@@ -45,6 +46,7 @@
 <translation id="7357211569052832586">ఎంచుకోబడిన డేటా Chromium మరియు సమకాలీకరించిన పరికరాల నుండి తీసివేయబడింది. మీ Google ఖాతా history.google.comలో ఇతర Google సేవలకు సంబంధించిన శోధనలు మరియు కార్యాచరణ వంటి ఇతర రకాల బ్రౌజింగ్ చరిత్రను కలిగి ఉండవచ్చు.</translation>
 <translation id="7400689562045506105">Chromiumని అంతటా ఉపయోగించండి</translation>
 <translation id="7674213385180944843">సెట్టింగ్‌లు &gt; గోప్యత &gt; కెమెరా &gt; Chromium తెరిచి, కెమెరాను ఆన్ చేయండి.</translation>
+<translation id="7746854981345936341">Chromium చిట్కా. ఇప్పుడు కొన్ని బటన్‌లు మీ స్క్రీన్ దిగువున ఉన్నాయి, వెనకకు, ముందుకు మరియు శోధన వంటి బటన్‌లు.</translation>
 <translation id="786327964234957808">మీరు సమకాలీకరణ ఖాతాలను <ph name="USER_EMAIL1" /> నుండి <ph name="USER_EMAIL2" />కి మారుస్తున్నారు. ఇప్పటికే ఉన్న మీ Chromium డేటా <ph name="DOMAIN" /> నిర్వహణలో ఉంది. దీని వలన మీ డేటా ఈ పరికరం నుండి తొలగించబడుతుంది, కానీ మీ డేటా <ph name="USER_EMAIL1" />లో అలాగే ఉంటుంది.</translation>
 <translation id="8175055321229419309">చిట్కా: <ph name="BEGIN_LINK" />Chromiumని మీ డాక్‌కి తరలించండి<ph name="END_LINK" /></translation>
 <translation id="8252885722420466166">మీ స్థానం ఆధారంగా Chromiumలో మెరుగైన Google అనుభవాన్ని పొందండి.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb
index f8e4264a..ffa8174 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb
@@ -23,6 +23,7 @@
 <translation id="3605252743693911722">登录 Chromium 即可将您的书签、密码等同步到您的所有设备上。</translation>
 <translation id="3805899903892079518">Chromium 无权访问您的照片或视频。请依次点按 iOS 中的“设置”&gt;“隐私”&gt;“照片”,授予其访问权限。</translation>
 <translation id="4024541897090868497">要将您的标签页同步到您的所有设备上,请登录 Chromium。</translation>
+<translation id="4157467675761413638">Chromium 提示。要查看更多标签页选项,请按住工具栏(位于屏幕底部或顶部)中的“显示标签页”按钮。</translation>
 <translation id="4241912885070669028">您正要退出由 <ph name="SIGNOUT_MANAGED_DOMAIN" /> 管理的帐号。退出后,您的 Chromium 数据将从这台设备上删除,但仍会保留在您的 Google 帐号中。</translation>
 <translation id="4272892696084633551">帮助我们改进 Chromium 的功能和性能</translation>
 <translation id="4555020257205549924">启用此功能后,Chromium 将使用 Google 翻译对其他语言的网页进行翻译。<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
@@ -45,6 +46,7 @@
 <translation id="7357211569052832586">所选数据已从 Chromium 和同步的设备中移除。不过,您的 Google 帐号在 history.google.com 上可能有其他形式的浏览记录(例如,在其他 Google 服务中的搜索记录和活动记录)。</translation>
 <translation id="7400689562045506105">随时随地使用 Chromium</translation>
 <translation id="7674213385180944843">打开“设置”&gt;“隐私”&gt;“相机”&gt;“Chromium”,然后开启相机。</translation>
+<translation id="7746854981345936341">Chromium 提示。现在屏幕底部会显示“后退”、“前进”和“搜索”等按钮。</translation>
 <translation id="786327964234957808">您正要将同步帐号从 <ph name="USER_EMAIL1" /> 切换到 <ph name="USER_EMAIL2" />。您现有的 Chromium 数据由 <ph name="DOMAIN" /> 管理。切换同步帐号后,您的数据将从这台设备上删除,但仍会保留在 <ph name="USER_EMAIL1" /> 中。</translation>
 <translation id="8175055321229419309">提示:<ph name="BEGIN_LINK" />将 Chromium 移到 Dock 中<ph name="END_LINK" /></translation>
 <translation id="8252885722420466166">Chromium 可根据您的位置信息为您提供更好的 Google 产品使用体验。</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_bn.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_bn.xtb
index 4ffd12f..6148aff4 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_bn.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_bn.xtb
@@ -39,6 +39,7 @@
 <translation id="5639704535586432836">সেটিংস &gt; গোপনীয়তা &gt; ক্যামেরা &gt; Google Chrome খুলুন এবং ক্যামেরা চালু করুন।</translation>
 <translation id="5642200033778930880">Google Chrome আপনার ক্যামেরা বিভক্ত দৃশ্য মোডে ব্যবহার করতে পারবে না</translation>
 <translation id="5703130498371792817">Chrome ব্যবহার করে ভাল লাগছে? <ph name="BEGIN_LINK" />এই অ্যাপ্লিকেশানটিকে রেট দিন<ph name="END_LINK" /></translation>
+<translation id="5854621639439811139">Chrome টিপ। কিছু বোতাম এখন আপনার স্ক্রিনে নিচের দিকে রয়েছে যেমন, ব্যাক, ফরওয়ার্ড এবং সার্চ বোতাম।</translation>
 <translation id="6036420186814142909">Google Chrome এর একটি বৈশিষ্ট্য যা আপনাকে আপনার ইন্টারনেট ডেটা পরিচালনা করতে এবং কিভাবে আপনি ওয়েবপৃষ্ঠাগুলি দ্রুত লোড করতে সক্ষম হবেন সে বিষয়ে সহায়তা করে৷
 <ph name="BEGIN_LINK" />আরও জানুন<ph name="END_LINK" /></translation>
 <translation id="6573431926118603307">আপনার অন্য ডিভাইসগুলিতে Chrome এ আপনি যে ট্যাবগুলি খুলেছেন সেগুলি এখানে দেখা যাবে।</translation>
@@ -57,4 +58,5 @@
 <translation id="8459495907675268833">Chrome ও সিঙ্ক করা ডিভাইস থেকে নির্বাচিত ডেটা সরিয়ে ফেলা হয়েছে। আপনার Google অ্যাকাউন্টের সার্চ এবং অন্যান্য Google পরিষেবাগুলি থেকে অ্যাক্টিভিটির মত অন্যান্য ধরনের ব্রাউজিং ইতিহাস history.google.com এ থাকতে পারে।</translation>
 <translation id="8540666473246803645">Google Chrome</translation>
 <translation id="8606668294522778825">Google Chrome আপনার ব্রাউজিংয়ের অভিজ্ঞতাকে উন্নত করতে ওয়েব পরিষেবাগুলি ব্যবহার করতে পারে৷ আপনি আপনার ইচ্ছা অনুযায়ী এই পরিষেবাগুলিকে অক্ষম করতে পারেন৷ <ph name="BEGIN_LINK" />আরও জানুন<ph name="END_LINK" /></translation>
+<translation id="96145293669295453">Chrome টিপ। ট্যাবে আরও বিকল্পের জন্য, আপনার স্ক্রিনের নিচে অথবা উপরে থাকা টুলবারে দেখানো ট্যাবটি প্রেস করে ধরে থাকুন।</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_es-419.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_es-419.xtb
index 9a521904..648795d 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_es-419.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_es-419.xtb
@@ -39,6 +39,7 @@
 <translation id="5639704535586432836">Abre Configuración &gt; Privacidad &gt; Cámara &gt; Google Chrome y activa la cámara.</translation>
 <translation id="5642200033778930880">Google Chrome no puede usar tu cámara en el modo de vista dividida</translation>
 <translation id="5703130498371792817">¿Te gusta Chrome? <ph name="BEGIN_LINK" />Calificar esta app<ph name="END_LINK" /></translation>
+<translation id="5854621639439811139">Sugerencia de Chrome: Algunos botones ahora están en la parte inferior de la pantalla, como Retroceder, Avanzar y Buscar.</translation>
 <translation id="6036420186814142909">Google Chrome tiene funciones que te ayudan a administrar tus datos de Internet y la rapidez con la que puedes cargar páginas web.
 <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /></translation>
 <translation id="6573431926118603307">Aquí aparecerán las pestañas que abriste en Chrome en tus otros dispositivos.</translation>
@@ -57,4 +58,5 @@
 <translation id="8459495907675268833">Los datos seleccionados se quitaron de Chrome y los dispositivos sincronizados. Es posible que tu cuenta de Google tenga otros formularios del historial de navegación, como las búsquedas y la actividad de otros servicios de Google en history.google.com.</translation>
 <translation id="8540666473246803645">Google Chrome</translation>
 <translation id="8606668294522778825">Es posible que Google Chrome utilice servicios web para mejorar tu experiencia de navegación (tienes la opción de inhabilitar estos servicios). <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /></translation>
+<translation id="96145293669295453">Sugerencia de Chrome: Para obtener más opciones de pestañas, mantén presionado el botón Mostrar pestañas de la barra de herramientas, que se encuentra en la parte inferior o superior de la pantalla.</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_te.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_te.xtb
index 04d44cd..52a49599 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_te.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_te.xtb
@@ -39,6 +39,7 @@
 <translation id="5639704535586432836">సెట్టింగ్‌లు &gt; గోప్యత &gt; కెమెరా &gt; Google Chromeని తెరిచి, కెమెరాను ఆన్ చేయండి.</translation>
 <translation id="5642200033778930880">Google Chrome విభజన వీక్షణ మోడ్‌లో మీ కెమెరాను ఉపయోగించలేదు</translation>
 <translation id="5703130498371792817">Chromeని ఆస్వాదిస్తున్నారా? <ph name="BEGIN_LINK" />ఈ అనువర్తనాన్ని రేట్ చేయండి<ph name="END_LINK" /></translation>
+<translation id="5854621639439811139">Chrome చిట్కా. ఇప్పుడు కొన్ని బటన్‌లు మీ స్క్రీన్ దిగువున ఉన్నాయి, వెనకకు, ముందుకు మరియు శోధన వంటి బటన్‌లు.</translation>
 <translation id="6036420186814142909">మీ ఇంటర్నెట్ డేటాను నిర్వహించడంలో మరియు మీరు వెబ్ పేజీలను త్వరగా లోడ్ చేయగలగడంలో మీకు సహాయపడే లక్షణాలను Google Chrome కలిగి ఉంది.
 <ph name="BEGIN_LINK" />మరింత తెలుసుకోండి<ph name="END_LINK" /></translation>
 <translation id="6573431926118603307">మీరు మీ ఇతర పరికరాల్లోని Chromeలో తెరిచిన ట్యాబ్‌లు ఇక్కడ చూపబడతాయి.</translation>
@@ -57,4 +58,5 @@
 <translation id="8459495907675268833">ఎంచుకోబడిన డేటా Chrome మరియు సమకాలీకరించిన పరికరాల నుండి తీసివేయబడింది. మీ Google ఖాతా history.google.comలో ఇతర Google సేవలకు సంబంధించిన శోధనలు మరియు కార్యాచరణ వంటి ఇతర రకాల బ్రౌజింగ్ చరిత్రను కలిగి ఉండవచ్చు.</translation>
 <translation id="8540666473246803645">Google Chrome</translation>
 <translation id="8606668294522778825">Google Chrome మీ బ్రౌజింగ్ అనుభవాన్ని మెరుగుపరచడానికి వెబ్ సేవలను ఉపయోగించవచ్చు. మీరు ఈ సేవలను ఐచ్ఛికంగా నిలిపివేయవచ్చు. <ph name="BEGIN_LINK" />మరింత తెలుసుకోండి<ph name="END_LINK" /></translation>
+<translation id="96145293669295453">Chrome చిట్కా. మరిన్ని ట్యాబ్ ఎంపికల కోసం, మీ స్క్రీన్‌లో పైన కాని దిగువన కాని ఉండే సాధనాల బార్‌లో ట్యాబ్‌లను చూపు బటన్‌ను నొక్కి పట్టుకోండి.</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-CN.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-CN.xtb
index cfa8773..55fc847b 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-CN.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_zh-CN.xtb
@@ -39,6 +39,7 @@
 <translation id="5639704535586432836">打开“设置”&gt;“隐私”&gt;“相机”&gt;“Google Chrome”,然后开启相机。</translation>
 <translation id="5642200033778930880">Google Chrome 无法在分割视图模式下使用您的相机</translation>
 <translation id="5703130498371792817">您对 Chrome 使用体验感到满意吗?欢迎<ph name="BEGIN_LINK" />为此应用评分<ph name="END_LINK" /></translation>
+<translation id="5854621639439811139">Chrome 提示。现在屏幕底部会显示“后退”、“前进”和“搜索”等按钮。</translation>
 <translation id="6036420186814142909">Google Chrome 的某些功能可帮助您管理互联网数据和网页加载速度。
 <ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
 <translation id="6573431926118603307">您在其他设备上的 Chrome 中打开的标签页将列在此处。</translation>
@@ -57,4 +58,5 @@
 <translation id="8459495907675268833">所选数据已从 Chrome 和同步的设备中移除。不过,您的 Google 帐号在 history.google.com 上可能有其他形式的浏览记录(例如,在其他 Google 服务中的搜索记录和活动记录)。</translation>
 <translation id="8540666473246803645">Google Chrome</translation>
 <translation id="8606668294522778825">Google Chrome 可能会使用网络服务来改善您的浏览体验。不过,您可以选择停用这些服务。<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
+<translation id="96145293669295453">Chrome 提示。要查看更多标签页选项,请按住工具栏(位于屏幕底部或顶部)中的“显示标签页”按钮。</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_strings_te.xtb b/ios/chrome/app/strings/resources/ios_strings_te.xtb
index efae268..7767baf4 100644
--- a/ios/chrome/app/strings/resources/ios_strings_te.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_te.xtb
@@ -92,7 +92,7 @@
 <translation id="2386793615875593361">1 ఎంచుకోబడింది</translation>
 <translation id="2435457462613246316">పాస్‌వర్డ్‌ను చూపించు</translation>
 <translation id="2481538920734869610">ఖాతాను జోడించు</translation>
-<translation id="2523184218357549926">మీరు సందర్శించే పేజీల URLను Googleకి పంపుతుంది</translation>
+<translation id="2523184218357549926">మీరు సందర్శించే పేజీల URLలను Googleకి పంపుతుంది</translation>
 <translation id="2523363575747517183">ఈ వెబ్‌సైట్ మరో అప్లికేషన్‌ను తెరవడానికి పలుసార్లు ప్రయత్నిస్తోంది.</translation>
 <translation id="2529021024822217800">అన్నీ తెరువు</translation>
 <translation id="2572712655377361602">ఒక పరికర విధానం మీ ఫోటోలకు ప్రాప్యతను బ్లాక్ చేసింది</translation>
@@ -234,7 +234,7 @@
 <translation id="4930268273022498155">ఇప్పటికే ఉన్న డేటాను తొలగించండి. మీరు <ph name="USER_EMAIL1" />కి తిరిగి వెళ్లడం ద్వారా దాన్ని తిరిగి పొందవచ్చు.</translation>
 <translation id="4941089862236492464">క్షమించండి, మీ అంశాన్ని భాగస్వామ్యం చేయడంలో సమస్య ఉంది.</translation>
 <translation id="4979397965658815378">మీ బుక్‌మార్క్‌లు, పాస్‌వర్డ్‌లు, చరిత్ర మరియు ఇతర సెట్టింగ్‌లను మీ అన్ని పరికరాల్లో పొందడానికి మీ Google ఖాతాతో సైన్ ఇన్ చేయండి</translation>
-<translation id="5004416275253351869">Google కార్యకలాపం నియంత్రణలు</translation>
+<translation id="5004416275253351869">Google కార్యకలాప నియంత్రణలు</translation>
 <translation id="5005498671520578047">పాస్‌వర్డ్ కాపీచేయడం</translation>
 <translation id="5010803260590204777">వెబ్‌ను ప్రైవేట్‌గా బ్రౌజ్ చేయడానికి అజ్ఞాత ట్యాబ్‌ను తెరవండి.</translation>
 <translation id="5011684439661633295">హాయ్, <ph name="FULL_ACCOUNT_NAME" /></translation>
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 2cb9cac..c6d121a6 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -116,6 +116,7 @@
     "//ios/chrome/browser/ui/overlays",
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/browser/undo",
+    "//ios/chrome/browser/unified_consent",
     "//ios/net",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/signin",
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
index 4b32c26..2b5ca1e2 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
@@ -187,12 +187,11 @@
   // Set up a persistent store for use by the network stack on the IO thread.
   base::FilePath network_json_store_filepath(
       profile_path_.Append(kIOSChromeNetworkPersistentStateFilename));
-  network_json_store_ =
-      new JsonPrefStore(network_json_store_filepath,
-                        base::CreateSequencedTaskRunnerWithTraits(
-                            {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
-                             base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
-                        std::unique_ptr<PrefFilter>());
+  network_json_store_ = new JsonPrefStore(
+      network_json_store_filepath, std::unique_ptr<PrefFilter>(),
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+           base::TaskShutdownBehavior::BLOCK_SHUTDOWN}));
   network_json_store_->ReadPrefsAsync(nullptr);
 
   net::URLRequestContext* main_context = main_request_context();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
index a02510f..d61b1347 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
@@ -41,6 +41,7 @@
 #include "ios/chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h"
 
 namespace {
 
@@ -223,6 +224,9 @@
   ios::AccountFetcherServiceFactory::GetForBrowserState(browser_state)
       ->SetupInvalidationsOnProfileLoad(invalidation_service);
   ios::AccountReconcilorFactory::GetForBrowserState(browser_state);
+  // Initialization needs to happen after the browser context is available
+  // because ProfileSyncService needs the URL context getter.
+  UnifiedConsentServiceFactory::GetForBrowserState(browser_state);
   DesktopPromotionSyncServiceFactory::GetForBrowserState(browser_state);
 }
 
diff --git a/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc b/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc
index e1e93b1..1cc29d9 100644
--- a/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc
+++ b/ios/chrome/browser/prefs/ios_chrome_pref_service_factory.cc
@@ -36,7 +36,7 @@
                     const base::FilePath& pref_filename,
                     base::SequencedTaskRunner* pref_io_task_runner) {
   factory->set_user_prefs(base::MakeRefCounted<JsonPrefStore>(
-      pref_filename, pref_io_task_runner, std::unique_ptr<PrefFilter>()));
+      pref_filename, std::unique_ptr<PrefFilter>(), pref_io_task_runner));
 
   factory->set_read_error_callback(base::Bind(&HandleReadError));
   factory->SetPrefModelAssociatorClient(
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h
index 9ad66714..182e40c 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -78,7 +78,8 @@
 
   // Members that must be fetched on the UI thread but accessed on their
   // respective backend threads.
-  scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
+  scoped_refptr<autofill::AutofillWebDataService> profile_web_data_service_;
+  scoped_refptr<autofill::AutofillWebDataService> account_web_data_service_;
   scoped_refptr<password_manager::PasswordStore> password_store_;
 
   // The task runner for the |web_data_service_|, if any.
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 61d5db1e..617f1d5b 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
@@ -18,6 +19,7 @@
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_features.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/profile_sync_components_factory_impl.h"
 #include "components/browser_sync/profile_sync_service.h"
@@ -158,11 +160,18 @@
 void IOSChromeSyncClient::Initialize() {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
 
-  web_data_service_ =
+  profile_web_data_service_ =
       ios::WebDataServiceFactory::GetAutofillWebDataForBrowserState(
           browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
-  db_thread_ =
-      web_data_service_ ? web_data_service_->GetDBTaskRunner() : nullptr;
+  account_web_data_service_ =
+      base::FeatureList::IsEnabled(
+          autofill::features::kAutofillEnableAccountWalletStorage)
+          ? ios::WebDataServiceFactory::GetAutofillWebDataForAccount(
+                browser_state_, ServiceAccessType::IMPLICIT_ACCESS)
+          : nullptr;
+  db_thread_ = profile_web_data_service_
+                   ? profile_web_data_service_->GetDBTaskRunner()
+                   : nullptr;
   password_store_ = IOSChromePasswordStoreFactory::GetForBrowserState(
       browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
 
@@ -173,7 +182,7 @@
         ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET,
         prefs::kSavingBrowserHistoryDisabled,
         web::WebThread::GetTaskRunnerForThread(web::WebThread::UI), db_thread_,
-        web_data_service_, password_store_));
+        profile_web_data_service_, account_web_data_service_, password_store_));
   }
 }
 
@@ -277,19 +286,19 @@
     case syncer::AUTOFILL_PROFILE:
     case syncer::AUTOFILL_WALLET_DATA:
     case syncer::AUTOFILL_WALLET_METADATA: {
-      if (!web_data_service_)
+      if (!profile_web_data_service_)
         return base::WeakPtr<syncer::SyncableService>();
       if (type == syncer::AUTOFILL_PROFILE) {
         return autofill::AutofillProfileSyncableService::FromWebDataService(
-                   web_data_service_.get())
+                   profile_web_data_service_.get())
             ->AsWeakPtr();
       } else if (type == syncer::AUTOFILL_WALLET_METADATA) {
         return autofill::AutofillWalletMetadataSyncableService::
-            FromWebDataService(web_data_service_.get())
+            FromWebDataService(profile_web_data_service_.get())
                 ->AsWeakPtr();
       }
       return autofill::AutofillWalletSyncableService::FromWebDataService(
-                 web_data_service_.get())
+                 profile_web_data_service_.get())
           ->AsWeakPtr();
     }
     case syncer::HISTORY_DELETE_DIRECTIVES: {
@@ -342,32 +351,6 @@
           ->change_processor()
           ->GetControllerDelegate();
     }
-    case syncer::AUTOFILL:
-      return autofill::AutocompleteSyncBridge::FromWebDataService(
-                 web_data_service_.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    case syncer::AUTOFILL_PROFILE:
-      return autofill::AutofillProfileSyncBridge::FromWebDataService(
-                 web_data_service_.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    case syncer::AUTOFILL_WALLET_DATA: {
-      return autofill::AutofillWalletSyncBridge::FromWebDataService(
-                 web_data_service_.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    }
-    case syncer::AUTOFILL_WALLET_METADATA: {
-      return autofill::AutofillWalletMetadataSyncBridge::FromWebDataService(
-                 web_data_service_.get())
-          ->change_processor()
-          ->GetControllerDelegate();
-    }
-    case syncer::TYPED_URLS:
-      // TypedURLModelTypeController doesn't exercise this function.
-      NOTREACHED();
-      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::USER_CONSENTS:
       return ConsentAuditorFactory::GetForBrowserState(browser_state_)
           ->GetControllerDelegate();
@@ -379,6 +362,17 @@
     case syncer::SESSIONS:
       return ProfileSyncServiceFactory::GetForBrowserState(browser_state_)
           ->GetSessionSyncControllerDelegate();
+
+    // We don't exercise this function for certain datatypes, because their
+    // controllers get the delegate elsewhere.
+    case syncer::AUTOFILL:
+    case syncer::AUTOFILL_PROFILE:
+    case syncer::AUTOFILL_WALLET_DATA:
+    case syncer::AUTOFILL_WALLET_METADATA:
+    case syncer::TYPED_URLS:
+      NOTREACHED();
+      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
+
     default:
       NOTREACHED();
       return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
diff --git a/ios/chrome/browser/ui/authentication/authentication_constants.h b/ios/chrome/browser/ui/authentication/authentication_constants.h
index 8027d10d..11e2ce8 100644
--- a/ios/chrome/browser/ui/authentication/authentication_constants.h
+++ b/ios/chrome/browser/ui/authentication/authentication_constants.h
@@ -32,7 +32,14 @@
 // Height of the separator.
 extern const CGFloat kAuthenticationSeparatorHeight;
 
+// Height and width of the checkmark.
+extern const CGFloat kAuthenticationCheckmarkSize;
+// Color of the checkmark.
+extern const int kAuthenticationCheckmarkColor;
+
 // Header image name.
 extern NSString* const kAuthenticationHeaderImageName;
+// Checkmark image name.
+extern NSString* const kAuthenticationCheckmarkImageName;
 
 #endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_AUTHENTICATION_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/authentication/authentication_constants.mm b/ios/chrome/browser/ui/authentication/authentication_constants.mm
index 4426b14..3d7cace 100644
--- a/ios/chrome/browser/ui/authentication/authentication_constants.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_constants.mm
@@ -24,4 +24,8 @@
 const CGFloat kAuthenticationSeparatorColorAlpha = 0.12;
 const CGFloat kAuthenticationSeparatorHeight = 1;
 
+const CGFloat kAuthenticationCheckmarkSize = 18;
+const int kAuthenticationCheckmarkColor = 0x1A73E8;
+
 NSString* const kAuthenticationHeaderImageName = @"unified_consent_header";
+NSString* const kAuthenticationCheckmarkImageName = @"authentication_checkmark";
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 63ebfe9..3ac9fad 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -617,6 +617,7 @@
   // Add the account selector view controller.
   if (_unifiedConsentEnabled) {
     _unifiedConsentCoordinator = [[UnifiedConsentCoordinator alloc] init];
+    _unifiedConsentCoordinator.interactable = YES;
     _unifiedConsentCoordinator.delegate = self;
     if (_selectedIdentity)
       _unifiedConsentCoordinator.selectedIdentity = _selectedIdentity;
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn b/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn
index f79bd67..ffa5eed 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/consent_bump/BUILD.gn
@@ -40,12 +40,15 @@
     "consent_bump_view_controller_delegate.h",
   ]
   deps = [
-    "resources:consent_bump_checkmark",
     "//base",
+    "//base:i18n",
+    "//components/strings",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/ui/authentication:authentication_constants",
+    "//ios/chrome/browser/ui/authentication/resources:authentication_checkmark",
     "//ios/chrome/common/ui_util",
+    "//ios/third_party/material_components_ios",
     "//ui/base",
   ]
 }
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_consumer.h b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_consumer.h
index b6af1d6..a2be044 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_consumer.h
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_consumer.h
@@ -13,11 +13,11 @@
 // Sets the title of the primary button of the ConsentBump. By default the
 // primary button isn't visible.
 - (void)setPrimaryButtonTitle:(NSString*)primaryButtonTitle;
-// Sets the title of the secondary button of the ConsentBump.
-- (void)setSecondaryButtonTitle:(NSString*)secondaryButtonTitle;
 // Shows the primary button on the ConsentBump. There are no way to hide it once
 // it is shown.
 - (void)showPrimaryButton;
+// Whether to show the button to display more options, or the back button.
+- (void)showMoreOptionsButton:(BOOL)showMoreOptionsButton;
 
 @end
 
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm
index b4f36a0f..775a726 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator.mm
@@ -69,6 +69,7 @@
 
   self.unifiedConsentCoordinator = [[UnifiedConsentCoordinator alloc] init];
   self.unifiedConsentCoordinator.delegate = self;
+  self.unifiedConsentCoordinator.interactable = NO;
   [self.unifiedConsentCoordinator start];
   self.presentedCoordinatorType = ConsentBumpScreenUnifiedConsent;
 
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_mediator.mm b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_mediator.mm
index 10b4b69..1ba3e14 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_mediator.mm
@@ -23,15 +23,13 @@
     case ConsentBumpScreenUnifiedConsent:
       [self.consumer setPrimaryButtonTitle:l10n_util::GetNSString(
                                                IDS_IOS_CONSENT_BUMP_IM_IN)];
-      [self.consumer setSecondaryButtonTitle:l10n_util::GetNSString(
-                                                 IDS_IOS_CONSENT_BUMP_MORE)];
+      [self.consumer showMoreOptionsButton:YES];
       break;
 
     case ConsentBumpScreenPersonalization:
       [self.consumer
           setPrimaryButtonTitle:l10n_util::GetNSString(IDS_ACCNAME_OK)];
-      [self.consumer
-          setSecondaryButtonTitle:l10n_util::GetNSString(IDS_ACCNAME_BACK)];
+      [self.consumer showMoreOptionsButton:NO];
       [self consumerCanProceed];
       break;
   }
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_option_button.mm b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_option_button.mm
index b4b47be..ff584bd 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_option_button.mm
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_option_button.mm
@@ -18,9 +18,6 @@
 
 const CGFloat kImageViewMargin = 16;
 
-const CGFloat kCheckmarkSize = 18;
-const int kCheckmarkColor = 0x1A73E8;
-
 const CGFloat kHighlightAlpha = 0.07;
 
 const CGFloat kAnimationDuration = 0.15;
@@ -63,12 +60,12 @@
 
   UIImageView* checkMarkImageView = [[UIImageView alloc]
       initWithImage:
-          [[UIImage imageNamed:@"consent_bump_checkmark"]
+          [[UIImage imageNamed:kAuthenticationCheckmarkImageName]
               imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
   option.checkMarkImageView = checkMarkImageView;
   checkMarkImageView.translatesAutoresizingMaskIntoConstraints = NO;
   checkMarkImageView.hidden = YES;
-  checkMarkImageView.tintColor = UIColorFromRGB(kCheckmarkColor);
+  checkMarkImageView.tintColor = UIColorFromRGB(kAuthenticationCheckmarkColor);
   [option addSubview:checkMarkImageView];
 
   id<LayoutGuideProvider> safeArea = SafeAreaLayoutGuideForView(option);
@@ -127,8 +124,10 @@
     [checkMarkImageView.bottomAnchor
         constraintLessThanOrEqualToAnchor:option.bottomAnchor
                                  constant:-kImageViewMargin],
-    [checkMarkImageView.heightAnchor constraintEqualToConstant:kCheckmarkSize],
-    [checkMarkImageView.widthAnchor constraintEqualToConstant:kCheckmarkSize],
+    [checkMarkImageView.heightAnchor
+        constraintEqualToConstant:kAuthenticationCheckmarkSize],
+    [checkMarkImageView.widthAnchor
+        constraintEqualToConstant:kAuthenticationCheckmarkSize],
 
     // Separator.
     [separator.heightAnchor
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller.mm b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller.mm
index f5ac3541..1510b966 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller.mm
@@ -4,10 +4,13 @@
 
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller.h"
 
+#include "base/i18n/rtl.h"
+#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_view_controller_delegate.h"
 #include "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -18,21 +21,25 @@
 const CGFloat kMargin = 16;
 const CGFloat kGradientHeight = 40;
 const int kButtonBackgroundColor = 0x1A73E8;
+const int kButtonInkColor = 0x5E97F6;
 const CGFloat kButtonTitleGreyShade = 0.98;
 const CGFloat kButtonCornerRadius = 8;
 const CGFloat kButtonPadding = 16;
 const CGFloat kButtonVerticalPadding = 8;
 const CGFloat kButtonMinimalWidth = 80;
 const CGFloat kButtonTitleChangeAnimationDuration = 0.15;
+const CGFloat kImageTitleSpace = 10;
 }  // namespace
 
 @interface ConsentBumpViewController ()
 
 @property(nonatomic, strong) UIView* buttonContainer;
 // Primary button. Hidden by default.
-@property(nonatomic, strong) UIButton* primaryButton;
-// Secondary button.
-@property(nonatomic, strong) UIButton* secondaryButton;
+@property(nonatomic, strong) MDCFlatButton* primaryButton;
+// Button used to displayed more options (i.e. the personalization screen).
+@property(nonatomic, strong) UIButton* moreOptionsButton;
+// Button used to get back to the first screen.
+@property(nonatomic, strong) UIButton* backButton;
 // More button. Used to scroll the content to the bottom. Only displayed while
 // the primary button is hidden.
 @property(nonatomic, strong) UIButton* moreButton;
@@ -51,7 +58,8 @@
 @synthesize contentViewController = _contentViewController;
 @synthesize buttonContainer = _buttonContainer;
 @synthesize primaryButton = _primaryButton;
-@synthesize secondaryButton = _secondaryButton;
+@synthesize moreOptionsButton = _moreOptionsButton;
+@synthesize backButton = _backButton;
 @synthesize moreButton = _moreButton;
 @synthesize secondaryMoreButtonMarginConstraint =
     _secondaryMoreButtonMarginConstraint;
@@ -93,18 +101,24 @@
 
 - (UIButton*)primaryButton {
   if (!_primaryButton) {
-    _primaryButton = [UIButton buttonWithType:UIButtonTypeSystem];
+    _primaryButton = [[MDCFlatButton alloc] init];
+    _primaryButton.uppercaseTitle = NO;
+    _primaryButton.layer.cornerRadius = kButtonCornerRadius;
+    [_primaryButton
+        setTitleFont:[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]
+            forState:UIControlStateNormal];
     _primaryButton.translatesAutoresizingMaskIntoConstraints = NO;
-    _primaryButton.backgroundColor = UIColorFromRGB(kButtonBackgroundColor);
     [_primaryButton
         setTitleColor:[UIColor colorWithWhite:kButtonTitleGreyShade alpha:1]
              forState:UIControlStateNormal];
-    _primaryButton.layer.cornerRadius = kButtonCornerRadius;
     _primaryButton.contentEdgeInsets =
         UIEdgeInsetsMake(kButtonVerticalPadding, kButtonPadding,
                          kButtonVerticalPadding, kButtonPadding);
     [_primaryButton setContentHuggingPriority:UILayoutPriorityDefaultHigh
                                       forAxis:UILayoutConstraintAxisVertical];
+    [_primaryButton setBackgroundColor:UIColorFromRGB(kButtonBackgroundColor)
+                              forState:UIControlStateNormal];
+    _primaryButton.inkColor = UIColorFromRGB(kButtonInkColor);
     [_primaryButton addTarget:self
                        action:@selector(primaryButtonCallback)
              forControlEvents:UIControlEventTouchUpInside];
@@ -113,31 +127,34 @@
   return _primaryButton;
 }
 
-- (UIButton*)secondaryButton {
-  if (!_secondaryButton) {
-    _secondaryButton = [UIButton buttonWithType:UIButtonTypeSystem];
-    _secondaryButton.translatesAutoresizingMaskIntoConstraints = NO;
-    _secondaryButton.contentEdgeInsets =
-        UIEdgeInsetsMake(kButtonVerticalPadding, kButtonPadding,
-                         kButtonVerticalPadding, kButtonPadding);
-    [_secondaryButton setContentHuggingPriority:UILayoutPriorityDefaultHigh
-                                        forAxis:UILayoutConstraintAxisVertical];
-    [_secondaryButton addTarget:self
-                         action:@selector(secondaryButtonCallback)
-               forControlEvents:UIControlEventTouchUpInside];
+- (UIButton*)moreOptionsButton {
+  if (!_moreOptionsButton) {
+    _moreOptionsButton = [self createButton];
+    [_moreOptionsButton
+        setTitle:l10n_util::GetNSString(IDS_IOS_CONSENT_BUMP_MORE)
+        forState:UIControlStateNormal];
+    [_moreOptionsButton addTarget:self
+                           action:@selector(secondaryButtonCallback)
+                 forControlEvents:UIControlEventTouchUpInside];
   }
-  return _secondaryButton;
+  return _moreOptionsButton;
+}
+
+- (UIButton*)backButton {
+  if (!_backButton) {
+    _backButton = [self createButton];
+    [_backButton setTitle:l10n_util::GetNSString(IDS_ACCNAME_BACK)
+                 forState:UIControlStateNormal];
+    [_backButton addTarget:self
+                    action:@selector(secondaryButtonCallback)
+          forControlEvents:UIControlEventTouchUpInside];
+  }
+  return _backButton;
 }
 
 - (UIButton*)moreButton {
   if (!_moreButton) {
-    _moreButton = [UIButton buttonWithType:UIButtonTypeSystem];
-    _moreButton.translatesAutoresizingMaskIntoConstraints = NO;
-    _moreButton.contentEdgeInsets =
-        UIEdgeInsetsMake(kButtonVerticalPadding, kButtonPadding,
-                         kButtonVerticalPadding, kButtonPadding);
-    [_moreButton setContentHuggingPriority:UILayoutPriorityDefaultHigh
-                                   forAxis:UILayoutConstraintAxisVertical];
+    _moreButton = [self createButton];
     [_moreButton addTarget:self
                     action:@selector(moreButtonCallback)
           forControlEvents:UIControlEventTouchUpInside];
@@ -147,6 +164,17 @@
         forState:UIControlStateNormal];
     [_moreButton setImage:[UIImage imageNamed:@"signin_confirmation_more"]
                  forState:UIControlStateNormal];
+    UIEdgeInsets insets = _moreButton.contentEdgeInsets;
+    if (base::i18n::IsRTL()) {
+      _moreButton.titleEdgeInsets =
+          UIEdgeInsetsMake(0, -kImageTitleSpace, 0, 0);
+      insets.left += kImageTitleSpace;
+    } else {
+      _moreButton.titleEdgeInsets =
+          UIEdgeInsetsMake(0, 0, 0, -kImageTitleSpace);
+      insets.right += kImageTitleSpace;
+    }
+    _moreButton.contentEdgeInsets = insets;
   }
   return _moreButton;
 }
@@ -193,13 +221,14 @@
   // Add subviews.
   [self.buttonContainer addSubview:self.primaryButton];
   [self.buttonContainer addSubview:self.moreButton];
-  [self.buttonContainer addSubview:self.secondaryButton];
+  [self.buttonContainer addSubview:self.moreOptionsButton];
+  [self.buttonContainer addSubview:self.backButton];
   [self.view addSubview:self.buttonContainer];
   [self.view addSubview:self.gradientView];
 
   // Constraints.
   self.secondaryMoreButtonMarginConstraint = [self.moreButton.leadingAnchor
-      constraintGreaterThanOrEqualToAnchor:self.secondaryButton.trailingAnchor
+      constraintGreaterThanOrEqualToAnchor:self.moreOptionsButton.trailingAnchor
                                   constant:kMargin];
   id<LayoutGuideProvider> safeArea = SafeAreaLayoutGuideForView(self.view);
   AddSameConstraintsToSides(self.view, self.gradientView,
@@ -208,7 +237,11 @@
       safeArea, self.buttonContainer,
       LayoutSides::kBottom | LayoutSides::kLeading | LayoutSides::kTrailing);
   AddSameConstraintsToSidesWithInsets(
-      self.secondaryButton, self.buttonContainer,
+      self.moreOptionsButton, self.buttonContainer,
+      LayoutSides::kLeading | LayoutSides::kTop | LayoutSides::kBottom,
+      ChromeDirectionalEdgeInsetsMake(kMargin, kMargin, kMargin, 0));
+  AddSameConstraintsToSidesWithInsets(
+      self.backButton, self.buttonContainer,
       LayoutSides::kLeading | LayoutSides::kTop | LayoutSides::kBottom,
       ChromeDirectionalEdgeInsetsMake(kMargin, kMargin, kMargin, 0));
   AddSameConstraintsToSidesWithInsets(
@@ -225,14 +258,20 @@
     [self.gradientView.bottomAnchor
         constraintEqualToAnchor:self.buttonContainer.topAnchor],
     [self.primaryButton.leadingAnchor
-        constraintGreaterThanOrEqualToAnchor:self.secondaryButton.trailingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.moreOptionsButton
+                                                 .trailingAnchor
+                                    constant:kMargin],
+    [self.primaryButton.leadingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.backButton.trailingAnchor
                                     constant:kMargin],
 
     // Add minimum width to the buttons to have a better looking animation when
     // changing the label.
     [self.primaryButton.widthAnchor
         constraintGreaterThanOrEqualToConstant:kButtonMinimalWidth],
-    [self.secondaryButton.widthAnchor
+    [self.moreOptionsButton.widthAnchor
+        constraintGreaterThanOrEqualToConstant:kButtonMinimalWidth],
+    [self.backButton.widthAnchor
         constraintGreaterThanOrEqualToConstant:kButtonMinimalWidth],
   ]];
 }
@@ -252,17 +291,20 @@
                   completion:nil];
 }
 
-- (void)setSecondaryButtonTitle:(NSString*)secondaryButtonTitle {
-  // Use CrossDisolve to avoid issue where the button is changing size before
-  // changing its label, leading to an inconsistent animation.
-  [UIView transitionWithView:self.primaryButton
-                    duration:kButtonTitleChangeAnimationDuration
-                     options:UIViewAnimationOptionTransitionCrossDissolve
-                  animations:^{
-                    [self.secondaryButton setTitle:secondaryButtonTitle
-                                          forState:UIControlStateNormal];
-                  }
-                  completion:nil];
+- (void)showMoreOptionsButton:(BOOL)showMoreOptionsButton {
+  self.moreOptionsButton.hidden = NO;
+  self.backButton.hidden = NO;
+  self.moreOptionsButton.alpha = showMoreOptionsButton ? 0 : 1;
+  self.backButton.alpha = showMoreOptionsButton ? 1 : 0;
+  [UIView animateWithDuration:kButtonTitleChangeAnimationDuration
+      animations:^{
+        self.moreOptionsButton.alpha = showMoreOptionsButton ? 1 : 0;
+        self.backButton.alpha = showMoreOptionsButton ? 0 : 1;
+      }
+      completion:^(BOOL finished) {
+        self.moreOptionsButton.hidden = !showMoreOptionsButton;
+        self.backButton.hidden = showMoreOptionsButton;
+      }];
 }
 
 - (void)showPrimaryButton {
@@ -273,6 +315,21 @@
 
 #pragma mark - Private
 
+// Returns a new UIButton, configured.
+- (UIButton*)createButton {
+  UIButton* button = [UIButton buttonWithType:UIButtonTypeSystem];
+  button.titleLabel.font =
+      [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+  button.translatesAutoresizingMaskIntoConstraints = NO;
+  button.contentEdgeInsets =
+      UIEdgeInsetsMake(kButtonVerticalPadding, kButtonPadding,
+                       kButtonVerticalPadding, kButtonPadding);
+  [button setContentHuggingPriority:UILayoutPriorityDefaultHigh
+                            forAxis:UILayoutConstraintAxisVertical];
+
+  return button;
+}
+
 - (void)primaryButtonCallback {
   [self.delegate consentBumpViewControllerDidTapPrimaryButton:self];
 }
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/resources/BUILD.gn b/ios/chrome/browser/ui/authentication/consent_bump/resources/BUILD.gn
deleted file mode 100644
index 9d3ab16..0000000
--- a/ios/chrome/browser/ui/authentication/consent_bump/resources/BUILD.gn
+++ /dev/null
@@ -1,14 +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("//build/config/ios/asset_catalog.gni")
-
-imageset("consent_bump_checkmark") {
-  sources = [
-    "consent_bump_checkmark.imageset/Contents.json",
-    "consent_bump_checkmark.imageset/consent_bump_checkmark.png",
-    "consent_bump_checkmark.imageset/consent_bump_checkmark@2x.png",
-    "consent_bump_checkmark.imageset/consent_bump_checkmark@3x.png",
-  ]
-}
diff --git a/ios/chrome/browser/ui/authentication/resources/BUILD.gn b/ios/chrome/browser/ui/authentication/resources/BUILD.gn
index 02a9899..0a892c6 100644
--- a/ios/chrome/browser/ui/authentication/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/resources/BUILD.gn
@@ -4,6 +4,15 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
+imageset("authentication_checkmark") {
+  sources = [
+    "authentication_checkmark.imageset/Contents.json",
+    "authentication_checkmark.imageset/authentication_checkmark.png",
+    "authentication_checkmark.imageset/authentication_checkmark@2x.png",
+    "authentication_checkmark.imageset/authentication_checkmark@3x.png",
+  ]
+}
+
 imageset("signin_confirmation_more") {
   sources = [
     "signin_confirmation_more.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/Contents.json b/ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/Contents.json
similarity index 66%
copy from ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/Contents.json
copy to ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/Contents.json
index 445d0bc..96700ba 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/Contents.json
+++ b/ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/Contents.json
@@ -3,17 +3,17 @@
         {
             "idiom": "universal",
             "scale": "1x",
-            "filename": "consent_bump_checkmark.png"
+            "filename": "authentication_checkmark.png"
         },
         {
             "idiom": "universal",
             "scale": "2x",
-            "filename": "consent_bump_checkmark@2x.png"
+            "filename": "authentication_checkmark@2x.png"
         },
         {
             "idiom": "universal",
             "scale": "3x",
-            "filename": "consent_bump_checkmark@3x.png"
+            "filename": "authentication_checkmark@3x.png"
         }
     ],
     "info": {
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/consent_bump_checkmark.png b/ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/authentication_checkmark.png
similarity index 100%
rename from ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/consent_bump_checkmark.png
rename to ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/authentication_checkmark.png
Binary files differ
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/consent_bump_checkmark@2x.png b/ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/authentication_checkmark@2x.png
similarity index 100%
rename from ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/consent_bump_checkmark@2x.png
rename to ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/authentication_checkmark@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/consent_bump_checkmark@3x.png b/ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/authentication_checkmark@3x.png
similarity index 100%
rename from ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/consent_bump_checkmark@3x.png
rename to ios/chrome/browser/ui/authentication/resources/authentication_checkmark.imageset/authentication_checkmark@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn b/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
index a8f858a..adf983247 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
@@ -43,6 +43,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/ui/authentication:authentication_constants",
+    "//ios/chrome/browser/ui/authentication/resources:authentication_checkmark",
     "//ios/chrome/browser/ui/authentication/unified_consent/identity_chooser:identity_chooser_ui",
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h
index 4ad661a..026d2aa 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h
@@ -16,6 +16,9 @@
 // -[UIControl addTarget:action:forControlEvents:].
 @interface IdentityPickerView : UIControl
 
+// Whether the identity displayed by this view can be changed.
+@property(nonatomic, assign) BOOL canChangeIdentity;
+
 // Initialises IdentityPickerView.
 - (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
 
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
index 169d253..f13ed8b 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h"
 
 #include "base/logging.h"
+#import "ios/chrome/browser/ui/authentication/authentication_constants.h"
 #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_view.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
@@ -35,13 +36,22 @@
 
 @property(nonatomic, strong) IdentityView* identityView;
 @property(nonatomic, strong) MDCInkView* inkView;
+// Image View for the down arrow, letting the user know that more profiles can
+// be selected.
+@property(nonatomic, strong) UIImageView* arrowDownImageView;
+// Image View for the checkmark, indicating that the selected identity cannot be
+// changed.
+@property(nonatomic, strong) UIImageView* checkmarkImageView;
 
 @end
 
 @implementation IdentityPickerView
 
+@synthesize canChangeIdentity = _canChangeIdentity;
 @synthesize identityView = _identityView;
 @synthesize inkView = _inkView;
+@synthesize arrowDownImageView = _arrowDownImageView;
+@synthesize checkmarkImageView = _checkmarkImageView;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
@@ -58,12 +68,21 @@
     [self addSubview:_inkView];
 
     // Arrow down.
-    UIImageView* arrowDownImageView =
-        [[UIImageView alloc] initWithFrame:CGRectZero];
-    arrowDownImageView.translatesAutoresizingMaskIntoConstraints = NO;
-    arrowDownImageView.image =
+    _arrowDownImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
+    _arrowDownImageView.translatesAutoresizingMaskIntoConstraints = NO;
+    _arrowDownImageView.image =
         [UIImage imageNamed:@"identity_picker_view_arrow_down"];
-    [self addSubview:arrowDownImageView];
+    [self addSubview:_arrowDownImageView];
+
+    // Checkmark.
+    _checkmarkImageView = [[UIImageView alloc] init];
+    _checkmarkImageView.translatesAutoresizingMaskIntoConstraints = NO;
+    _checkmarkImageView.image =
+        [[UIImage imageNamed:kAuthenticationCheckmarkImageName]
+            imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    _checkmarkImageView.tintColor =
+        UIColorFromRGB(kAuthenticationCheckmarkColor);
+    [self addSubview:_checkmarkImageView];
 
     // Main view with avatar, name and email.
     _identityView = [[IdentityView alloc] initWithFrame:CGRectZero];
@@ -73,11 +92,13 @@
     // Layout constraints.
     NSDictionary* views = @{
       @"identityview" : _identityView,
-      @"arrow" : arrowDownImageView,
+      @"arrow" : _arrowDownImageView,
+      @"checkmark" : _checkmarkImageView,
     };
     NSDictionary* metrics = @{
       @"ArrowMargin" : @(kArrowDownMargin),
       @"ArrowSize" : @(kArrowDownSize),
+      @"CheckmarkSize" : @(kAuthenticationCheckmarkSize),
       @"HAvatMrg" : @(kHorizontalAvatarMargin),
       @"VMargin" : @(kVerticalMargin),
     };
@@ -89,8 +110,11 @@
       // Size constraints.
       @"H:[arrow(ArrowSize)]",
       @"V:[arrow(ArrowSize)]",
+      @"H:[checkmark(CheckmarkSize)]",
+      @"V:[checkmark(CheckmarkSize)]",
     ];
-    AddSameCenterYConstraint(self, arrowDownImageView);
+    AddSameCenterYConstraint(self, _arrowDownImageView);
+    AddSameCenterConstraints(_checkmarkImageView, _arrowDownImageView);
     ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
   }
   return self;
@@ -98,6 +122,13 @@
 
 #pragma mark - Setter
 
+- (void)setCanChangeIdentity:(BOOL)canChangeIdentity {
+  _canChangeIdentity = canChangeIdentity;
+  self.enabled = canChangeIdentity;
+  self.arrowDownImageView.hidden = !canChangeIdentity;
+  self.checkmarkImageView.hidden = canChangeIdentity;
+}
+
 - (void)setIdentityAvatar:(UIImage*)identityAvatar {
   [self.identityView setAvatar:identityAvatar];
 }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
index 294958d22..b672f1d67 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
@@ -52,6 +52,8 @@
 @property(nonatomic, readonly) BOOL isScrolledToBottom;
 // Returns YES if the user tapped on the setting link.
 @property(nonatomic, readonly) BOOL settingsLinkWasTapped;
+// Whether the ViewController configured by this coordinator is interactable.
+@property(nonatomic, assign) BOOL interactable;
 
 // Starts this coordinator.
 - (void)start;
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
index db3d52c..fdc109a3 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
@@ -31,6 +31,7 @@
 @synthesize unifiedConsentMediator = _unifiedConsentMediator;
 @synthesize unifiedConsentViewController = _unifiedConsentViewController;
 @synthesize settingsLinkWasTapped = _settingsLinkWasTapped;
+@synthesize interactable = _interactable;
 @synthesize identityChooserCoordinator = _identityChooserCoordinator;
 
 - (instancetype)init {
@@ -45,6 +46,7 @@
 }
 
 - (void)start {
+  self.unifiedConsentViewController.interactable = self.interactable;
   [self.unifiedConsentMediator start];
 }
 
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.h b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.h
index a6bee264..8e8efa9 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.h
@@ -44,6 +44,8 @@
 @property(nonatomic, assign, readonly) int openSettingsStringId;
 // Returns YES if the consent view is scrolled to the bottom.
 @property(nonatomic, assign, readonly) BOOL isScrolledToBottom;
+// Whether it is possible to interact with this ViewController.
+@property(nonatomic, assign) BOOL interactable;
 
 // -[UnifiedConsentViewController init] should be used.
 - (instancetype)initWithNibName:(NSString*)nibNameOrNil
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
index e78bb622..c80fa97 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
@@ -92,6 +92,7 @@
     _imageBackgroundViewHeightConstraint;
 @synthesize noIdentityConstraint = _noIdentityConstraint;
 @synthesize openSettingsStringId = _openSettingsStringId;
+@synthesize interactable = _interactable;
 @synthesize scrollView = _scrollView;
 @synthesize settingsLinkController = _settingsLinkController;
 @synthesize withIdentityConstraint = _withIdentityConstraint;
@@ -108,7 +109,7 @@
   self.noIdentityConstraint.active = NO;
   self.withIdentityConstraint.active = YES;
   [self.identityPickerView setIdentityName:fullName email:email];
-  [self setSettingsLinkURLShown:YES];
+  [self setSettingsLinkURLShown:self.interactable];
 }
 
 - (void)updateIdentityPickerViewWithAvatar:(UIImage*)avatar {
@@ -139,6 +140,15 @@
   return scrollPosition >= scrollLimit;
 }
 
+- (void)setInteractable:(BOOL)interactable {
+  _interactable = interactable;
+  if (!self.viewLoaded)
+    return;
+
+  self.identityPickerView.canChangeIdentity = interactable;
+  [self setSettingsLinkURLShown:interactable];
+}
+
 #pragma mark - UIViewController
 
 - (void)viewDidLoad {
@@ -190,6 +200,7 @@
   // Identity picker view.
   self.identityPickerView =
       [[IdentityPickerView alloc] initWithFrame:CGRectZero];
+  self.identityPickerView.canChangeIdentity = self.interactable;
   self.identityPickerView.translatesAutoresizingMaskIntoConstraints = NO;
   [self.identityPickerView addTarget:self
                               action:@selector(identityPickerAction:)
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/resources/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/resources/BUILD.gn
new file mode 100644
index 0000000..3f1e2fd
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/resources/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ios/asset_catalog.gni")
+
+imageset("addresses") {
+  sources = [
+    "addresses.imageset/Contents.json",
+    "addresses.imageset/addresses.png",
+    "addresses.imageset/addresses@2x.png",
+    "addresses.imageset/addresses@3x.png",
+  ]
+}
diff --git a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/Contents.json b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/Contents.json
similarity index 67%
rename from ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/Contents.json
rename to ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/Contents.json
index 445d0bc..ce006b4 100644
--- a/ios/chrome/browser/ui/authentication/consent_bump/resources/consent_bump_checkmark.imageset/Contents.json
+++ b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/Contents.json
@@ -3,17 +3,17 @@
         {
             "idiom": "universal",
             "scale": "1x",
-            "filename": "consent_bump_checkmark.png"
+            "filename": "addresses.png"
         },
         {
             "idiom": "universal",
             "scale": "2x",
-            "filename": "consent_bump_checkmark@2x.png"
+            "filename": "addresses@2x.png"
         },
         {
             "idiom": "universal",
             "scale": "3x",
-            "filename": "consent_bump_checkmark@3x.png"
+            "filename": "addresses@3x.png"
         }
     ],
     "info": {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses.png b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses.png
new file mode 100644
index 0000000..98bdcd40
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses.png
Binary files differ
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses@2x.png b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses@2x.png
new file mode 100644
index 0000000..cea2c80
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses@3x.png b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses@3x.png
new file mode 100644
index 0000000..6c603dc
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/resources/addresses.imageset/addresses@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h
index e6dd289c..37e2b90 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h
@@ -46,6 +46,10 @@
 // Command to trigger when the cell is tapped. The default value is 0.
 @property(nonatomic, assign) NSInteger commandID;
 
+// YES if the cell should be tappable. The text color is grayed out when set to
+// NO (only if no |textColor| has been set). The default value is YES.
+@property(nonatomic, assign) BOOL enabled;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COLLECTION_VIEW_CELLS_COLLECTION_VIEW_TEXT_ITEM_H_
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm
index d3db43f..23de748 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm
@@ -25,6 +25,7 @@
 @synthesize detailTextColor = _detailTextColor;
 @synthesize numberOfDetailTextLines = _numberOfDetailTextLines;
 @synthesize commandID = _commandID;
+@synthesize enabled = _enabled;
 
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
@@ -32,6 +33,7 @@
     self.cellClass = [CollectionViewTextCell class];
     _numberOfTextLines = 1;
     _numberOfDetailTextLines = 1;
+    _enabled = YES;
   }
   return self;
 }
@@ -45,7 +47,8 @@
 
 - (UIColor*)textColor {
   if (!_textColor) {
-    _textColor = [[MDCPalette greyPalette] tint900];
+    return self.enabled ? [[MDCPalette greyPalette] tint900]
+                        : [[MDCPalette greyPalette] tint500];
   }
   return _textColor;
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
index 6745288..b9286f8 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h"
 #include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/favicon/favicon_view.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
@@ -19,6 +20,8 @@
 const CGFloat kCountWidth = 20;
 const CGFloat kCountBorderWidth = 24;
 
+const int kBackgroundColor = 0xE8F1FC;
+
 }  // namespace
 
 @implementation ContentSuggestionsMostVisitedActionCell : MDCCollectionViewCell
@@ -42,19 +45,33 @@
 
     _iconView = [[UIImageView alloc] initWithFrame:self.bounds];
 
+    UIImageView* iconBackground = [[UIImageView alloc] init];
+    iconBackground.image = [[UIImage imageNamed:@"ntp_most_visited_tile"]
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    iconBackground.tintColor = UIColorFromRGB(kBackgroundColor);
+
     _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _iconView.translatesAutoresizingMaskIntoConstraints = NO;
+    iconBackground.translatesAutoresizingMaskIntoConstraints = NO;
 
+    [self.contentView addSubview:iconBackground];
     [self.contentView addSubview:_titleLabel];
     [self.contentView addSubview:_iconView];
 
     [NSLayoutConstraint activateConstraints:@[
       [_iconView.widthAnchor constraintEqualToConstant:kIconSize],
+      [iconBackground.widthAnchor
+          constraintEqualToAnchor:_iconView.widthAnchor],
       [_iconView.heightAnchor constraintEqualToAnchor:_iconView.widthAnchor],
+      [iconBackground.heightAnchor
+          constraintEqualToAnchor:iconBackground.widthAnchor],
       [_iconView.centerXAnchor
           constraintEqualToAnchor:_titleLabel.centerXAnchor],
     ]];
 
+    AddSameCenterXConstraint(iconBackground, _iconView);
+    AddSameCenterYConstraint(iconBackground, _iconView);
+
     ApplyVisualConstraintsWithMetrics(
         @[ @"V:|[icon]-(space)-[title]", @"H:|[title]|" ],
         @{@"icon" : _iconView, @"title" : _titleLabel},
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm
index f6417fa5..b06146017 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.mm
@@ -93,16 +93,22 @@
 - (UIImage*)imageForAction:(ContentSuggestionsMostVisitedAction)action {
   switch (action) {
     case ContentSuggestionsMostVisitedActionBookmark:
-      return [UIImage imageNamed:@"ntp_bookmarks_icon"];
+      return [self imageGettingTintedNamed:@"ntp_bookmarks_icon"];
     case ContentSuggestionsMostVisitedActionReadingList:
-      return [UIImage imageNamed:@"ntp_readinglist_icon"];
+      return [self imageGettingTintedNamed:@"ntp_readinglist_icon"];
     case ContentSuggestionsMostVisitedActionRecentTabs:
-      return [UIImage imageNamed:@"ntp_recent_icon"];
+      return [self imageGettingTintedNamed:@"ntp_recent_icon"];
     case ContentSuggestionsMostVisitedActionHistory:
-      return [UIImage imageNamed:@"ntp_history_icon"];
+      return [self imageGettingTintedNamed:@"ntp_history_icon"];
   }
 }
 
+// Returns the image named |imageName| with a rendering mode "AlwaysTemplate".
+- (UIImage*)imageGettingTintedNamed:(NSString*)imageName {
+  return [[UIImage imageNamed:imageName]
+      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+}
+
 // Updates self.accessibilityLabel based on the current property values.
 - (void)updateAccessibilityLabel {
   // Resetting self.accessibilityLabel to nil will prompt self.title to be used
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png
index e0f6691..40b2c13 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png
index faf2f501..7855deaf 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png
index eb1b41a7..f1af62b 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_bookmarks_icon.imageset/ntp_bookmarks_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png
index 5c8a320..7a014d1 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png
index 0c4738af..6aec266 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png
index ee1a638..38146767 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_history_icon.imageset/ntp_history_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png
index 80c7da13..91ff28f7 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png
index 0e0bb836..a3239699 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png
index 45248d64..abc4c13e 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_readinglist_icon.imageset/ntp_readinglist_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png
index f43c7059..cd73e172 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png
index 2e6c29c..e8373d1 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png
index a27261b..f55dd44d 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png
+++ b/ios/chrome/browser/ui/content_suggestions/cells/resources/ntp_recent_icon.imageset/ntp_recent_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn
index 699e1144..f9974165 100644
--- a/ios/chrome/browser/ui/first_run/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -48,6 +48,7 @@
     "//ios/third_party/material_components_ios",
     "//ios/third_party/material_roboto_font_loader_ios",
     "//ios/web",
+    "//services/identity/public/cpp:cpp",
     "//ui/base",
     "//ui/gfx",
     "//url",
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm
index da04f11..b633086e 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -11,19 +11,19 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/time/time.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/crash_report/breakpad_helper.h"
 #include "ios/chrome/browser/first_run/first_run.h"
 #import "ios/chrome/browser/first_run/first_run_configuration.h"
 #include "ios/chrome/browser/first_run/first_run_metrics.h"
-#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/tabs/tab.h"
 #include "ios/chrome/browser/ui/first_run/first_run_histograms.h"
 #import "ios/chrome/browser/ui/settings/settings_utils.h"
 #import "ios/chrome/browser/ui/settings/sync_utils/sync_util.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/web/public/web_thread.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -94,9 +94,8 @@
                                    bool sign_in_attempted,
                                    bool has_sso_accounts) {
   first_run::SignInStatus sign_in_status;
-  bool user_signed_in =
-      ios::SigninManagerFactory::GetForBrowserState(browserState)
-          ->IsAuthenticated();
+  bool user_signed_in = IdentityManagerFactory::GetForBrowserState(browserState)
+                            ->HasPrimaryAccount();
   if (user_signed_in) {
     sign_in_status = has_sso_accounts
                          ? first_run::HAS_SSO_ACCOUNT_SIGNIN_SUCCESSFUL
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h
index fdaccf7a..53c695f 100644
--- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h
+++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h
@@ -38,6 +38,7 @@
   bool IsSearchResultsPage() const override;
   bool IsNewTabPage(const GURL& url) const override;
   bool IsHomePage(const GURL& url) const override;
+  bool IsDefaultSearchProviderEnabled() const override;
   const SessionID& GetSessionID() const override;
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   TemplateURLService* GetTemplateURLService() override;
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
index e63c60f..90328250 100644
--- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
@@ -98,6 +98,11 @@
   return false;
 }
 
+bool ChromeOmniboxClientIOS::IsDefaultSearchProviderEnabled() const {
+  // iOS does not have Enterprise policies
+  return true;
+}
+
 const SessionID& ChromeOmniboxClientIOS::GetSessionID() const {
   return IOSChromeSessionTabHelper::FromWebState(controller_->GetWebState())
       ->session_id();
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index 270d052..4f3ea8a7 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -707,6 +707,14 @@
     return YES;
   }
 
+  // Allow key commands to be recognized.
+  if (action == @selector(keyCommandUp) ||
+      action == @selector(keyCommandDown) ||
+      action == @selector(keyCommandLeft) ||
+      action == @selector(keyCommandRight)) {
+    return YES;
+  }
+
   // Note that this NO does not keep other elements in the responder chain from
   // adding actions they handle to the menu.
   // No special handling is necessary for pre-edit and autocomplete states.
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
index 628caac3..49c1dc6 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.h"
 
+#include "base/ios/ios_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
@@ -138,6 +139,15 @@
       initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width,
                                0.01f)];
 
+  if (!base::ios::IsRunningOnIOS11OrLater()) {
+    // On iOS 10, a footer with a height of 0 is also needed to prevent inset at
+    // the bottom.
+    self.tableView.tableFooterView = [[UIView alloc]
+        initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width,
+                                 0.01f)];
+    self.tableView.sectionFooterHeight = 0.0;
+  }
+
   self.view.layer.cornerRadius = kPopupMenuCornerRadius;
   self.view.layer.masksToBounds = YES;
 }
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 2ec37d6..377e54e 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -46,6 +46,7 @@
     "google_services_settings_consumer.h",
     "google_services_settings_coordinator.h",
     "google_services_settings_coordinator.mm",
+    "google_services_settings_local_commands.h",
     "google_services_settings_mediator.h",
     "google_services_settings_mediator.mm",
     "google_services_settings_view_controller.h",
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_command_handler.h b/ios/chrome/browser/ui/settings/google_services_settings_command_handler.h
index 82cd17d7e..f3a0032f 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_command_handler.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_command_handler.h
@@ -11,8 +11,18 @@
   GoogleServicesSettingsCommandIDNoOp,
   // Enabble/disable all the Google services.
   GoogleServicesSettingsCommandIDToggleSyncEverything,
+
+  // Personalized section.
   // Enable/disabble bookmark sync.
   GoogleServicesSettingsCommandIDToggleDataTypeSync,
+  // Opens the Google activity controls dialog.
+  GoogleServicesSettingsCommandIDOpenGoogleActivityControlsDialog,
+  // Opens the encryption dialog.
+  GoogleServicesSettingsCommandIDOpenEncryptionDialog,
+  // Opens manage synced data web page.
+  GoogleServicesSettingsCommandIDOpenManageSyncedDataWebPage,
+
+  // Non-personalized section.
   // Enable/disabble autocomplete searches service.
   GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService,
   // Enable/disabble preload pages service.
@@ -21,41 +31,32 @@
   GoogleServicesSettingsCommandIDToggleImproveChromeService,
   // Enable/disabble better search and browsing service.
   GoogleServicesSettingsCommandIDToggleBetterSearchAndBrowsingService,
-  // Opens the Google activity controls dialog.
-  GoogleServicesSettingsCommandIDOpenGoogleActivityPage,
-  // Opens the encryption dialog.
-  GoogleServicesSettingsCommandIDOpenEncryptionDialog,
-  // Opens manage synced data page.
-  GoogleServicesSettingsCommandIDOpenManageSyncedDataPage,
 };
 
 // Protocol to handle Google services settings commands.
 @protocol GoogleServicesSettingsCommandHandler<NSObject>
 
 // Called when GoogleServicesSettingsCommandIDToggleSyncEverything is triggered.
-- (void)toggleSyncEverythingWithValue:(BOOL)on;
+- (void)toggleSyncEverythingWithValue:(BOOL)value;
+
+// Personalized section.
 // Called when GoogleServicesSettingsCommandIDToggleDataTypeSync is triggered.
-- (void)toggleSyncDataSync:(NSInteger)dataType WithValue:(BOOL)on;
-- (void)toggleAutocompleteSearchesServiceWithValue:(BOOL)on;
+- (void)toggleSyncDataSync:(NSInteger)dataType withValue:(BOOL)value;
+
+// Non-personalized section.
+// Called when GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService
+// is triggered.
+- (void)toggleAutocompleteSearchesServiceWithValue:(BOOL)value;
 // Called when GoogleServicesSettingsCommandIDTogglePreloadPagesService is
 // triggered.
-- (void)togglePreloadPagesServiceWithValue:(BOOL)on;
+- (void)togglePreloadPagesServiceWithValue:(BOOL)value;
 // Called when GoogleServicesSettingsCommandIDToggleImproveChromeService is
 // triggered.
-- (void)toggleImproveChromeServiceWithValue:(BOOL)on;
+- (void)toggleImproveChromeServiceWithValue:(BOOL)value;
 // Called when
 // GoogleServicesSettingsCommandIDToggleBetterSearchAndBrowsingService is
 // triggered.
-- (void)toggleBetterSearchAndBrowsingServiceWithValue:(BOOL)on;
-// Called when GoogleServicesSettingsCommandIDOpenGoogleActivityPage is
-// triggered.
-- (void)openGoogleActivityPage;
-// Called when GoogleServicesSettingsCommandIDOpenEncryptionDialog is
-// triggered.
-- (void)openEncryptionDialog;
-// Called when GoogleServicesSettingsCommandIDOpenManageSyncedDataPage is
-// triggered.
-- (void)openManageSyncedDataPage;
+- (void)toggleBetterSearchAndBrowsingServiceWithValue:(BOOL)value;
 
 @end
 
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_coordinator.h b/ios/chrome/browser/ui/settings/google_services_settings_coordinator.h
index a978581..0eed524 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_coordinator.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_coordinator.h
@@ -7,6 +7,7 @@
 
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 
+@protocol ApplicationCommands;
 @class GoogleServicesSettingsCoordinator;
 
 // Delegate for GoogleServicesSettingsCoordinator.
@@ -23,10 +24,11 @@
 
 // View controller for the Google services settings.
 @property(nonatomic, strong) UIViewController* viewController;
-
 // Delegate.
 @property(nonatomic, weak) id<GoogleServicesSettingsCoordinatorDelegate>
     delegate;
+// Global dispatcher.
+@property(nonatomic, weak) id<ApplicationCommands> dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm
index 6854e15..d3f107c 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_coordinator.mm
@@ -4,10 +4,16 @@
 
 #import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h"
 
+#include "components/google/core/common/google_util.h"
+#include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.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"
+#import "ios/chrome/browser/ui/settings/google_services_settings_local_commands.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_mediator.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
 
@@ -16,6 +22,7 @@
 #endif
 
 @interface GoogleServicesSettingsCoordinator ()<
+    GoogleServicesSettingsLocalCommands,
     GoogleServicesSettingsViewControllerPresentationDelegate>
 
 // Google services settings mediator.
@@ -25,8 +32,9 @@
 
 @implementation GoogleServicesSettingsCoordinator
 
-@synthesize delegate = _delegate;
 @synthesize viewController = _viewController;
+@synthesize delegate = _delegate;
+@synthesize dispatcher = _dispatcher;
 @synthesize mediator = _mediator;
 
 - (void)start {
@@ -36,6 +44,7 @@
           initWithLayout:layout
                    style:CollectionViewControllerStyleAppBar];
   controller.presentationDelegate = self;
+  controller.localDispatcher = self;
   self.viewController = controller;
   SyncSetupService* syncSetupService =
       SyncSetupServiceFactory::GetForBrowserState(self.browserState);
@@ -55,6 +64,25 @@
                                        animated:YES];
 }
 
+#pragma mark - GoogleServicesSettingsLocalCommands
+
+- (void)openGoogleActivityControlsDialog {
+  // Needs to be implemented.
+}
+
+- (void)openEncryptionDialog {
+  // Needs to be implemented.
+}
+
+- (void)openManageSyncedDataWebPage {
+  GURL learnMoreUrl = google_util::AppendGoogleLocaleParam(
+      GURL(kSyncGoogleDashboardURL),
+      GetApplicationContext()->GetApplicationLocale());
+  OpenNewTabCommand* command =
+      [OpenNewTabCommand commandWithURLFromChrome:learnMoreUrl];
+  [self.dispatcher closeSettingsUIAndOpenURL:command];
+}
+
 #pragma mark - GoogleServicesSettingsViewControllerPresentationDelegate
 
 - (void)googleServicesSettingsViewControllerDidRemove:
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm b/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm
index 9ce10ea..cfd671dd 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_egtest.mm
@@ -135,6 +135,38 @@
   [self assertNonPersonalizedServicesCollapsed:NO];
 }
 
+// Tests the "Manage synced data" cell does nothing when the user is not signed
+// in.
+- (void)testOpenManageSyncedDataWebPage {
+  if (!IsUIRefreshPhase1Enabled())
+    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
+  PrefService* prefService = GetOriginalBrowserState()->GetPrefs();
+  prefService->SetBoolean(kUnifiedConsentGiven, false);
+  [self openGoogleServicesSettings];
+  [self togglePersonalizedServicesSection];
+  [[self cellElementInteractionWithTitleID:
+             IDS_IOS_GOOGLE_SERVICES_SETTINGS_MANAGED_SYNC_DATA_TEXT
+                              detailTextID:0] performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:self.scrollViewMatcher]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests the "Manage synced data" cell closes the settings, to open the web
+// page.
+- (void)testOpenManageSyncedDataWebPageWhileSignedIn {
+  if (!IsUIRefreshPhase1Enabled())
+    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
+  PrefService* prefService = GetOriginalBrowserState()->GetPrefs();
+  prefService->SetBoolean(kUnifiedConsentGiven, false);
+  [SigninEarlGreyUI signinWithIdentity:[SigninEarlGreyUtils fakeIdentity1]];
+  [self openGoogleServicesSettings];
+  [[self cellElementInteractionWithTitleID:
+             IDS_IOS_GOOGLE_SERVICES_SETTINGS_MANAGED_SYNC_DATA_TEXT
+                              detailTextID:0] performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:self.scrollViewMatcher]
+      assertWithMatcher:grey_nil()];
+}
+
 #pragma mark - Helpers
 
 - (void)openGoogleServicesSettings {
@@ -162,21 +194,31 @@
       performAction:grey_tap()];
 }
 
-- (void)assertCellWithTitleID:(int)titleID detailTextID:(int)detailTextID {
+// Returns GREYElementInteraction for a cell based on the title string ID and
+// the detail text string ID. |detailTextID| should be set to 0 if it doesn't
+// exist in the cell.
+- (GREYElementInteraction*)cellElementInteractionWithTitleID:(int)titleID
+                                                detailTextID:(int)detailTextID {
   NSString* accessibilityLabel = GetNSString(titleID);
   if (detailTextID) {
     accessibilityLabel =
         [NSString stringWithFormat:@"%@, %@", accessibilityLabel,
                                    GetNSString(detailTextID)];
   }
-  [[[EarlGrey
+  return [[EarlGrey
       selectElementWithMatcher:grey_allOf(
                                    grey_accessibilityLabel(accessibilityLabel),
                                    grey_kindOfClass(
                                        [UICollectionViewCell class]),
                                    grey_sufficientlyVisible(), nil)]
-         usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
-      onElementWithMatcher:self.scrollViewMatcher]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 150)
+      onElementWithMatcher:self.scrollViewMatcher];
+}
+
+// Asserts that a cell exists, based on its title string ID and its detail text
+// string ID. |detailTextID| should be set to 0 if it doesn't exist in the cell.
+- (void)assertCellWithTitleID:(int)titleID detailTextID:(int)detailTextID {
+  [[self cellElementInteractionWithTitleID:titleID detailTextID:detailTextID]
       assertWithMatcher:grey_notNil()];
 }
 
@@ -202,6 +244,8 @@
                    detailTextID:0];
     [self assertCellWithTitleID:IDS_IOS_GOOGLE_SERVICES_SETTINGS_AUTOFILL_TEXT
                    detailTextID:0];
+    [self assertCellWithTitleID:IDS_IOS_GOOGLE_SERVICES_SETTINGS_SETTINGS_TEXT
+                   detailTextID:0];
     [self
         assertCellWithTitleID:IDS_IOS_GOOGLE_SERVICES_SETTINGS_READING_LIST_TEXT
                  detailTextID:0];
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_local_commands.h b/ios/chrome/browser/ui/settings/google_services_settings_local_commands.h
new file mode 100644
index 0000000..a42935d
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/google_services_settings_local_commands.h
@@ -0,0 +1,20 @@
+// 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_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_LOCAL_COMMANDS_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_LOCAL_COMMANDS_H_
+
+// Protocol to communicate GoogleServicesSettingsVC actions to its coordinator.
+@protocol GoogleServicesSettingsLocalCommands<NSObject>
+
+// Called when the "Google Activity Controls" dialog should be opened.
+- (void)openGoogleActivityControlsDialog;
+// Called when the "Encryption" dialog should be opened.
+- (void)openEncryptionDialog;
+// Called when the "Manage Synced Data" web page should be opened.
+- (void)openManageSyncedDataWebPage;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_LOCAL_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.h b/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
index 9419f3bc..1703b34 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.h
@@ -26,6 +26,11 @@
     : NSObject<GoogleServicesSettingsCommandHandler,
                GoogleServicesSettingsViewControllerModelDelegate>
 
+// View controller.
+@property(nonatomic, weak) id<GoogleServicesSettingsConsumer> consumer;
+// Authentication service.
+@property(nonatomic, assign) AuthenticationService* authService;
+
 // Designated initializer. |prefService|, |syncService| and |syncSetupService|
 // should not be null.
 - (instancetype)initWithPrefService:(PrefService*)prefService
@@ -36,11 +41,6 @@
 
 - (instancetype)init NS_UNAVAILABLE;
 
-// View controller.
-@property(nonatomic, weak) id<GoogleServicesSettingsConsumer> consumer;
-// Authentication service.
-@property(nonatomic, assign) AuthenticationService* authService;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_GOOGLE_SERVICES_SETTINGS_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
index f290ba5..8c876f6e 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_mediator.mm
@@ -267,6 +267,12 @@
                 detailStringID:0
                      commandID:GoogleServicesSettingsCommandIDToggleDataTypeSync
                       dataType:SyncSetupService::kSyncAutofill];
+    SyncSwitchItem* syncSettingsItem = [self
+        switchItemWithItemType:SyncAutofillItemType
+                  textStringID:IDS_IOS_GOOGLE_SERVICES_SETTINGS_SETTINGS_TEXT
+                detailStringID:0
+                     commandID:GoogleServicesSettingsCommandIDToggleDataTypeSync
+                      dataType:SyncSetupService::kSyncPreferences];
     SyncSwitchItem* syncReadingListItem = [self
         switchItemWithItemType:SyncReadingListItemType
                   textStringID:
@@ -290,7 +296,7 @@
                   IDS_IOS_GOOGLE_SERVICES_SETTINGS_GOOGLE_ACTIVITY_CONTROL_DETAIL
                accessoryType:MDCCollectionViewCellAccessoryDisclosureIndicator
                    commandID:
-                       GoogleServicesSettingsCommandIDOpenGoogleActivityPage];
+                       GoogleServicesSettingsCommandIDOpenGoogleActivityControlsDialog];
     CollectionViewTextItem* encryptionItem = [self
         textItemWithItemType:EncryptionItemType
                 textStringID:IDS_IOS_GOOGLE_SERVICES_SETTINGS_ENCRYPTION_TEXT
@@ -305,11 +311,12 @@
               detailStringID:0
                accessoryType:MDCCollectionViewCellAccessoryNone
                    commandID:
-                       GoogleServicesSettingsCommandIDOpenManageSyncedDataPage];
+                       GoogleServicesSettingsCommandIDOpenManageSyncedDataWebPage];
     _personalizedItems = @[
       syncBookmarksItem, syncHistoryItem, syncPasswordsItem, syncOpenTabsItem,
-      syncAutofillItem, syncReadingListItem, syncActivityAndInteractionsItem,
-      syncGoogleActivityControlsItem, encryptionItem, manageSyncedDataItem
+      syncAutofillItem, syncSettingsItem, syncReadingListItem,
+      syncActivityAndInteractionsItem, syncGoogleActivityControlsItem,
+      encryptionItem, manageSyncedDataItem
     ];
   }
   return _personalizedItems;
@@ -469,7 +476,7 @@
     } else if ([item isKindOfClass:[CollectionViewTextItem class]]) {
       CollectionViewTextItem* textItem =
           base::mac::ObjCCast<CollectionViewTextItem>(item);
-      textItem.textColor = textColor;
+      textItem.enabled = enabled;
     } else {
       NOTREACHED();
     }
@@ -499,39 +506,27 @@
   self.prefService->SetBoolean(kUnifiedConsentGiven, value);
 }
 
-- (void)toggleSyncDataSync:(NSInteger)dataTypeInt WithValue:(BOOL)on {
+- (void)toggleSyncDataSync:(NSInteger)dataTypeInt withValue:(BOOL)value {
   base::AutoReset<BOOL> autoReset(&_personalizedSectionBeingAnimated, YES);
   SyncSetupService::SyncableDatatype dataType =
       static_cast<SyncSetupService::SyncableDatatype>(dataTypeInt);
   syncer::ModelType modelType = self.syncSetupService->GetModelType(dataType);
-  self.syncSetupService->SetDataTypeEnabled(modelType, on);
+  self.syncSetupService->SetDataTypeEnabled(modelType, value);
 }
 
-- (void)toggleAutocompleteSearchesServiceWithValue:(BOOL)on {
+- (void)toggleAutocompleteSearchesServiceWithValue:(BOOL)value {
   // Needs to be implemented.
 }
 
-- (void)togglePreloadPagesServiceWithValue:(BOOL)on {
+- (void)togglePreloadPagesServiceWithValue:(BOOL)value {
   // Needs to be implemented.
 }
 
-- (void)toggleImproveChromeServiceWithValue:(BOOL)on {
+- (void)toggleImproveChromeServiceWithValue:(BOOL)value {
   // Needs to be implemented.
 }
 
-- (void)toggleBetterSearchAndBrowsingServiceWithValue:(BOOL)on {
-  // Needs to be implemented.
-}
-
-- (void)openGoogleActivityPage {
-  // Needs to be implemented.
-}
-
-- (void)openEncryptionDialog {
-  // Needs to be implemented.
-}
-
-- (void)openManageSyncedDataPage {
+- (void)toggleBetterSearchAndBrowsingServiceWithValue:(BOOL)value {
   // Needs to be implemented.
 }
 
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h
index 0b86104..22b1f69 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h
+++ b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.h
@@ -11,6 +11,7 @@
 
 @class GoogleServicesSettingsViewController;
 @protocol GoogleServicesSettingsCommandHandler;
+@protocol GoogleServicesSettingsLocalCommands;
 @protocol GoogleServicesSettingsViewControllerModelDelegate;
 
 // Delegate for presentation events related to
@@ -34,10 +35,12 @@
 // Model delegate.
 @property(nonatomic, weak) id<GoogleServicesSettingsViewControllerModelDelegate>
     modelDelegate;
-
 // Handler for GoogleServicesSettingsCommand.
 @property(nonatomic, weak) id<GoogleServicesSettingsCommandHandler>
     commandHandler;
+// Local command dispatcher.
+@property(nonatomic, weak) id<GoogleServicesSettingsLocalCommands>
+    localDispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
index 6ead0dd..b386b175 100644
--- a/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/google_services_settings_view_controller.mm
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/ui/settings/cells/settings_collapsible_item.h"
 #import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_command_handler.h"
+#import "ios/chrome/browser/ui/settings/google_services_settings_local_commands.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller_model_delegate.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -32,6 +33,7 @@
 @synthesize presentationDelegate = _presentationDelegate;
 @synthesize modelDelegate = _modelDelegate;
 @synthesize commandHandler = _commandHandler;
+@synthesize localDispatcher = _localDispatcher;
 
 - (instancetype)initWithLayout:(UICollectionViewLayout*)layout
                          style:(CollectionViewControllerStyle)style {
@@ -101,18 +103,12 @@
   GoogleServicesSettingsCommandID commandID =
       static_cast<GoogleServicesSettingsCommandID>(syncSwitchItem.commandID);
   switch (commandID) {
-    case GoogleServicesSettingsCommandIDNoOp:
-    case GoogleServicesSettingsCommandIDOpenGoogleActivityPage:
-    case GoogleServicesSettingsCommandIDOpenEncryptionDialog:
-    case GoogleServicesSettingsCommandIDOpenManageSyncedDataPage:
-      NOTREACHED();
-      break;
     case GoogleServicesSettingsCommandIDToggleSyncEverything:
       [self.commandHandler toggleSyncEverythingWithValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDToggleDataTypeSync:
       [self.commandHandler toggleSyncDataSync:syncSwitchItem.dataType
-                                    WithValue:isOn];
+                                    withValue:isOn];
       break;
     case GoogleServicesSettingsCommandIDToggleAutocompleteSearchesService:
       [self.commandHandler toggleAutocompleteSearchesServiceWithValue:isOn];
@@ -126,6 +122,12 @@
     case GoogleServicesSettingsCommandIDToggleBetterSearchAndBrowsingService:
       [self.commandHandler toggleBetterSearchAndBrowsingServiceWithValue:isOn];
       break;
+    case GoogleServicesSettingsCommandIDNoOp:
+    case GoogleServicesSettingsCommandIDOpenGoogleActivityControlsDialog:
+    case GoogleServicesSettingsCommandIDOpenEncryptionDialog:
+    case GoogleServicesSettingsCommandIDOpenManageSyncedDataWebPage:
+      NOTREACHED();
+      break;
   }
 }
 
@@ -201,7 +203,7 @@
   } else if ([item isKindOfClass:[CollectionViewTextItem class]]) {
     CollectionViewTextItem* textItem =
         base::mac::ObjCCast<CollectionViewTextItem>(item);
-    return textItem.commandID != 0;
+    return textItem.enabled;
   }
   return NO;
 }
@@ -221,14 +223,14 @@
   GoogleServicesSettingsCommandID commandID =
       static_cast<GoogleServicesSettingsCommandID>(textItem.commandID);
   switch (commandID) {
-    case GoogleServicesSettingsCommandIDOpenGoogleActivityPage:
-      [self.commandHandler openGoogleActivityPage];
+    case GoogleServicesSettingsCommandIDOpenGoogleActivityControlsDialog:
+      [self.localDispatcher openGoogleActivityControlsDialog];
       break;
     case GoogleServicesSettingsCommandIDOpenEncryptionDialog:
-      [self.commandHandler openEncryptionDialog];
+      [self.localDispatcher openEncryptionDialog];
       break;
-    case GoogleServicesSettingsCommandIDOpenManageSyncedDataPage:
-      [self.commandHandler openManageSyncedDataPage];
+    case GoogleServicesSettingsCommandIDOpenManageSyncedDataWebPage:
+      [self.localDispatcher openManageSyncedDataWebPage];
       break;
     case GoogleServicesSettingsCommandIDNoOp:
     case GoogleServicesSettingsCommandIDToggleSyncEverything:
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
index 144ca95..0ed4daf 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -1007,6 +1007,7 @@
       [[GoogleServicesSettingsCoordinator alloc]
           initWithBaseViewController:self.navigationController
                         browserState:_browserState];
+  _googleServicesSettingsCoordinator.dispatcher = self.dispatcher;
   _googleServicesSettingsCoordinator.navigationController =
       self.navigationController;
   _googleServicesSettingsCoordinator.delegate = self;
diff --git a/ios/chrome/browser/web_data_service_factory.cc b/ios/chrome/browser/web_data_service_factory.cc
index 8a79b56..1b8d2ef 100644
--- a/ios/chrome/browser/web_data_service_factory.cc
+++ b/ios/chrome/browser/web_data_service_factory.cc
@@ -53,6 +53,16 @@
 }
 
 // static
+scoped_refptr<autofill::AutofillWebDataService>
+WebDataServiceFactory::GetAutofillWebDataForAccount(
+    ios::ChromeBrowserState* browser_state,
+    ServiceAccessType access_type) {
+  WebDataServiceWrapper* wrapper =
+      GetForBrowserState(browser_state, access_type);
+  return wrapper ? wrapper->GetAccountAutofillWebData() : nullptr;
+}
+
+// static
 scoped_refptr<KeywordWebDataService>
 WebDataServiceFactory::GetKeywordWebDataForBrowserState(
     ios::ChromeBrowserState* browser_state,
diff --git a/ios/chrome/browser/web_data_service_factory.h b/ios/chrome/browser/web_data_service_factory.h
index 99801be..0911605e 100644
--- a/ios/chrome/browser/web_data_service_factory.h
+++ b/ios/chrome/browser/web_data_service_factory.h
@@ -46,6 +46,12 @@
   GetAutofillWebDataForBrowserState(ios::ChromeBrowserState* browser_state,
                                     ServiceAccessType access_type);
 
+  // Returns the account-scoped AutofillWebDataService associated with the
+  // |browser_state|.
+  static scoped_refptr<autofill::AutofillWebDataService>
+  GetAutofillWebDataForAccount(ios::ChromeBrowserState* browser_state,
+                               ServiceAccessType access_type);
+
   // Returns the KeywordWebDataService associated with |browser_state|.
   static scoped_refptr<KeywordWebDataService> GetKeywordWebDataForBrowserState(
       ios::ChromeBrowserState* browser_state,
diff --git a/media/capture/mojom/video_capture_types.mojom b/media/capture/mojom/video_capture_types.mojom
index b59c87a..a0d5b030 100644
--- a/media/capture/mojom/video_capture_types.mojom
+++ b/media/capture/mojom/video_capture_types.mojom
@@ -5,6 +5,7 @@
 module media.mojom;
 
 import "gpu/ipc/common/mailbox_holder.mojom";
+import "mojo/public/mojom/base/shared_memory.mojom";
 import "mojo/public/mojom/base/time.mojom";
 import "mojo/public/mojom/base/values.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
@@ -144,6 +145,7 @@
 
 union VideoBufferHandle {
   handle<shared_buffer> shared_buffer_handle;
+  mojo_base.mojom.ReadOnlySharedMemoryRegion read_only_shmem_region;
   SharedMemoryViaRawFileDescriptor shared_memory_via_raw_file_descriptor;
   MailboxBufferHandleSet mailbox_handles;
 };
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index d6ea52d..83412296 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -366,6 +366,7 @@
       "//base",
       "//base/test:test_support",
       "//media:test_support",
+      "//mojo/core/embedder",
       "//testing/gtest",
       "//ui/base",
       "//ui/display/manager",
@@ -474,6 +475,7 @@
       "//base/test:test_support",
       "//media:test_support",
       "//media/gpu",
+      "//mojo/core/embedder",
       "//testing/gtest",
       "//ui/base",
       "//ui/gfx",
@@ -503,6 +505,7 @@
       "//base/test:test_support",
       "//media:test_support",
       "//media/gpu",
+      "//mojo/core/embedder",
       "//testing/gtest",
       "//third_party:jpeg",
       "//third_party/libyuv",
@@ -534,6 +537,7 @@
       "//media:test_support",
       "//media/gpu",
       "//media/mojo/services",
+      "//mojo/core/embedder",
       "//testing/gtest",
       "//third_party/libyuv",
       "//ui/base",
diff --git a/media/gpu/jpeg_decode_accelerator_unittest.cc b/media/gpu/jpeg_decode_accelerator_unittest.cc
index 13ed807..74d4a259 100644
--- a/media/gpu/jpeg_decode_accelerator_unittest.cc
+++ b/media/gpu/jpeg_decode_accelerator_unittest.cc
@@ -31,6 +31,7 @@
 #include "media/gpu/gpu_jpeg_decode_accelerator_factory.h"
 #include "media/gpu/test/video_accelerator_unittest_helpers.h"
 #include "media/video/jpeg_decode_accelerator.h"
+#include "mojo/core/embedder/embedder.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -842,6 +843,7 @@
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   base::CommandLine::Init(argc, argv);
+  mojo::core::Init();
   base::ShadowingAtExitManager at_exit_manager;
 
   // Needed to enable DVLOG through --vmodule.
diff --git a/media/gpu/jpeg_encode_accelerator_unittest.cc b/media/gpu/jpeg_encode_accelerator_unittest.cc
index 3485fb1b..ce20d60 100644
--- a/media/gpu/jpeg_encode_accelerator_unittest.cc
+++ b/media/gpu/jpeg_encode_accelerator_unittest.cc
@@ -33,6 +33,7 @@
 #include "media/gpu/test/video_accelerator_unittest_helpers.h"
 #include "media/gpu/vaapi/vaapi_jpeg_encode_accelerator.h"
 #include "media/video/jpeg_encode_accelerator.h"
+#include "mojo/core/embedder/embedder.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 
@@ -635,6 +636,7 @@
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   base::CommandLine::Init(argc, argv);
+  mojo::core::Init();
   base::ShadowingAtExitManager at_exit_manager;
 
   // Needed to enable DVLOG through --vmodule.
diff --git a/media/gpu/vaapi/BUILD.gn b/media/gpu/vaapi/BUILD.gn
index d69ad3b..66473a4 100644
--- a/media/gpu/vaapi/BUILD.gn
+++ b/media/gpu/vaapi/BUILD.gn
@@ -140,6 +140,7 @@
     "//base/test:test_support",
     "//gpu:test_support",
     "//media/gpu:common",
+    "//mojo/core/embedder",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/gfx:test_support",
diff --git a/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc b/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
index 35b7389..bf858919 100644
--- a/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
+++ b/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
@@ -22,6 +22,7 @@
 #include "media/base/video_frame.h"
 #include "media/filters/jpeg_parser.h"
 #include "media/gpu/vaapi/vaapi_jpeg_decoder.h"
+#include "mojo/core/embedder/embedder.h"
 
 namespace media {
 namespace {
@@ -132,6 +133,7 @@
 }  // namespace media
 
 int main(int argc, char** argv) {
+  mojo::core::Init();
   testing::InitGoogleTest(&argc, argv);
   base::AtExitManager exit_manager;
   media::VaapiWrapper::PreSandboxInitialization();
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 5705bfa..988561a4 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -1573,8 +1573,6 @@
 
   int Run() {
 #if defined(OS_WIN) || defined(OS_CHROMEOS)
-    mojo::core::Init();  // Required only for Win7 tests.
-
     // For windows the decoding thread initializes the media foundation decoder
     // which uses COM. We need the thread to be a UI thread.
     // On Ozone, the backend initializes the event system using a UI
@@ -1610,6 +1608,7 @@
 }  // namespace media
 
 int main(int argc, char** argv) {
+  mojo::core::Init();
   media::VDATestSuite test_suite(argc, argv);
 
   // Needed to enable DVLOG through --vmodule.
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 27ef976a..28b8e99 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -58,6 +58,7 @@
 #include "media/video/fake_video_encode_accelerator.h"
 #include "media/video/h264_parser.h"
 #include "media/video/video_encode_accelerator.h"
+#include "mojo/core/embedder/embedder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(USE_VAAPI)
@@ -2587,6 +2588,7 @@
 }  // namespace media
 
 int main(int argc, char** argv) {
+  mojo::core::Init();
   media::VEATestSuite test_suite(argc, argv);
 
   base::ShadowingAtExitManager at_exit_manager;
diff --git a/net/base/elements_upload_data_stream_unittest.cc b/net/base/elements_upload_data_stream_unittest.cc
index 92ff1c6..2b9b190d 100644
--- a/net/base/elements_upload_data_stream_unittest.cc
+++ b/net/base/elements_upload_data_stream_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/strings/string_piece.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -165,7 +166,8 @@
 TEST_F(ElementsUploadDataStreamTest, EmptyUploadData) {
   std::unique_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
-  ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(stream->Init(CompletionOnceCallback(), NetLogWithSource()),
+              IsOk());
   EXPECT_TRUE(stream->IsInMemory());
   EXPECT_EQ(0U, stream->size());
   EXPECT_EQ(0U, stream->position());
@@ -177,7 +179,8 @@
       std::make_unique<UploadBytesElementReader>(kTestData, kTestDataSize));
   std::unique_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
-  ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(stream->Init(CompletionOnceCallback(), NetLogWithSource()),
+              IsOk());
   EXPECT_TRUE(stream->IsInMemory());
   EXPECT_EQ(kTestDataSize, stream->size());
   EXPECT_EQ(0U, stream->position());
@@ -185,7 +188,7 @@
   scoped_refptr<IOBuffer> buf = new IOBuffer(kTestBufferSize);
   while (!stream->IsEOF()) {
     int bytes_read =
-        stream->Read(buf.get(), kTestBufferSize, CompletionCallback());
+        stream->Read(buf.get(), kTestBufferSize, CompletionOnceCallback());
     ASSERT_LE(0, bytes_read);  // Not an error.
   }
   EXPECT_EQ(kTestDataSize, stream->position());
@@ -285,7 +288,8 @@
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
   // Run Init().
-  ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(stream->Init(CompletionOnceCallback(), NetLogWithSource()),
+              IsOk());
   EXPECT_EQ(kTestDataSize * 2, stream->size());
   EXPECT_EQ(0U, stream->position());
   EXPECT_FALSE(stream->IsEOF());
@@ -296,7 +300,7 @@
 
   // Read() results in success even when the reader returns error.
   EXPECT_EQ(ERR_FAILED,
-            stream->Read(buf.get(), kTestBufferSize, CompletionCallback()));
+            stream->Read(buf.get(), kTestBufferSize, CompletionOnceCallback()));
   EXPECT_EQ(0U, stream->position());
   EXPECT_FALSE(stream->IsEOF());
 
@@ -470,13 +474,15 @@
   std::unique_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(std::move(element_readers_), 0));
 
-  ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(stream->Init(CompletionOnceCallback(), NetLogWithSource()),
+              IsOk());
   EXPECT_TRUE(stream->IsInMemory());
   EXPECT_EQ(kTestDataSize, stream->size());
   EXPECT_EQ(0U, stream->position());
   EXPECT_FALSE(stream->IsEOF());
   scoped_refptr<IOBuffer> buf = new IOBuffer(kTestDataSize);
-  int bytes_read = stream->Read(buf.get(), kTestDataSize, CompletionCallback());
+  int bytes_read =
+      stream->Read(buf.get(), kTestDataSize, CompletionOnceCallback());
   ASSERT_EQ(static_cast<int>(kTestDataSize), bytes_read);  // Not an error.
   EXPECT_EQ(kTestDataSize, stream->position());
   ASSERT_TRUE(stream->IsEOF());
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc
index 1e760d3..6a4ce587 100644
--- a/net/base/network_change_notifier_fuchsia_unittest.cc
+++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -121,13 +121,6 @@
   fidl::Binding<fuchsia::netstack::Netstack>& binding() { return binding_; }
 
  private:
-  // fuchsia::netstack::Netstack implementation.
-  void RegisterListener(
-      ::fidl::InterfaceHandle<fuchsia::netstack::NotificationListener> listener)
-      override {
-    NOTREACHED();
-  }
-
   void GetInterfaces(GetInterfacesCallback callback) override {
     callback(std::move(interfaces_));
   }
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index e694620..2fecd7f 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -28,6 +28,7 @@
 #include "base/trace_event/trace_event_argument.h"
 #include "build/build_config.h"
 #include "net/base/cache_type.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/request_priority.h"
@@ -3389,7 +3390,7 @@
   // Writing this sparse data should not crash. Ignoring the result because
   // we're only concerned with not crashing in this particular test.
   first_parent->WriteSparseData(32768, buffer.get(), 1024,
-                                net::CompletionCallback());
+                                net::CompletionOnceCallback());
 }
 
 TEST_F(DiskCacheBackendTest, MemoryCapsWritesToMaxSize) {
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 3fd25fa..cdd90e0c 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -18,7 +18,7 @@
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/platform_thread.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/request_priority.h"
@@ -91,17 +91,14 @@
   const int kSize1 = 10;
   scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1));
   CacheTestFillBuffer(buffer1->data(), kSize1, false);
-  EXPECT_EQ(
-      0,
-      entry->ReadData(0, 0, buffer1.get(), kSize1, net::CompletionCallback()));
+  EXPECT_EQ(0, entry->ReadData(0, 0, buffer1.get(), kSize1,
+                               net::CompletionOnceCallback()));
   base::strlcpy(buffer1->data(), "the data", kSize1);
-  EXPECT_EQ(10,
-            entry->WriteData(
-                0, 0, buffer1.get(), kSize1, net::CompletionCallback(), false));
+  EXPECT_EQ(10, entry->WriteData(0, 0, buffer1.get(), kSize1,
+                                 net::CompletionOnceCallback(), false));
   memset(buffer1->data(), 0, kSize1);
-  EXPECT_EQ(
-      10,
-      entry->ReadData(0, 0, buffer1.get(), kSize1, net::CompletionCallback()));
+  EXPECT_EQ(10, entry->ReadData(0, 0, buffer1.get(), kSize1,
+                                net::CompletionOnceCallback()));
   EXPECT_STREQ("the data", buffer1->data());
 
   const int kSize2 = 5000;
@@ -111,42 +108,33 @@
   memset(buffer3->data(), 0, kSize3);
   CacheTestFillBuffer(buffer2->data(), kSize2, false);
   base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
-  EXPECT_EQ(
-      5000,
-      entry->WriteData(
-          1, 1500, buffer2.get(), kSize2, net::CompletionCallback(), false));
+  EXPECT_EQ(5000, entry->WriteData(1, 1500, buffer2.get(), kSize2,
+                                   net::CompletionOnceCallback(), false));
   memset(buffer2->data(), 0, kSize2);
-  EXPECT_EQ(4989,
-            entry->ReadData(
-                1, 1511, buffer2.get(), kSize2, net::CompletionCallback()));
+  EXPECT_EQ(4989, entry->ReadData(1, 1511, buffer2.get(), kSize2,
+                                  net::CompletionOnceCallback()));
   EXPECT_STREQ("big data goes here", buffer2->data());
-  EXPECT_EQ(
-      5000,
-      entry->ReadData(1, 0, buffer2.get(), kSize2, net::CompletionCallback()));
+  EXPECT_EQ(5000, entry->ReadData(1, 0, buffer2.get(), kSize2,
+                                  net::CompletionOnceCallback()));
   EXPECT_EQ(0, memcmp(buffer2->data(), buffer3->data(), 1500));
-  EXPECT_EQ(1500,
-            entry->ReadData(
-                1, 5000, buffer2.get(), kSize2, net::CompletionCallback()));
+  EXPECT_EQ(1500, entry->ReadData(1, 5000, buffer2.get(), kSize2,
+                                  net::CompletionOnceCallback()));
 
-  EXPECT_EQ(0,
-            entry->ReadData(
-                1, 6500, buffer2.get(), kSize2, net::CompletionCallback()));
-  EXPECT_EQ(
-      6500,
-      entry->ReadData(1, 0, buffer3.get(), kSize3, net::CompletionCallback()));
-  EXPECT_EQ(8192,
-            entry->WriteData(
-                1, 0, buffer3.get(), 8192, net::CompletionCallback(), false));
-  EXPECT_EQ(
-      8192,
-      entry->ReadData(1, 0, buffer3.get(), kSize3, net::CompletionCallback()));
+  EXPECT_EQ(0, entry->ReadData(1, 6500, buffer2.get(), kSize2,
+                               net::CompletionOnceCallback()));
+  EXPECT_EQ(6500, entry->ReadData(1, 0, buffer3.get(), kSize3,
+                                  net::CompletionOnceCallback()));
+  EXPECT_EQ(8192, entry->WriteData(1, 0, buffer3.get(), 8192,
+                                   net::CompletionOnceCallback(), false));
+  EXPECT_EQ(8192, entry->ReadData(1, 0, buffer3.get(), kSize3,
+                                  net::CompletionOnceCallback()));
   EXPECT_EQ(8192, entry->GetDataSize(1));
 
   // We need to delete the memory buffer on this thread.
-  EXPECT_EQ(0, entry->WriteData(
-      0, 0, NULL, 0, net::CompletionCallback(), true));
-  EXPECT_EQ(0, entry->WriteData(
-      1, 0, NULL, 0, net::CompletionCallback(), true));
+  EXPECT_EQ(
+      0, entry->WriteData(0, 0, NULL, 0, net::CompletionOnceCallback(), true));
+  EXPECT_EQ(
+      0, entry->WriteData(1, 0, NULL, 0, net::CompletionOnceCallback(), true));
 }
 
 // We need to support synchronous IO even though it is not a supported operation
@@ -391,49 +379,38 @@
   CacheTestFillBuffer(buffer1->data(), kSize1, false);
   CacheTestFillBuffer(buffer2->data(), kSize2, false);
   base::strlcpy(buffer1->data(), "the data", kSize1);
-  EXPECT_EQ(17000,
-            entry->WriteData(
-                0, 0, buffer1.get(), kSize1, net::CompletionCallback(), false));
+  EXPECT_EQ(17000, entry->WriteData(0, 0, buffer1.get(), kSize1,
+                                    net::CompletionOnceCallback(), false));
   memset(buffer1->data(), 0, kSize1);
-  EXPECT_EQ(
-      17000,
-      entry->ReadData(0, 0, buffer1.get(), kSize1, net::CompletionCallback()));
+  EXPECT_EQ(17000, entry->ReadData(0, 0, buffer1.get(), kSize1,
+                                   net::CompletionOnceCallback()));
   EXPECT_STREQ("the data", buffer1->data());
 
   base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
-  EXPECT_EQ(
-      25000,
-      entry->WriteData(
-          1, 10000, buffer2.get(), kSize2, net::CompletionCallback(), false));
+  EXPECT_EQ(25000, entry->WriteData(1, 10000, buffer2.get(), kSize2,
+                                    net::CompletionOnceCallback(), false));
   memset(buffer2->data(), 0, kSize2);
-  EXPECT_EQ(24989,
-            entry->ReadData(
-                1, 10011, buffer2.get(), kSize2, net::CompletionCallback()));
+  EXPECT_EQ(24989, entry->ReadData(1, 10011, buffer2.get(), kSize2,
+                                   net::CompletionOnceCallback()));
   EXPECT_STREQ("big data goes here", buffer2->data());
-  EXPECT_EQ(
-      25000,
-      entry->ReadData(1, 0, buffer2.get(), kSize2, net::CompletionCallback()));
-  EXPECT_EQ(5000,
-            entry->ReadData(
-                1, 30000, buffer2.get(), kSize2, net::CompletionCallback()));
+  EXPECT_EQ(25000, entry->ReadData(1, 0, buffer2.get(), kSize2,
+                                   net::CompletionOnceCallback()));
+  EXPECT_EQ(5000, entry->ReadData(1, 30000, buffer2.get(), kSize2,
+                                  net::CompletionOnceCallback()));
 
-  EXPECT_EQ(0,
-            entry->ReadData(
-                1, 35000, buffer2.get(), kSize2, net::CompletionCallback()));
-  EXPECT_EQ(
-      17000,
-      entry->ReadData(1, 0, buffer1.get(), kSize1, net::CompletionCallback()));
-  EXPECT_EQ(
-      17000,
-      entry->WriteData(
-          1, 20000, buffer1.get(), kSize1, net::CompletionCallback(), false));
+  EXPECT_EQ(0, entry->ReadData(1, 35000, buffer2.get(), kSize2,
+                               net::CompletionOnceCallback()));
+  EXPECT_EQ(17000, entry->ReadData(1, 0, buffer1.get(), kSize1,
+                                   net::CompletionOnceCallback()));
+  EXPECT_EQ(17000, entry->WriteData(1, 20000, buffer1.get(), kSize1,
+                                    net::CompletionOnceCallback(), false));
   EXPECT_EQ(37000, entry->GetDataSize(1));
 
   // We need to delete the memory buffer on this thread.
-  EXPECT_EQ(0, entry->WriteData(
-      0, 0, NULL, 0, net::CompletionCallback(), true));
-  EXPECT_EQ(0, entry->WriteData(
-      1, 0, NULL, 0, net::CompletionCallback(), true));
+  EXPECT_EQ(
+      0, entry->WriteData(0, 0, NULL, 0, net::CompletionOnceCallback(), true));
+  EXPECT_EQ(
+      0, entry->WriteData(1, 0, NULL, 0, net::CompletionOnceCallback(), true));
 }
 
 void DiskCacheEntryTest::ExternalSyncIO() {
@@ -1629,14 +1606,12 @@
   ASSERT_THAT(CreateEntry(key, &parent_entry), IsOk());
 
   // Writes to the parent entry.
-  EXPECT_EQ(kSize,
-            parent_entry->WriteSparseData(
-                0, buf.get(), kSize, net::CompletionCallback()));
+  EXPECT_EQ(kSize, parent_entry->WriteSparseData(
+                       0, buf.get(), kSize, net::CompletionOnceCallback()));
 
   // This write creates a child entry and writes to it.
-  EXPECT_EQ(kSize,
-            parent_entry->WriteSparseData(
-                8192, buf.get(), kSize, net::CompletionCallback()));
+  EXPECT_EQ(kSize, parent_entry->WriteSparseData(
+                       8192, buf.get(), kSize, net::CompletionOnceCallback()));
 
   parent_entry->Close();
 
@@ -2124,20 +2099,16 @@
   ASSERT_THAT(CreateEntry(key, &entry), IsOk());
 
   // Writes in the middle of an entry.
-  EXPECT_EQ(
-      1024,
-      entry->WriteSparseData(0, buf.get(), 1024, net::CompletionCallback()));
-  EXPECT_EQ(
-      1024,
-      entry->WriteSparseData(5120, buf.get(), 1024, net::CompletionCallback()));
-  EXPECT_EQ(1024,
-            entry->WriteSparseData(
-                10000, buf.get(), 1024, net::CompletionCallback()));
+  EXPECT_EQ(1024, entry->WriteSparseData(0, buf.get(), 1024,
+                                         net::CompletionOnceCallback()));
+  EXPECT_EQ(1024, entry->WriteSparseData(5120, buf.get(), 1024,
+                                         net::CompletionOnceCallback()));
+  EXPECT_EQ(1024, entry->WriteSparseData(10000, buf.get(), 1024,
+                                         net::CompletionOnceCallback()));
 
   // Writes in the middle of an entry and spans 2 child entries.
-  EXPECT_EQ(8192,
-            entry->WriteSparseData(
-                50000, buf.get(), 8192, net::CompletionCallback()));
+  EXPECT_EQ(8192, entry->WriteSparseData(50000, buf.get(), 8192,
+                                         net::CompletionOnceCallback()));
 
   int64_t start;
   net::TestCompletionCallback cb;
@@ -2322,9 +2293,8 @@
   int64_t offset = 1024;
   // Write to a bunch of ranges.
   for (int i = 0; i < 12; i++) {
-    EXPECT_EQ(kSize,
-              entry->WriteSparseData(
-                  offset, buf.get(), kSize, net::CompletionCallback()));
+    EXPECT_EQ(kSize, entry->WriteSparseData(offset, buf.get(), kSize,
+                                            net::CompletionOnceCallback()));
     offset *= 4;
   }
   EXPECT_EQ(9, cache_->GetEntryCount());
@@ -2530,11 +2500,11 @@
 
   if (!cb1.have_result()) {
     EXPECT_EQ(net::ERR_CACHE_OPERATION_NOT_SUPPORTED,
-              entry->ReadSparseData(
-                  offset, buf.get(), kSize, net::CompletionCallback()));
+              entry->ReadSparseData(offset, buf.get(), kSize,
+                                    net::CompletionOnceCallback()));
     EXPECT_EQ(net::ERR_CACHE_OPERATION_NOT_SUPPORTED,
-              entry->WriteSparseData(
-                  offset, buf.get(), kSize, net::CompletionCallback()));
+              entry->WriteSparseData(offset, buf.get(), kSize,
+                                     net::CompletionOnceCallback()));
   }
 
   // Now see if we receive all notifications. Note that we should not be able
@@ -2834,7 +2804,7 @@
                          base::File::FLAG_WRITE | base::File::FLAG_CREATE);
   ASSERT_TRUE(entry_file1.IsValid());
 
-  entry->WriteData(2, 0, buffer1.get(), kSize1, net::CompletionCallback(),
+  entry->WriteData(2, 0, buffer1.get(), kSize1, net::CompletionOnceCallback(),
                    /* truncate= */ true);
   entry->Close();
 
@@ -2923,7 +2893,7 @@
                          base::File::FLAG_WRITE | base::File::FLAG_CREATE);
   ASSERT_TRUE(entry_file1.IsValid());
 
-  entry->WriteData(2, 0, buffer1.get(), kSize1, net::CompletionCallback(),
+  entry->WriteData(2, 0, buffer1.get(), kSize1, net::CompletionOnceCallback(),
                    /* truncate= */ true);
 
   net::TestCompletionCallback cb;
@@ -3220,7 +3190,7 @@
 
   disk_cache::Entry* entry = NULL;
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   EXPECT_NE(null, entry);
   entry->Close();
 
@@ -3254,7 +3224,7 @@
   disk_cache::Entry* entry = NULL;
 
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   EXPECT_NE(null, entry);
   entry->Close();
 
@@ -3289,9 +3259,8 @@
   // twice, so the next Write operation must succeed and it must be able to
   // perform it optimistically, since there is no operation running on this
   // entry.
-  EXPECT_EQ(kSize1,
-            entry2->WriteData(
-                1, 0, buffer1.get(), kSize1, net::CompletionCallback(), false));
+  EXPECT_EQ(kSize1, entry2->WriteData(1, 0, buffer1.get(), kSize1,
+                                      net::CompletionOnceCallback(), false));
 
   // Lets do another read so we block until both the write and the read
   // operation finishes and we can then test for HasOneRef() below.
@@ -3320,7 +3289,7 @@
   disk_cache::Entry* entry = NULL;
 
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   EXPECT_NE(null, entry);
   ScopedEntryPtr entry_closer(entry);
   entry->Doom();
@@ -3355,7 +3324,7 @@
   disk_cache::Entry* entry = NULL;
 
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   EXPECT_NE(null, entry);
   ScopedEntryPtr entry_closer(entry);
 
@@ -3387,7 +3356,7 @@
 
   // First, an optimistic create.
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   ASSERT_TRUE(entry);
   ScopedEntryPtr entry_closer(entry);
 
@@ -3405,10 +3374,8 @@
 
   // Finally, we should perform an optimistic write and confirm that all
   // references to the IO buffer have been released.
-  EXPECT_EQ(
-      kWriteSize,
-      entry->WriteData(
-          1, 0, buffer1.get(), kWriteSize, net::CompletionCallback(), false));
+  EXPECT_EQ(kWriteSize, entry->WriteData(1, 0, buffer1.get(), kWriteSize,
+                                         net::CompletionOnceCallback(), false));
   EXPECT_TRUE(buffer1->HasOneRef());
 }
 
@@ -3427,7 +3394,7 @@
   disk_cache::Entry* entry = NULL;
 
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   EXPECT_NE(null, entry);
 
   EXPECT_THAT(cache_->DoomEntry(key, net::HIGHEST, cb.callback()),
@@ -3832,7 +3799,7 @@
   const char key[] = "the first key";
   disk_cache::Entry* entry = NULL;
   ASSERT_EQ(net::OK, cache_->CreateEntry(key, net::HIGHEST, &entry,
-                                         net::CompletionCallback()));
+                                         net::CompletionOnceCallback()));
   ScopedEntryPtr entry_closer(entry);
 
   const int kBufferSize = 1024;
@@ -5119,7 +5086,7 @@
   // meaningful here, as the latter is a helper in the test fixture that blocks
   // if needed.
   EXPECT_EQ(kEntrySize, entry->ReadData(1, 0, read_buf.get(), kEntrySize,
-                                        net::CompletionCallback()));
+                                        net::CompletionOnceCallback()));
   EXPECT_EQ(0, memcmp(read_buf->data(), payload_->data(), kEntrySize));
   entry->Close();
 }
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index b26dc83bd..2825f643 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -267,9 +267,10 @@
   Initialize(base::span<MockRead>(), base::span<MockWrite>(),
              base::span<MockRead>(), base::span<MockWrite>());
 
-  int rv = handle_.Init("a", CreateNoTunnelParams(), LOW, SocketTag(),
-                        ClientSocketPool::RespectLimits::ENABLED,
-                        CompletionCallback(), pool_.get(), NetLogWithSource());
+  int rv =
+      handle_.Init("a", CreateNoTunnelParams(), LOW, SocketTag(),
+                   ClientSocketPool::RespectLimits::ENABLED,
+                   CompletionOnceCallback(), pool_.get(), NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle_.is_initialized());
   ASSERT_TRUE(handle_.socket());
@@ -287,10 +288,10 @@
 TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
   Initialize(base::span<MockRead>(), base::span<MockWrite>(),
              base::span<MockRead>(), base::span<MockWrite>());
-  EXPECT_EQ(
-      OK, handle_.Init("a", CreateNoTunnelParams(), HIGHEST, SocketTag(),
-                       ClientSocketPool::RespectLimits::ENABLED,
-                       CompletionCallback(), pool_.get(), NetLogWithSource()));
+  EXPECT_EQ(OK, handle_.Init("a", CreateNoTunnelParams(), HIGHEST, SocketTag(),
+                             ClientSocketPool::RespectLimits::ENABLED,
+                             CompletionOnceCallback(), pool_.get(),
+                             NetLogWithSource()));
   EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
 }
 
@@ -897,9 +898,10 @@
   SocketTag tag2(getuid(), 0x87654321);
 
   // Verify requested socket is tagged properly.
-  int rv = handle_.Init("a", CreateNoTunnelParams(), LOW, tag1,
-                        ClientSocketPool::RespectLimits::ENABLED,
-                        CompletionCallback(), pool_.get(), NetLogWithSource());
+  int rv =
+      handle_.Init("a", CreateNoTunnelParams(), LOW, tag1,
+                   ClientSocketPool::RespectLimits::ENABLED,
+                   CompletionOnceCallback(), pool_.get(), NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle_.is_initialized());
   ASSERT_TRUE(handle_.socket());
@@ -913,7 +915,7 @@
   handle_.Reset();
   rv = handle_.Init("a", CreateNoTunnelParams(), LOW, tag2,
                     ClientSocketPool::RespectLimits::ENABLED,
-                    CompletionCallback(), pool_.get(), NetLogWithSource());
+                    CompletionOnceCallback(), pool_.get(), NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle_.socket());
   EXPECT_TRUE(handle_.socket()->IsConnected());
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index 23f093d..320a071 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -351,7 +351,7 @@
   std::unique_ptr<UploadDataStream> body(
       std::make_unique<ElementsUploadDataStream>(std::move(element_readers),
                                                  0));
-  ASSERT_THAT(body->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(body->Init(CompletionOnceCallback(), NetLogWithSource()), IsOk());
   // Shouldn't be merged if upload data is empty.
   ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
       "some header", body.get()));
@@ -410,7 +410,7 @@
 
   std::unique_ptr<UploadDataStream> body(
       new ElementsUploadDataStream(std::move(element_readers), 0));
-  ASSERT_THAT(body->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(body->Init(CompletionOnceCallback(), NetLogWithSource()), IsOk());
   // Yes, should be merged if the in-memory body is small here.
   ASSERT_TRUE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
       "some header", body.get()));
@@ -424,7 +424,7 @@
 
   std::unique_ptr<UploadDataStream> body(
       new ElementsUploadDataStream(std::move(element_readers), 0));
-  ASSERT_THAT(body->Init(CompletionCallback(), NetLogWithSource()), IsOk());
+  ASSERT_THAT(body->Init(CompletionOnceCallback(), NetLogWithSource()), IsOk());
   // Shouldn't be merged if the in-memory body is large here.
   ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
       "some header", body.get()));
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 99dcf7b6..9bcf4c3 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -1577,7 +1577,6 @@
     { "name": "sro.center", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "standardssuck.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "testsuite.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "thecustomizewindows.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "weggeweest.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "whatwg.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "when-release.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -1833,7 +1832,6 @@
     { "name": "mutantmonkey.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mutantmonkey.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alecvannoten.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "anime.my", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "atavio.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "atavio.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "atavio.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -3146,7 +3144,6 @@
     { "name": "linguatrip.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "korobi.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gipsamsfashion.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "lachlankidson.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kinderbasar-luhe.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "konsertoversikt.no", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kbit.dk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -13998,7 +13995,6 @@
     { "name": "kfbrussels.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kiadoapartman.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kickass-proxies.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "kickstart.com.pk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kiedys.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kiekin.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "kilogram.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -14247,7 +14243,6 @@
     { "name": "notnl.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "novabench.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "novaco.in", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "novoresume.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nozoe.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nrechn.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ntotten.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -14286,12 +14281,10 @@
     { "name": "papermasters.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "paraborsa.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "parser.nu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "partnersfcu.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pasadenapooch.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "passionatefoodie.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "passumpsicbank.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "paulov.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "paultibbetts.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "paulwatabe.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "payme.uz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "paystack.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -14315,7 +14308,6 @@
     { "name": "philpropertygroup.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "philsturgeon.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "phonenumberinfo.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "phosagro.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "photographyforchange.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "phpbbchinese.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "phpmyadmin.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -17225,7 +17217,6 @@
     { "name": "grillinfools.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "getronics.care", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gus.host", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "giftking.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gglks.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "grimcalc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "greyskymedia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -22108,7 +22099,6 @@
     { "name": "mode-marine.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "macsandcheesedreams.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "monkeyhill.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "monsieurbureau.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "msx.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "moskva.guide", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mozilla.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -27448,7 +27438,6 @@
     { "name": "schnyder-werbung.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "schsrch.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "schull.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "schuppentier.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "schwarzwald-flirt.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "scintilla.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "scintillating.stream", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -28296,7 +28285,6 @@
     { "name": "yubikey.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "yubikey.sg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "yude.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "yuhuo.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "yummyfamilyrecipes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "yuriykuzmin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "yvonnehaeusser.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29102,7 +29090,6 @@
     { "name": "coptic-treasures.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "compagniemartin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "crossfunctional.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "creative-coder.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "curiouscat.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cosmiatria.pe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "conkret.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29174,7 +29161,6 @@
     { "name": "creaescola.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cursuri-de-actorie.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "darkfire.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "cwningen.cymru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cyberspace.community", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "darkanzali.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "darylcumbo.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29329,7 +29315,6 @@
     { "name": "dugnet.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dr-becarelli-philippe.chirurgiens-dentistes.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cyberprey.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "dreamhostremixer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "driver.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dkcomputers.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dopsi.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29584,7 +29569,6 @@
     { "name": "faraslot8.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "fleursdesoleil.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "feisim.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "eriador.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "fetclips.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "florentynadawn.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "followersya.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -31809,7 +31793,6 @@
     { "name": "twenty71.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ttll.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "thaiforest.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "turtlepwr.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tsukuba.style", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tuts4you.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "twincitynissantxparts.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -33262,7 +33245,6 @@
     { "name": "kakoomedia.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jpdeharenne.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "judc-ge.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "ivystech.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jundimax.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "judosaintdenis.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jsd-cog.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -33515,7 +33497,6 @@
     { "name": "mojnet.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "looka.photo", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "msgallery.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "mr-wolf.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "mww.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "muh.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "modelsclub.org.ua", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -39379,7 +39360,6 @@
     { "name": "myowndisk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myowndisk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mzh.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "n-kanazawa.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "n26.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nakedtruthbeauty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nan.ci", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39644,7 +39624,6 @@
     { "name": "soulcrazy.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "southambouncycastle.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "soutien-naissance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sp-sephiroth.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "spahireleeds.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "speedychat.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sportressofblogitude.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39684,7 +39663,6 @@
     { "name": "swfmax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "synergisticsoccer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "t47.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "taqsim.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "taylors-castles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tbtech.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tdsinflatables.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39738,7 +39716,6 @@
     { "name": "tokobungadilampung.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tokobungadipadangflorist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tokyo-onkyo.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tomochun.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "topbounce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "topbouncycastles.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "topclassfun.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39765,7 +39742,6 @@
     { "name": "tubetooncartoons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tubs4fun.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tumblenfun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tuminauskas.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tuppenceworth.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "turtles.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tuthowto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39894,7 +39870,6 @@
     { "name": "alloydevil.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "alwaysdry.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "asryflorist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "autism-osaka.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "belyvly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bkentertainments.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bobaobei.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -40228,7 +40203,6 @@
     { "name": "gobarrelroll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "goldcoaststumpbusters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "goldsky.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "gorakukai.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gordonscouts.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gotobrno.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "gouptime.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -40449,7 +40423,6 @@
     { "name": "optiekzien.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "orchidlive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "organica.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "osaka-fukushi.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ouestsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "packetlinux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "paducaheic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -41373,7 +41346,6 @@
     { "name": "clearance365.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "climaencusco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "code-judge.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "colorlifesupport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "comphare.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crag.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crowdliminal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44549,7 +44521,6 @@
     { "name": "pavelstriz.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pb-design.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pbcomp.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pc-tablet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pdxtowncar.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "peaceloveandlabor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pedikura-vitu.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -45929,7 +45900,6 @@
     { "name": "dietaanticelulitis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dietacelulitis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dietafeliz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "disarc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "divi-experte.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "djsk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dko-steiermark.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47068,7 +47038,6 @@
     { "name": "infocusvr.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "inku.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "innovum.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "invidio.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ioerror.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iotfen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ipv8.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -49310,7 +49279,6 @@
     { "name": "nazuna.blue", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "neftis.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "neriumhcp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "networking4all.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newpoke.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nikoninframe.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nikonnps.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -49329,7 +49297,6 @@
     { "name": "opticaltest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "orbu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oryva.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "osaka-jusan.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "overwall.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "p-fent.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "packetdigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -49880,7 +49847,6 @@
     { "name": "mbaasy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mbanq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mede-handover.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "medmarkt24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mega-aukcion.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "meintragebaby.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "melissaauclaire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51068,7 +51034,6 @@
     { "name": "ahosi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "airi-tabei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "airwolfthemes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "aixvox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aizxxs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aizxxs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "akplates.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -52951,7 +52916,6 @@
     { "name": "emailcontrol.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "et-inf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "etikus-hacker.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "euroapo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "evadifranco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "evenstar-gaming.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "evilcult.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -52959,7 +52923,6 @@
     { "name": "evolvingthoughts.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "exploitit.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fanhouwan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "farmacia-discreto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fcp.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "felett.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fiasgo.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53030,8 +52993,6 @@
     { "name": "jomofojo.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jomofojo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jordan-jungk.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kamagra-comprare.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kamagra-italia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kelleymcchesney.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kiyotatsu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kkr-bridal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53119,17 +53080,12 @@
     { "name": "passabook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "passy.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pc-servis-brno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pharmacie-fr.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pickmysoap.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pilarguineagil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pizzafunny.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "placedapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "placedsupport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "potenzmittel-levitra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "potenzmittel-webshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "potenzmittelblog.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "potenzpillen-kaufen.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "potenzprobleme-info.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "privelust.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "programistka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prophiler.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53155,7 +53111,6 @@
     { "name": "sanalbayrak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sayrodigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "school-b.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "screenplay.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "seadus.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "secondbike.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "securitycamerasaustin.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53214,7 +53169,6 @@
     { "name": "uldsh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vat.direct", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ventajasdesventajas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "viagra-kaufen.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "viagraonlinebestellen.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vistodeturista.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vitalthrills.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53576,7 +53530,6 @@
     { "name": "hendersonvalleyautomotive.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "henley-computer-repairs.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "herofil.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hesa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hesyifei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hh-wolke.dedyn.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hisingenrunt.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54496,6 +54449,1348 @@
     { "name": "zengdong.ren", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zny.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zone403.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0086286.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0x0.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1fach-digital.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1lord1faith.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1password.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1password.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "24zpravy.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2566335.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "286.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "297computers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "314553.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "360rail.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "364553.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "394553.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3deeplearner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3ik.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4c-haircare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "50.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "508088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52hentai.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "55797.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "656088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "66136.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "666omg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "755k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "7570.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "783lab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "787k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "80036.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "86286286.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8xx.bet", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8xx.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8xx888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8xxbet.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9riddles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aaron.cm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ab-bauservice-berlin.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abaaustin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abdelsater.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abdulwahaab.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "absolutedouble.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "absturztau.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "absturztaube.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acaptureservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acen.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ackermann.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acodess.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acousticalsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acriticismlab.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acyume.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adamyuan.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "admin.casa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adsamcik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adsbtc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "advocator.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adwokatkosterka.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adwokatzdunek.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "affordableblindsexpress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8-game.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agendatelefonica.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agostinhoenascimento.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agroxxi.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agscinemas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agscinemasapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aimax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "airductcleaninggrandprairie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "airductcleaningirving.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "airtimerewards.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "akr.services", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alamancetv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aledg.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alessandroz.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alftrain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allsaints.church", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allteach.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alorenzi.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alphagateanddoor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amifoundation.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aminorth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andreadraghetti.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andreas-hecht.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andreashecht-blog.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andree.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aneebahmed.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "animatelluris.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anjoola.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anshar.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anthonyvadala.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aoadatacommunity.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aofusa.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apkdv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apostilasaprovacao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apsa.paris", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aquainfo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arabicxz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arclandholdings.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arctica.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arefidgetspinnersgay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arias.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arizer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "armbrust.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aros.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arpamip.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arpnet.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arrazane.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "artisan-cheminees-poeles-design.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aseko.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ashleyedisonuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "asian-archi.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "atyourprice.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "audits.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "auroz.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "auroz.video", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autodidactic.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autodidacticstudios.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autodidacticstudios.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autodidacticstudios.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autosecurityfinance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "avidmode-dev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "avidmode-staging.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "avidmode.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "azurecrimson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "azuriasky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "azuriasky.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baby-fotografie-muenchen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "babybauch-shooting-muenchen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "babyshoprimini.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bacsituvansuckhoe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "badgersystems.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "badoo.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "badoo.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bahnenimbild.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bahnenimbild.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bahnmagazine.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baiduo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bamily.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bananavapes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baristador.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bartolomebellido.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "basercap.co.ke", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bauwens.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baytalebaa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bazos.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bbkaforum.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bc416.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bc418.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bc419.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beardic.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bebout.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "benhchuyenkhoa.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "benjamin-hering.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beretech.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-berlin.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-dortmund.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-duesseldorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-essen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-frankfurt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-hamburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-koeln.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-muenchen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bergmann-fotografin-stuttgart.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestiahosting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestjumptrampolines.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestparking.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestpig.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "betaprofiles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "betterjapanese.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "betterjapanese.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "betterjapanese.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bgwfans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bienstar.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bieumau.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bignumworks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "billionaire365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "binnenmeer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "biomasscore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "birthright.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bit-service-aalter.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitbox.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "biztouch.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blenheimears.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blinds-unlimited.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blogdelosjuguetes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bluedata.ltd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blueridgesecuritycameras.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bluetexservice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bluimedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blzrk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bodyweb.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bokkeriders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bonito.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boost.fyi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "borgmestervangen.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bourgdepabos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boxmoe.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boyfriendcookbook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brasildxn.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brnojebozi.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "browsemycity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bttc.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "burncorp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buycbd.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bztraveler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bztraveler.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "c0rporation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cabineritten.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cagalogluyayinevi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "caleb.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "calendly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "calrotaract.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cambridge-security.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cameo-membership.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "camjobs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "camomile.desi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "campvana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cannacards.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cant.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "caoshan60.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capstoneinsights.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carhunters.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carlot-j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carolina.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carroceriascarluis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carseatchecks.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carsoug.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "castbulletassoc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casteloinformatica.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "catalogosvirtualesonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "catgirl.science", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "catprog.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cc2729.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "centrym.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cfurl.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chadtaljaardt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chamicro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chargedmonkey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "charisma.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "charmanterelefant.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chefwear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chenzhipeng.com.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chibr.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chilimath.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chipglobe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chips-scheduler.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chmielarz.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "choyri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "christianlis.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "christianlis.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chrysanthos.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chuppa.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cindydudley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cirurgicasalutar.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cisofy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cispeo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cjdby.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cjean.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudlessdreams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clsfoundationrepairandwaterproofing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubcorsavenezuela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cobcode.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "codejots.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "codexpo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "codinginfinity.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coentropic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comandofilmes.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comeals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comevius.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comevius.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comevius.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "compros.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "conatus.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "concretelevelingsystems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "conexiontransporte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "conn.cx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "conner.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "connorhatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "conociendosalama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "constructieve.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "contractdigital.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coolbitx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coonawarrawines.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coppermein.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "corinastefan.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "countersolutions.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "couvreur-hinault.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crawler.ninja", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "creativeglassgifts.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crowdsim3d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crt.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crystallizedcouture.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "culturesouthwest.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "curiouspeddler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "curva.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwrau.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cybrary.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "czbtm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "d3lab.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dabneydriveanimalhospital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daisakuikeda.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "danielmorell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "danielran.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dansdiscounttools.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dappworld.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "darkerlystormy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "darkerstormy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "darknessflickers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dashwebconsulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dasteichwerk.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davesharpe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidforward.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidforward.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidmn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dawgs.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dbjc.duckdns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ddy.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deathofspring.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dentistesdarveauetrioux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "der-fliesenzauberer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dereddingsklos.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "design-in-bad.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "desormiers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "destinopiriapolis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "detodojuegos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "detoxic.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "devsjournal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "devsrvr.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dex.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dexigner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diablovalleytech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dialapicnic.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digicy.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dirkdoering.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "djleon.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dnspod.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dnzz123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dobraprace.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donlydental.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-business-fotografie-muenchen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-berlin.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-erfurt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-frankfurt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-hamburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-koeln.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-muenchen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-nuernberg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-stuttgart.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-fotografie-wien.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "donna-bellini-hochzeitsfotograf-frankfurt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dormirmucho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dornhecker.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dosdediez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dostlar.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dotsiam.in.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "draghetti.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drawxp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drevanbeale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drfranciscofonseca.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drinkcontrolapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dripdoctors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drlandis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drusantia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drwxr.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dryerventcleaningarlington.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dryerventcleaningcarrollton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dso-izlake.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dukatek.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dunesadventure.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dwienzek.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dylancl.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dym.asia", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dym.bz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dym2012.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dym2013.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dym2014.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dym2017.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dymmovie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dzyszla.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "e-ptn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eacero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eaglewreck.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eastblue.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "easyssl.com.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eboutic.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ec.mine.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eca.edu.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecardoo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecardoo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecardoo.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eentweevijf.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "efcross.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "egres.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ehbssl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ehub.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ehub.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ehub.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ejkmedia.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ejkmuseum.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ejknet.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ejkwebdesign.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eleaut.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "electmikewaters.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "electricalpacificpalisades.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "electricfencingballito.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elektro-doerr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eluvio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elvn.tokyo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "embudospro.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ememsei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emvoice.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emyself.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emyself.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "encore.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enjoy-drive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enpasenerji.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ensembling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "envoutement-desenvoutement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epidauros.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epigrafes-led-farmakeia.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eposig.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "equeim.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "erikkruithof.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eroskines.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "evanreev.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "evavolfova.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eventnexus.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "evromandie.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "exoplatform.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "exploremonero.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fabmart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "familie-kruithof.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fanatical.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fateandirony.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "filamentia.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "filiosoft.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "filmers.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "firegore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fireplex.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "firstdry.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fitmeat.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flickcritter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flkrpxl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "florian2833z.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fluids.ac.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fogway.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fornwall.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "forquilhinhanoticias.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fotokomorkomania.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "foundationspecialisteast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "foundationspecialistmi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "foxo.blue", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fracreazioni.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frankbellamy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "free.ac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freedom.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freedom35.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freehao123.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frontierdiscount.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frostysummers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fullereno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fullerlife.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fun25.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "funfair.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "furry.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "g-p-design.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "g1s.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gabeb1920.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gachimuchi.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gachiyase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gaiavanderzeyp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "galanight.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "galilahiskye.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gameplaysforkids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gametube.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gamivo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "garciagerman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gartenhauszentrum.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gastromedicalcenter.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gatemotorsumhlanga.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gaurl.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gawrimanecuta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gaya-sa.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gccm-events.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gdngs.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gehirn.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gehirn.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "generace-id.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gensokyo.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gepgroup.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gerardinden.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gerbyte.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gerbyte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gerbyte.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "getinphase.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gf5fcalc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ghowell.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "giaithich.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gifts.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gingersutton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gisher.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gisher.video", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "glencambria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "glitzerstuecke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "glu3cifer.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gm-net.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gmtplus.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gndh.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gnk.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gocher.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "golang.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goldcoastasian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goldcoastphotographycourses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goldfmromania.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gosu.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gradecam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gradingcontractornc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grahamcarruthers.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "graphified.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "greenbaysecuritysolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "greenliv.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "greensborosecuritycameras.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grillen-darf-nicht-gesund-sein.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grottenthaler.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grrmmll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gsdb.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gtopala.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "guerard.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hacertest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hacker.holiday", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "haidihai.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "haim.bio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hajekdavid.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hardwareschotte.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "harion.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hash.army", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hausjugo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "haydentomas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "healthyteame.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hentaiworld.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "henzenhoning.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hgvnet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hj2999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hj3455.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hktkl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hochyi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hogepad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hohenleimbach.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "homem-viril.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "homesteadandprepper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hopesanddreams.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "horrormovies.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotcoin.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "houseofyee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "howellaccounts.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "howieisawesome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "howtocommunicate.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hqy.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hsappstatic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hsex.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hti.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hubapi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hubspot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "huffsinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "huskyeye.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hydrosight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyparia.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyvanilmankampaamo.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ianklug.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ibigawamizueco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ibstyle.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "icasture.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "idfy.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "idisposable.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "idolknow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ieeedeis.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "igshpa.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ihtdenisjaccard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ikedaquotes.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ikraenglish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imhua.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iminshell.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imwalking.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "imyrs.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "incy.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "indiatrademarkwatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "indigitalagency.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inflationstation.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infocoin.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "informhealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infradio.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infrathink.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inkeliz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "innerlightcrystals.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "innocenceseekers.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "insignificant.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "investor-academy.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inzestfreunde.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ioactive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ipv6demo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "irrewilse.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "islykaithecutest.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "islykaithecutest.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ismailkarsli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "italianjourneys.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iusedtosmoke.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ivanboi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ivig.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jacik.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jacksutton.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jacobjangles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jadara.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jakewestrip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "janterpstra.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jantinaboelens.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jarrodcastaing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jarrodcastaing.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jason.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jcbgolfandcountryclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jdjohnsonwaterproofing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jej.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jej.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jelmoli-shop.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jeroensangers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jerryweb.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jf-fotos.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jitlab.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jjjconnection.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jmce.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joefixit.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joerosca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jonahperez.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jorcus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joseitoda.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joshruppe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joshua.bio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "js93029.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jsdelivr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ju.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "juttaheitland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jvandenbroeck.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jzcapital.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k3508.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k4law.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kalolina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kashinavi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "katja-und-ronny.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kaverti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kdfans.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kfm.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kidsclub.photos", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kliqsd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "klzwzhi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kolania.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kolania.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kolania.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kolorbon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "komenamanda.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kotobox.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kucukayvaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "labspack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lanahallen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "landlordy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "landscape-photography.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "landscapephotography.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "langotie.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "larsgujord.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lc-promiss.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "learntale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "legrandvtc.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lendingclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "leonbuitendam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lesconteursavis.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lesfilmsavivre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "libra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lightdream.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "limelabs.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "limelabs.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lindsaygorski.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linux-audit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linuxsecurity.expert", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lisky.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "livebandphotos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liverider.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "livetoride.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "locksmith-sanantonio-tx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "logfro.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loigiai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loihay.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loli.tube", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loyaltyondemand.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loyaltyondemand.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lsmpx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lucasbergen.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "luke6887.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lukesutton.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lzwc.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "machinelearningjavascript.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maeln.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magieamour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magieblanche.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magnacarebroker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mahjong-navi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maison-haimard.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "majolka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "makalu.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maki-chan.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maniw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manski.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mapstack.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "marcbeije.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "marcberndtgen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "marchwj.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "marguerite-maison.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "marin-dom.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mark1998.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "markridgwell.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "massagelimaperu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matejgroma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mateuszchyla.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matok.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matsu-walk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matthewgrow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "matthewj.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mattlaks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maurovacca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mb300sd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcuuid.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcversions.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mdazo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mediabm.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medja.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "melodicprogressivehouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "menuiserie-berard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "metaregistrar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mibuiin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "michaelismold.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "miembarcacion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mikkonen.bio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milkandcookies.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millions57.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millions58.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millions60.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millions61.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millions62.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "millions63.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milsonhypnotherapyservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "minetracker.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "misinstrumentos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mitre10.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mivzaklive.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mizu.coffee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mobisium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "modulex-gmbh.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moeyoo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moeyun.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mojizuri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moneoci.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moneybird.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "monotributo.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "morrodafumacanoticias.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mosquitojoe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "movingtojapan.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mphoto.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mpu-giessen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mpu-vorbereitung.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mrjhnsn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mrprintables.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mrtunnel.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mu3on.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "muitadica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "murray.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "my-best-wishes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myamihealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myclasscam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myclasscam.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myhome-24.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myinvite.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mylittlechat.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mylotto.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mymun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myperks.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myrepublic.run", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mysterydata.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "n8mgt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "n8nvi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "n8solutions.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nacfit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nadsandgams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nakayama.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "natur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "natura-sense.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "navarralanparty.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nayami64.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nechiactua.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neffat.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neos.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neotist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "netsec.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "network-midlands.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "network-midlands.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "networking-groups.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "networkmidlands.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "networkmidlands.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "netz-yokohama.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newlifeband.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nextiot.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nflsic.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nicks-autos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nicktheitguy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nicolemathew.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ninja-skillz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nitschinger.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nixx-gel.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "noahjacobson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nomoondev.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "noortronic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nordwal.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "norsewars.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "notmybox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "npmg.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nulle-part.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nyadora.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nyadora.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nyansparkle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nzbr.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "obs.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "obsessharness.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ocarupo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ojeremy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "olbat.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oldita.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oles-hundehaus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "olifant.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "onesnzeroes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "onionbot.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "opportunity.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oppwa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimised.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimised.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimisedlabs.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimisedlabs.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimisedlabs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimisedlabs.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimizedlabs.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimizedlabs.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimizedlabs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "optimizedlabs.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "opure.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "orca.pet", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "osnova.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ospf.sk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "otakuyun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ottoversand.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ouin.land", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "our-box.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ourdocuments.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "outsiders.paris", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "p1cn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pact2017.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pagalworld.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paper.sc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paranoidcrypto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parentelement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parkfans.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parroquiasanrafaeldegramalote.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "partyyy.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "passionatelife.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "patapwn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "patrickquinn.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pauly-stahlhandel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pauly-stahlhandel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pdfsearches.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pennington.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "peoplesdecade.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pequenosfavoritos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "petalkr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pfarre-kremsmuenster.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phonix-company.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "photography-workshops.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "phumin.in.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pie-express.xxx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pigs.pictures", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pilatescenteraz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pintosplumbing.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pizza-show.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pj009.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pj02.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pkisolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plaisirdumouvement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "planetsoftware.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "planup.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plazasummerlin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plokko.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plurr.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pmnaish.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pogera.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pokazy-iluzji.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "polyr.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "poodlefan.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "portale-randkowe.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "portalveneza.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "portvincentcaravanpark.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pow-s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pow.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pplsoft.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "praxis-odermath.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "preio.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pressakey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pressakey.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "privacychick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "privcloud.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "procarservices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "procrastinatingengineer.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "projectlinuseasttn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "promo-brille.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "promo-brille.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "promo-brille.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "propertyinside.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "protech.ge", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "protectr.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "prowise.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "psici.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "psicologajanainapresotto.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pt-d.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ptfiber.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ptfiber.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ptfiber.spb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pty.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pubmire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "puggan.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "purplegrapegames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pusichatka.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "putrock.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pyramidsofchi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pzpittsburgh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qensio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qingcao.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quelle.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quelle.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quelle.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "queo.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quitimes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "quoteidiot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "r7.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "racdek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "racdek.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "racozo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "raft.pub", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rail-o-rama.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rail360.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "railbird.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "railorama.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "railpassie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "railvideo.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "railvideo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "railvideo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rawinfosec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rbcservicehub-uat.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rdplumbingsolutions.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reactpwa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "readytobattle.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "recaptcha-demo.appspot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "refletindosaude.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reisslittle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "relojes-online.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "relojesseiko.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "remedionaturales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "remilner.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "remirampin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reneclemens.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "renedekoeijer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "renedekoeijer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "resort-islands.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "retrojar.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rewtherealtor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rexhockingkelpies.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "riaki.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "richadams.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ridgelandchurch.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rioxmarketing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rivoflor.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rkmns.edu.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rmeuropean.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "robinwill.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "robot.works", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roc.net.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roodhealth.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rostclub.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal812.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal850.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal853.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal857.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal859.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal862.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal863.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal865.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal867.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal868.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal871.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royal876.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rpgcampaign.website", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rsanahuano.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rsmith.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ryzex.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "s1ris.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "s64.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saggiocc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sailormoonlibrary.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saint-bernard-gouesch.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saitv.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saleduck.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saleduck.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saleduck.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saleduck.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saleduck.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "salutethefish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "salutethegrains.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "samrobertson.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "samvanderkris.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "san-mian-ka.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "santamonicapost123.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sarahdoyley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sarahlouisesearle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saxotex.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sbrownbourne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scene.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schbebtv.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schottenland.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schutterijschinveld.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sciencehouse.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scubaland.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seanrodda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "searchcandy.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "searchcandy.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "searchshops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sebald.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sebald.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "secondchancejobsforfelons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seibu-kikaku.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "selectsplat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "semiread.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "septentrionalist.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "serbianclimbing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "serversfrom.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sethjust.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seventwentynine.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sgi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sgs.camera", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shophisway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shoshin.technology", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shovonhasan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shukatsu-support.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "siaggiusta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sianjhon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sidemount-forum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sidemount-tauchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sideropolisnoticias.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sielsystems.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sight-sound.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sihaizixun.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "simrail.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sinronet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "siratalmustaqim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sistemlash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skincare-note.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sky-universe.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skyem.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sleeps.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "slim-slender.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smakassen.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smartietop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smtpdev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "snaptier.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sngallery.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "snowpaws.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "snowyluma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "social-media-strategy.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "socialmarketingday.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sokaissues.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "solden.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soldesduck.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soldesduck.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "solidarita-kosovo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "songsmp3.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sonia.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "souly.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soundonsound.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soundprotectionllc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sp-sites.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spinor.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spoorcam.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spslawoffice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spsnewengland.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "staffordlabour.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stakestrategy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stanron.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "star.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "startsamenvitaal.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "statistik-seminare.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stcplasticsurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stevecostar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stmkza.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stoneagehealth.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "storeit.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "street-medics.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "striped.horse", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stuarteggerton.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "studiopirrate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "studytale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sugarmillmanagement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "suka.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "suke3.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sundayrest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sundragon.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sunfiregold.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "superdaddy.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "supermae.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "surgiclinic.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "surreyheathyc.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "svetdrzaku.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "svht.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "svobodnyblog.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sweak.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swiftpcbassembly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "syamuwatching.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sympmarc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sympraxisconsulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "systemchile.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "szclsya.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tabi-news.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taiphanmem.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tannerwj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taplamvan.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tapsnapp.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxid-k.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tbejos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "technic3000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "technikman.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techtrader.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techtrader.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tecma.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tellcorpassessoria.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "termux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tetraetc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "the-bermanns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "the-woods.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thebarrens.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thebestpersonin.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thebinarys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thebulletin.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thecookiejar.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thefourthmoira.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thefuckingtide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thehoryzon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thelatedcult.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thepoplarswines.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thepurem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thereisnocloud.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theworldexchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theworldexchange.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theworldexchange.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thisisgrey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thisisthefinalact.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thomasduerlund.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thomasmerritt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thoroughbreddiesel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "threit.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ticketmaze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ticketrunway.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tilta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timbers.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timhieubenh.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timhieuthuoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tina.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tit-dev.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tmakiguchi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toabsentfamily.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tobiaswiese.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tokenmarket.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tom.je", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tomandmara.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tomspdblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "toplist.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "topsailtechnologies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trainmagazine.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trainmagazine.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trainmagazine.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trainplaza.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trainplaza.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trainplaza.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trajectfoto.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trajectvideo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "transitmoe.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "transoil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "treinmagazine.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "treinmagazine.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trevsanders.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tribe.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tribetrails.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "troyhunt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "truncus-encephali.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ts3-legenda.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tsai.com.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ttrade.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tudorapido.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tuffsruffs.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "turl.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tusi.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tweetfinity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tweetfinityapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tz56789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ulgc.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unicorn-systems.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "universal.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upholsterydesign.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upturn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urbandance.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urep.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urlakite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uskaria.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "usweme.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "utterberry.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uw1008.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uxp-it.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uziregister.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "valcardiesel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "valentin.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "valleydalecottage.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vandorenscholars.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vandyhacks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vangoghcoaching.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vantaio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "varalwamp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vendermicasarapido.com.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "verifiedjoseph.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "verifiny.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vetbits.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vgorcum.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "victora.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "videosxgays.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vikalpgupta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vinetech.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vip-9649.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vip9649.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "viralsv.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vnpem.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vrjetpackgame.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vsestoki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vuojolahti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vv1234.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vwfsrentacar.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "w1221.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wandystan.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangbangyu.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangbangyu.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangbangyu.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangbangyu.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangbangyu.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wanybug.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wanybug.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wanybug.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wanybug.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "waterdogsmokedfish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "waverlysecuritycameras.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "waycraze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wblinks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wby.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcwcg.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "web-odyssey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "web-siena.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "web-smart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webadiccion.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webadicta.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webadicto.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webcurtaincall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webdemaestrias.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webnexty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webseo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "websouthdesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "weynaphotography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "whatusb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "whoiscuter.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "whoiscutest.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "whynohttps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wildwind.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wisedog.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "womcom.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "woudenbergsedrukkerij.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www-66136.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www-7570.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www-80036.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www-9649.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www-pj009.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wxforums.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wycrow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wylog.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xdos.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xeiropraktiki.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xiaomao.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xjf6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--68jub.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--80adbevek3air0ee9b8d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--ehq13kgw4e.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--krpto-lva.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xoonth.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yageys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yellowfly.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yhfou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yiheng.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yogahealsinc.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yourtrainingsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yrjanheikki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yspeo.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yspeo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuanjiazhao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuki-portfolio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuyo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yyrss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "z-to-a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zacharyseguin.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zalvus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zbut.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zdrave-konzultace.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zdravekonzultace.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zeparadox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zephyretcoraline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zhenyan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zhi.ci", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zhongzicili.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zkontrolujsiauto.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zoarcampsite.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zozo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zpy.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zvejonys.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index a57d084..7a17f045 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -24,7 +24,6 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "net/base/completion_once_callback.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
 #include "net/base/net_errors.h"
@@ -426,7 +425,7 @@
   int DoConnect(bool succeed, bool was_async, bool recoverable) {
     int result = OK;
     if (succeed) {
-      socket()->Connect(CompletionCallback());
+      socket()->Connect(CompletionOnceCallback());
     } else if (recoverable) {
       result = ERR_PROXY_AUTH_REQUESTED;
     } else {
@@ -779,7 +778,7 @@
   TestConnectJobDelegate delegate;
   ClientSocketHandle ignored;
   TestClientSocketPoolBase::Request request(
-      &ignored, CompletionCallback(), DEFAULT_PRIORITY, SocketTag(),
+      &ignored, CompletionOnceCallback(), DEFAULT_PRIORITY, SocketTag(),
       ClientSocketPool::RespectLimits::ENABLED,
       internal::ClientSocketPoolBaseHelper::NORMAL, params_,
       NetLogWithSource());
@@ -796,7 +795,7 @@
   TestNetLog log;
 
   TestClientSocketPoolBase::Request request(
-      &ignored, CompletionCallback(), DEFAULT_PRIORITY, SocketTag(),
+      &ignored, CompletionOnceCallback(), DEFAULT_PRIORITY, SocketTag(),
       ClientSocketPool::RespectLimits::ENABLED,
       internal::ClientSocketPoolBaseHelper::NORMAL, params_,
       NetLogWithSource());
@@ -2303,7 +2302,7 @@
   ASSERT_THAT(callback.WaitForResult(), IsOk());
 
   // Use and release the socket.
-  EXPECT_EQ(1, handle.socket()->Write(NULL, 1, CompletionCallback(),
+  EXPECT_EQ(1, handle.socket()->Write(NULL, 1, CompletionOnceCallback(),
                                       TRAFFIC_ANNOTATION_FOR_TESTS));
   TestLoadTimingInfoConnectedNotReused(handle);
   handle.Reset();
@@ -2316,7 +2315,7 @@
   BoundTestNetLog log;
   rv = handle.Init("a", params_, LOWEST, SocketTag(),
                    ClientSocketPool::RespectLimits::ENABLED,
-                   CompletionCallback(), pool_.get(), log.bound());
+                   CompletionOnceCallback(), pool_.get(), log.bound());
   ASSERT_THAT(rv, IsOk());
   EXPECT_TRUE(handle.is_reused());
   TestLoadTimingInfoConnectedReused(handle);
@@ -2366,7 +2365,7 @@
   handle.Reset();
   ASSERT_THAT(callback2.WaitForResult(), IsOk());
   // Use the socket.
-  EXPECT_EQ(1, handle2.socket()->Write(NULL, 1, CompletionCallback(),
+  EXPECT_EQ(1, handle2.socket()->Write(NULL, 1, CompletionOnceCallback(),
                                        TRAFFIC_ANNOTATION_FOR_TESTS));
   handle2.Reset();
 
@@ -3068,9 +3067,9 @@
   EXPECT_THAT(callback3.WaitForResult(), IsOk());
 
   // Use the socket.
-  EXPECT_EQ(1, handle1.socket()->Write(NULL, 1, CompletionCallback(),
+  EXPECT_EQ(1, handle1.socket()->Write(NULL, 1, CompletionOnceCallback(),
                                        TRAFFIC_ANNOTATION_FOR_TESTS));
-  EXPECT_EQ(1, handle3.socket()->Write(NULL, 1, CompletionCallback(),
+  EXPECT_EQ(1, handle3.socket()->Write(NULL, 1, CompletionOnceCallback(),
                                        TRAFFIC_ANNOTATION_FOR_TESTS));
 
   handle1.Reset();
@@ -3671,7 +3670,7 @@
   EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
 
   // Drain the pending read.
-  EXPECT_EQ(1, handle.socket()->Read(NULL, 1, CompletionCallback()));
+  EXPECT_EQ(1, handle.socket()->Read(NULL, 1, CompletionOnceCallback()));
 
   TestLoadTimingInfoConnectedReused(handle);
   handle.Reset();
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index ea2c5ff..83ae90d3 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -471,7 +471,7 @@
       ssl_config_for_origin, ssl_config_for_proxy,
       /*force_tunnel=*/false, privacy_mode, SocketTag(), net_log,
       num_preconnect_streams, NULL, HttpNetworkSession::NORMAL_SOCKET_POOL,
-      OnHostResolutionCallback(), CompletionCallback());
+      OnHostResolutionCallback(), CompletionOnceCallback());
 }
 
 }  // namespace net
diff --git a/net/socket/sequenced_socket_data_unittest.cc b/net/socket/sequenced_socket_data_unittest.cc
index 4095130..8748c42 100644
--- a/net/socket/sequenced_socket_data_unittest.cc
+++ b/net/socket/sequenced_socket_data_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
 #include "net/log/net_log_with_source.h"
@@ -264,12 +265,12 @@
   data_->set_connect_data(connect_data_);
   socket_factory_.AddSocketDataProvider(data_.get());
 
-  EXPECT_EQ(OK,
-            connection_.Init(
-                endpoint_.ToString(), tcp_params_, LOWEST, SocketTag(),
-                ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(),
-                reinterpret_cast<TransportClientSocketPool*>(&socket_pool_),
-                NetLogWithSource()));
+  EXPECT_EQ(OK, connection_.Init(
+                    endpoint_.ToString(), tcp_params_, LOWEST, SocketTag(),
+                    ClientSocketPool::RespectLimits::ENABLED,
+                    CompletionOnceCallback(),
+                    reinterpret_cast<TransportClientSocketPool*>(&socket_pool_),
+                    NetLogWithSource()));
   sock_ = connection_.socket();
 }
 
diff --git a/net/socket/socket_bio_adapter_unittest.cc b/net/socket/socket_bio_adapter_unittest.cc
index a3dc80f..983054a 100644
--- a/net/socket/socket_bio_adapter_unittest.cc
+++ b/net/socket/socket_bio_adapter_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "crypto/openssl_util.h"
 #include "net/base/address_list.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/net_errors.h"
 #include "net/log/net_log_source.h"
 #include "net/socket/socket_test_util.h"
@@ -56,7 +57,7 @@
     factory_.AddSocketDataProvider(data);
     std::unique_ptr<StreamSocket> socket = factory_.CreateTransportClientSocket(
         AddressList(), nullptr, nullptr, NetLogSource());
-    CHECK_EQ(OK, socket->Connect(net::CompletionCallback()));
+    CHECK_EQ(OK, socket->Connect(CompletionOnceCallback()));
     return socket;
   }
 
diff --git a/net/socket/socks_client_socket_pool.h b/net/socket/socks_client_socket_pool.h
index 1cfa31b..48fb475a 100644
--- a/net/socket/socks_client_socket_pool.h
+++ b/net/socket/socks_client_socket_pool.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_export.h"
 #include "net/dns/host_resolver.h"
diff --git a/net/socket/socks_client_socket_pool_unittest.cc b/net/socket/socks_client_socket_pool_unittest.cc
index 41131afe..78fd110c 100644
--- a/net/socket/socks_client_socket_pool_unittest.cc
+++ b/net/socket/socks_client_socket_pool_unittest.cc
@@ -145,7 +145,7 @@
   ClientSocketHandle handle;
   int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(),
                        ClientSocketPool::RespectLimits::ENABLED,
-                       CompletionCallback(), &pool_, NetLogWithSource());
+                       CompletionOnceCallback(), &pool_, NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle.is_initialized());
   EXPECT_TRUE(handle.socket());
@@ -163,10 +163,10 @@
         data.data_provider());
 
     ClientSocketHandle handle;
-    EXPECT_EQ(OK,
-              handle.Init("a", CreateSOCKSv5Params(), priority, SocketTag(),
-                          ClientSocketPool::RespectLimits::ENABLED,
-                          CompletionCallback(), &pool_, NetLogWithSource()));
+    EXPECT_EQ(
+        OK, handle.Init("a", CreateSOCKSv5Params(), priority, SocketTag(),
+                        ClientSocketPool::RespectLimits::ENABLED,
+                        CompletionOnceCallback(), &pool_, NetLogWithSource()));
     EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
     handle.socket()->Disconnect();
   }
@@ -183,10 +183,11 @@
         data.data_provider());
 
     ClientSocketHandle handle;
-    EXPECT_EQ(ERR_IO_PENDING,
-              handle.Init("a", CreateSOCKSv4Params(), priority, SocketTag(),
-                          ClientSocketPool::RespectLimits::ENABLED,
-                          CompletionCallback(), &pool_, NetLogWithSource()));
+    EXPECT_EQ(
+        ERR_IO_PENDING,
+        handle.Init("a", CreateSOCKSv4Params(), priority, SocketTag(),
+                    ClientSocketPool::RespectLimits::ENABLED,
+                    CompletionOnceCallback(), &pool_, NetLogWithSource()));
     EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
     EXPECT_EQ(priority, host_resolver_.last_request_priority());
     EXPECT_TRUE(handle.socket() == NULL);
@@ -221,7 +222,7 @@
   ClientSocketHandle handle;
   int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(),
                        ClientSocketPool::RespectLimits::ENABLED,
-                       CompletionCallback(), &pool_, NetLogWithSource());
+                       CompletionOnceCallback(), &pool_, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED));
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
@@ -258,7 +259,7 @@
   EXPECT_EQ(0, transport_socket_pool_.release_count());
   int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, SocketTag(),
                        ClientSocketPool::RespectLimits::ENABLED,
-                       CompletionCallback(), &pool_, NetLogWithSource());
+                       CompletionOnceCallback(), &pool_, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_SOCKS_CONNECTION_FAILED));
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
@@ -385,7 +386,7 @@
   ClientSocketHandle handle;
   int rv = handle.Init("a", params, LOW, tag1,
                        ClientSocketPool::RespectLimits::ENABLED,
-                       CompletionCallback(), &pool, NetLogWithSource());
+                       CompletionOnceCallback(), &pool, NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle.is_initialized());
   EXPECT_TRUE(handle.socket());
@@ -398,7 +399,7 @@
   handle.Reset();
   rv = handle.Init("a", params, LOW, tag2,
                    ClientSocketPool::RespectLimits::ENABLED,
-                   CompletionCallback(), &pool, NetLogWithSource());
+                   CompletionOnceCallback(), &pool, NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle.socket());
   EXPECT_TRUE(handle.socket()->IsConnected());
@@ -427,7 +428,7 @@
   handle.Reset();
   rv = handle.Init("a", params, LOW, tag2,
                    ClientSocketPool::RespectLimits::ENABLED,
-                   CompletionCallback(), &pool, NetLogWithSource());
+                   CompletionOnceCallback(), &pool, NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(handle.socket());
   EXPECT_TRUE(handle.socket()->IsConnected());
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index d3b528c..f54469a 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/net_export.h"
 #include "net/base/privacy_mode.h"
 #include "net/http/http_response_info.h"
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 8bd148b..a608a607 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -228,9 +228,10 @@
   scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT);
 
   ClientSocketHandle handle;
-  int rv = handle.Init(kGroupName, params, MEDIUM, SocketTag(),
-                       ClientSocketPool::RespectLimits::ENABLED,
-                       CompletionCallback(), pool_.get(), NetLogWithSource());
+  int rv =
+      handle.Init(kGroupName, params, MEDIUM, SocketTag(),
+                  ClientSocketPool::RespectLimits::ENABLED,
+                  CompletionOnceCallback(), pool_.get(), NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_CONNECTION_FAILED));
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
@@ -757,8 +758,8 @@
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
     std::unique_ptr<HostResolver::Request> request;
     int rv = host_resolver_.Resolve(
-        info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
-        &request, NetLogWithSource());
+        info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+        CompletionOnceCallback(), &request, NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
 
     // Setup a SpdySessionKey
@@ -816,8 +817,8 @@
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
     std::unique_ptr<HostResolver::Request> request;
     int rv = host_resolver_.Resolve(
-        info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
-        &request, NetLogWithSource());
+        info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+        CompletionOnceCallback(), &request, NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
 
     // Setup a SpdySessionKey
diff --git a/net/socket/ssl_server_socket_impl.cc b/net/socket/ssl_server_socket_impl.cc
index 9c72c4e5..eb44d4c 100644
--- a/net/socket/ssl_server_socket_impl.cc
+++ b/net/socket/ssl_server_socket_impl.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_util.h"
 #include "crypto/openssl_util.h"
 #include "crypto/rsa_private_key.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/client_cert_verifier.h"
@@ -784,8 +785,8 @@
 
   // TODO(davidben): Support asynchronous verifiers. http://crbug.com/347402
   std::unique_ptr<ClientCertVerifier::Request> ignore_async;
-  int res =
-      verifier->Verify(client_cert.get(), CompletionCallback(), &ignore_async);
+  int res = verifier->Verify(client_cert.get(), CompletionOnceCallback(),
+                             &ignore_async);
   DCHECK_NE(res, ERR_IO_PENDING);
 
   if (res != OK) {
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index be39db6..9581c0e 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -36,7 +36,7 @@
 #include "crypto/rsa_private_key.h"
 #include "crypto/signature_creator.h"
 #include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_address.h"
@@ -321,12 +321,13 @@
 
   // Write then read.
   int written =
-      server.Write(write_buf.get(), kTestDataSize, CompletionCallback(),
+      server.Write(write_buf.get(), kTestDataSize, CompletionOnceCallback(),
                    TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_GT(written, 0);
   EXPECT_LE(written, kTestDataSize);
 
-  int read = client.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  int read =
+      client.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   EXPECT_GT(read, 0);
   EXPECT_LE(read, written);
   EXPECT_EQ(0, memcmp(kTestData, read_buf->data(), read));
@@ -336,8 +337,9 @@
   EXPECT_EQ(ERR_IO_PENDING,
             server.Read(read_buf.get(), kReadBufSize, callback.callback()));
 
-  written = client.Write(write_buf.get(), kTestDataSize, CompletionCallback(),
-                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  written =
+      client.Write(write_buf.get(), kTestDataSize, CompletionOnceCallback(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_GT(written, 0);
   EXPECT_LE(written, kTestDataSize);
 
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 7c3c50f6..cdc1fe6d 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -6548,7 +6548,7 @@
   // size increased to default.
   scoped_refptr<IOBuffer> buf(new IOBuffer(kTargetSize));
   EXPECT_EQ(static_cast<int>(kTargetSize),
-            trans->Read(buf.get(), kTargetSize, CompletionCallback()));
+            trans->Read(buf.get(), kTargetSize, CompletionOnceCallback()));
   EXPECT_EQ(static_cast<int>(stream_max_recv_window_size),
             stream->stream()->recv_window_size());
   EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index d85f4cd..25f236cd 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -241,7 +241,7 @@
 void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data,
                                                      int len) {
   scoped_refptr<IOBuffer> buf(new IOBuffer(len));
-  ASSERT_EQ(len, sock_->Read(buf.get(), len, CompletionCallback()));
+  ASSERT_EQ(len, sock_->Read(buf.get(), len, CompletionOnceCallback()));
   ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
   ASSERT_TRUE(sock_->IsConnected());
 }
@@ -949,9 +949,9 @@
   ResumeAndRun();
 
   ASSERT_FALSE(sock_->IsConnected());
-  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
-  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
-  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
+  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionOnceCallback()));
+  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionOnceCallback()));
+  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionOnceCallback()));
   ASSERT_FALSE(sock_->IsConnectedAndIdle());
 }
 
@@ -1000,7 +1000,7 @@
   sock_->Disconnect();
 
   ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
-            sock_->Read(NULL, 1, CompletionCallback()));
+            sock_->Read(NULL, 1, CompletionOnceCallback()));
 
   // Let the RST_STREAM write while |rst| is in-scope.
   base::RunLoop().RunUntilIdle();
@@ -1029,14 +1029,14 @@
 
   ASSERT_FALSE(sock_->IsConnected());
   scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1));
-  ASSERT_EQ(kLen1, sock_->Read(buf.get(), kLen1, CompletionCallback()));
+  ASSERT_EQ(kLen1, sock_->Read(buf.get(), kLen1, CompletionOnceCallback()));
   ASSERT_EQ(std::string(kMsg1, kLen1), std::string(buf->data(), kLen1));
 
-  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
-  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback()));
+  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionOnceCallback()));
+  ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionOnceCallback()));
   sock_->Disconnect();
   ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
-            sock_->Read(NULL, 1, CompletionCallback()));
+            sock_->Read(NULL, 1, CompletionOnceCallback()));
 }
 
 // Calling Write() on a closed socket is an error
@@ -1061,7 +1061,7 @@
   ResumeAndRun();
   scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
   EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED,
-            sock_->Write(buf.get(), buf->size(), CompletionCallback(),
+            sock_->Write(buf.get(), buf->size(), CompletionOnceCallback(),
                          TRAFFIC_ANNOTATION_FOR_TESTS));
 }
 
@@ -1088,7 +1088,7 @@
 
   scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
   EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED,
-            sock_->Write(buf.get(), buf->size(), CompletionCallback(),
+            sock_->Write(buf.get(), buf->size(), CompletionOnceCallback(),
                          TRAFFIC_ANNOTATION_FOR_TESTS));
 
   // Let the RST_STREAM write while |rst| is in-scope.
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 5cbbf9ed..37eeb1c 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "build/build_config.h"
+#include "net/base/completion_once_callback.h"
 #include "net/dns/host_cache.h"
 #include "net/http/http_network_session.h"
 #include "net/log/net_log_with_source.h"
@@ -358,8 +359,8 @@
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
     std::unique_ptr<HostResolver::Request> request;
     int rv = session_deps_.host_resolver->Resolve(
-        info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
-        &request, NetLogWithSource());
+        info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+        CompletionOnceCallback(), &request, NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
 
     // Setup a SpdySessionKey.
@@ -546,8 +547,8 @@
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
     std::unique_ptr<HostResolver::Request> request;
     int rv = session_deps_.host_resolver->Resolve(
-        info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
-        &request, NetLogWithSource());
+        info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+        CompletionOnceCallback(), &request, NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
 
     test_hosts[i].key = SpdySessionKey(
@@ -627,8 +628,8 @@
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
     std::unique_ptr<HostResolver::Request> request;
     int rv = session_deps_.host_resolver->Resolve(
-        info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
-        &request, NetLogWithSource());
+        info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+        CompletionOnceCallback(), &request, NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
 
     test_hosts[i].key = SpdySessionKey(
@@ -989,8 +990,8 @@
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
     std::unique_ptr<HostResolver::Request> request;
     int rv = session_deps_.host_resolver->Resolve(
-        info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
-        &request, NetLogWithSource());
+        info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+        CompletionOnceCallback(), &request, NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
 
     test_hosts[i].key = SpdySessionKey(
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 564c2625..0148dad 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -3494,7 +3494,7 @@
   // Pre-populate the DNS cache, since a cached entry is required in order to
   // create the alias.
   int rv = session_deps_.host_resolver->Resolve(
-      info, DEFAULT_PRIORITY, &addresses, CompletionCallback(), &request,
+      info, DEFAULT_PRIORITY, &addresses, CompletionOnceCallback(), &request,
       NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
 
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index 04027fca..d6c4c1f 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -16,6 +16,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -182,16 +183,15 @@
   // URLFetcherStringWriter (for testing of this method only).
   if (fake_response_destination_ == STRING) {
     response_writer_ = std::move(response_writer);
-    int response = response_writer_->Initialize(CompletionCallback());
+    int response = response_writer_->Initialize(CompletionOnceCallback());
     // The TestURLFetcher doesn't handle asynchronous writes.
     DCHECK_EQ(OK, response);
 
     scoped_refptr<IOBuffer> buffer(new StringIOBuffer(fake_response_string_));
-    response = response_writer_->Write(buffer.get(),
-                                       fake_response_string_.size(),
-                                       CompletionCallback());
+    response = response_writer_->Write(
+        buffer.get(), fake_response_string_.size(), CompletionOnceCallback());
     DCHECK_EQ(static_cast<int>(fake_response_string_.size()), response);
-    response = response_writer_->Finish(OK, CompletionCallback());
+    response = response_writer_->Finish(OK, CompletionOnceCallback());
     DCHECK_EQ(OK, response);
   } else if (fake_response_destination_ == TEMP_FILE) {
     // SaveResponseToFileAtPath() should be called instead of this method to
diff --git a/net/websockets/websocket_basic_stream_adapters_test.cc b/net/websockets/websocket_basic_stream_adapters_test.cc
index b49df8e..31f7892 100644
--- a/net/websockets/websocket_basic_stream_adapters_test.cc
+++ b/net/websockets/websocket_basic_stream_adapters_test.cc
@@ -163,7 +163,7 @@
   // Buffer larger than each MockRead.
   const int kReadBufSize = 1024;
   auto read_buf = base::MakeRefCounted<IOBuffer>(kReadBufSize);
-  int rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  int rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(3, rv);
   EXPECT_EQ("foo", base::StringPiece(read_buf->data(), rv));
 
@@ -194,11 +194,11 @@
   // Buffer smaller than each MockRead.
   const int kReadBufSize = 2;
   auto read_buf = base::MakeRefCounted<IOBuffer>(kReadBufSize);
-  int rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  int rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(2, rv);
   EXPECT_EQ("fo", base::StringPiece(read_buf->data(), rv));
 
-  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(1, rv);
   EXPECT_EQ("o", base::StringPiece(read_buf->data(), rv));
 
@@ -209,7 +209,7 @@
   ASSERT_EQ(2, rv);
   EXPECT_EQ("ba", base::StringPiece(read_buf->data(), rv));
 
-  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(1, rv);
   EXPECT_EQ("r", base::StringPiece(read_buf->data(), rv));
 
@@ -231,8 +231,9 @@
   EXPECT_TRUE(adapter.is_initialized());
 
   auto write_buf1 = base::MakeRefCounted<StringIOBuffer>("foo");
-  int rv = adapter.Write(write_buf1.get(), write_buf1->size(),
-                         CompletionCallback(), TRAFFIC_ANNOTATION_FOR_TESTS);
+  int rv =
+      adapter.Write(write_buf1.get(), write_buf1->size(),
+                    CompletionOnceCallback(), TRAFFIC_ANNOTATION_FOR_TESTS);
   ASSERT_EQ(3, rv);
 
   auto write_buf2 = base::MakeRefCounted<StringIOBuffer>("bar");
@@ -667,11 +668,11 @@
   EXPECT_FALSE(stream);
 
   // Two socket reads are concatenated by WebSocketSpdyStreamAdapter.
-  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(3, rv);
   EXPECT_EQ("bar", base::StringPiece(read_buf->data(), rv));
 
-  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(3, rv);
   EXPECT_EQ("baz", base::StringPiece(read_buf->data(), rv));
 
@@ -736,7 +737,7 @@
   EXPECT_FALSE(stream);
 
   // Read remaining buffered data.  This will PostTask CallDelegateOnClose().
-  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionCallback());
+  rv = adapter.Read(read_buf.get(), kReadBufSize, CompletionOnceCallback());
   ASSERT_EQ(3, rv);
   EXPECT_EQ("bar", base::StringPiece(read_buf->data(), rv));
 
diff --git a/net/websockets/websocket_basic_stream_test.cc b/net/websockets/websocket_basic_stream_test.cc
index 29e8090c..b3a0e88 100644
--- a/net/websockets/websocket_basic_stream_test.cc
+++ b/net/websockets/websocket_basic_stream_test.cc
@@ -125,7 +125,8 @@
     scoped_refptr<MockTransportSocketParams> params;
     transport_socket->Init("a", params, MEDIUM, SocketTag(),
                            ClientSocketPool::RespectLimits::ENABLED,
-                           CompletionCallback(), &pool_, NetLogWithSource());
+                           CompletionOnceCallback(), &pool_,
+                           NetLogWithSource());
     return transport_socket;
   }
 
diff --git a/net/websockets/websocket_handshake_stream_create_helper_test.cc b/net/websockets/websocket_handshake_stream_create_helper_test.cc
index baabadb9..40f68bf7 100644
--- a/net/websockets/websocket_handshake_stream_create_helper_test.cc
+++ b/net/websockets/websocket_handshake_stream_create_helper_test.cc
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
-#include "net/base/completion_callback.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/net_errors.h"
 #include "net/base/proxy_server.h"
@@ -70,7 +69,7 @@
     auto socket_handle = std::make_unique<ClientSocketHandle>();
     socket_handle->Init("a", scoped_refptr<MockTransportSocketParams>(), MEDIUM,
                         SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
-                        CompletionCallback(), &pool_, NetLogWithSource());
+                        CompletionOnceCallback(), &pool_, NetLogWithSource());
     return socket_handle;
   }
 
diff --git a/ppapi/tests/test_browser_font.cc b/ppapi/tests/test_browser_font.cc
index 84fd7c1..9a56ea8 100644
--- a/ppapi/tests/test_browser_font.cc
+++ b/ppapi/tests/test_browser_font.cc
@@ -54,8 +54,12 @@
   int32_t length1 = font.MeasureText(pp::BrowserFontTextRun("WWW"));
   ASSERT_TRUE(length1 > 0);
   int32_t length2 = font.MeasureText(pp::BrowserFontTextRun("WWWWWWWW"));
-
   ASSERT_TRUE(length2 >= length1 * 2);
+
+  // Fallback font test.
+  int32_t length3 = font.MeasureText(pp::BrowserFontTextRun("こんにちは"));
+  ASSERT_TRUE(length3 > 0);
+
   PASS();
 }
 
diff --git a/remoting/resources/remoting_strings_bn.xtb b/remoting/resources/remoting_strings_bn.xtb
index abcc0c22..79c37aa3 100644
--- a/remoting/resources/remoting_strings_bn.xtb
+++ b/remoting/resources/remoting_strings_bn.xtb
@@ -136,6 +136,7 @@
 <translation id="405887016757208221">দূরবর্তী কম্পিউটারটি অধিবেশন আরম্ভ করতে ব্যর্থ হয়েছে। সমস্যা অব্যাহত থাকলে দয়া করে হোস্ট আবার কনফিগার করার চেষ্টা করুন।</translation>
 <translation id="4068946408131579958">সমস্ত সংযোগ</translation>
 <translation id="409800995205263688">দ্রষ্টব্য: নীতি সেটিং কেবলমাত্র আপনার নেটওয়ার্কে থাকা কম্পিউটারের মধ্যে সংযোগের অনুমতি দেয়৷</translation>
+<translation id="4126409073460786861">সেট-আপ হয়ে যাওয়ার পরে পৃষ্ঠাটি রিফ্রেশ করুন, তারপর আপনি ডিভাইস বেছে নিয়ে পিন নম্বর লিখে কম্পিউটারটি অ্যাক্সেস করতে পারেন</translation>
 <translation id="4145029455188493639"><ph name="EMAIL_ADDRESS" /> হিসেবে সাইন-ইন করেছেন।</translation>
 <translation id="4155497795971509630">প্রয়োজনীয় কিছু উপাদান অনুপস্থিত আছে৷ আপনি অতিসাম্প্রতিক সংস্করণটি ইনস্টল করেছেন কিনা দয়া করে তা নিশ্চিত করুন এবং আবার চেষ্টা করুন৷</translation>
 <translation id="4156740505453712750">এই কম্পিউটারে অ্যাক্সেস রক্ষা করতে, দয়া করে <ph name="BOLD_START" />অন্তত ছয় সংখ্যার<ph name="BOLD_END" /> একটি পিন বেছে নিন৷ অন্য কোনো লোকেশন থেকে সংযুক্ত হতে এই পিন এর প্রয়োজন হবে৷</translation>
@@ -270,6 +271,7 @@
 <translation id="6998989275928107238">প্রাপক:</translation>
 <translation id="7019153418965365059">অস্বীকৃত হোস্ট ত্রুটি: <ph name="HOST_OFFLINE_REASON" />।</translation>
 <translation id="701976023053394610">রিমোট সহায়তা</translation>
+<translation id="7026930240735156896">রিমোট অ্যাক্সেসের জন্য আপনার কম্পিউটার সেট-আপ করতে নির্দেশাবলী অনুসরণ করুন</translation>
 <translation id="7038683108611689168">আমাদের ব্যবহার পরিসংখ্যান এবং ক্র্যাশ প্রতিবেদনগুলি সংগ্রহের অনুমতি দিয়ে, Chromoting এর উন্নতিতে আমাদের সাহায্য করুন৷</translation>
 <translation id="7067321367069083429">স্ক্রিন একটি টাচ স্ক্রিনের মত কাজ করে</translation>
 <translation id="7116737094673640201">Chrome দূরবর্তী ডেস্কটপে স্বাগতম</translation>
diff --git a/remoting/resources/remoting_strings_es-419.xtb b/remoting/resources/remoting_strings_es-419.xtb
index a7465b59..a661c20e 100644
--- a/remoting/resources/remoting_strings_es-419.xtb
+++ b/remoting/resources/remoting_strings_es-419.xtb
@@ -136,6 +136,7 @@
 <translation id="405887016757208221">La computadora remota no pudo inicializar la sesión. Si el problema persiste, intenta volver a configurar el host.</translation>
 <translation id="4068946408131579958">Todas las conexiones</translation>
 <translation id="409800995205263688">NOTA: La configuración de la política solo permite conexiones entre computadoras que estén dentro de tu red.</translation>
+<translation id="4126409073460786861">Después de completar la configuración, actualiza esta página. Luego, para acceder a la computadora, deberás elegir tu dispositivo y escribir el PIN.</translation>
 <translation id="4145029455188493639">Accediste como <ph name="EMAIL_ADDRESS" />.</translation>
 <translation id="4155497795971509630">Faltan algunos de los componentes necesarios. Asegúrate de tener instalada la última versión del software y vuelve a intentarlo.</translation>
 <translation id="4156740505453712750">Debes elegir un PIN de <ph name="BOLD_START" />al menos seis dígitos<ph name="BOLD_END" /> para proteger el acceso a esta computadora. Se solicitará ese PIN cada vez que se establezca una conexión con esa computadora desde otra ubicación.</translation>
@@ -270,6 +271,7 @@
 <translation id="6998989275928107238">A</translation>
 <translation id="7019153418965365059">Error de host no reconocido: <ph name="HOST_OFFLINE_REASON" /></translation>
 <translation id="701976023053394610">Asistencia remota</translation>
+<translation id="7026930240735156896">Sigue las instrucciones para configurar la computadora para acceder de forma remota.</translation>
 <translation id="7038683108611689168">Ayúdanos a mejorar la aplicación Chromoting permitiéndonos recopilar estadísticas de uso e informes sobre fallos.</translation>
 <translation id="7067321367069083429">La pantalla cuenta con función táctil</translation>
 <translation id="7116737094673640201">Bienvenido a Escritorio remoto de Chrome</translation>
diff --git a/remoting/resources/remoting_strings_te.xtb b/remoting/resources/remoting_strings_te.xtb
index fd867d4..844e350 100644
--- a/remoting/resources/remoting_strings_te.xtb
+++ b/remoting/resources/remoting_strings_te.xtb
@@ -136,6 +136,7 @@
 <translation id="405887016757208221">సెషన్‌ను ప్రారంభించడంలో రిమోట్ కంప్యూటర్ విఫలమైంది. సమస్య కొనసాగితే, దయచేసి హోస్ట్‌ను మళ్లీ కాన్ఫిగర్ చేసి ప్రయత్నించండి.</translation>
 <translation id="4068946408131579958">అన్ని కనెక్షన్‌లు</translation>
 <translation id="409800995205263688">గమనిక: విధాన సెట్టింగ్‌లు మీ నెట్‌వర్క్‌లోని కంప్యూటర్‌ల మధ్య మాత్రమే కనెక్షన్‌లను అనుమతిస్తాయి.</translation>
+<translation id="4126409073460786861">సెటప్ పూర్తయిన తర్వాత, పేజీని రీఫ్రెష్ చేయండి, అప్పుడు మీరు మీ పరికరాన్ని ఎంచుకుని, PINను నమోదు చేయడం ద్వారా మీ కంప్యూటర్‌ను యాక్సెస్ చేయగలుగుతారు</translation>
 <translation id="4145029455188493639"><ph name="EMAIL_ADDRESS" /> వలె సైన్ ఇన్ చేసారు.</translation>
 <translation id="4155497795971509630">కొన్ని ఆవశ్యక అంశాలు లేవు. దయచేసి మీరు తాజా సాఫ్ట్‌వేర్ సంస్కరణను ఇన్‌స్టాల్ చేసారని నిర్ధారించుకొని, ఆపై మళ్లీ ప్రయత్నించండి.</translation>
 <translation id="4156740505453712750">ఈ కంప్యూటర్‌కు ప్రాప్యతను రక్షించడానికి, దయచేసి <ph name="BOLD_START" />కనీసం ఆరు అంకెలు<ph name="BOLD_END" /> కలిగి ఉన్న PINను ఎంచుకోండి. ఈ PIN వేరొక స్థానం నుండి కనెక్ట్ చేస్తున్నప్పుడు అవసరం అవుతుంది.</translation>
@@ -270,6 +271,7 @@
 <translation id="6998989275928107238">స్వీకర్త</translation>
 <translation id="7019153418965365059">గుర్తుపట్టని హోస్ట్ లోపం: <ph name="HOST_OFFLINE_REASON" />.</translation>
 <translation id="701976023053394610">రిమోట్ సహాయం</translation>
+<translation id="7026930240735156896">మీ కంప్యూటర్‌ను రిమోట్ యాక్సెస్ కోసం సెటప్ చేయడానికి సూచనలను పాటించండి</translation>
 <translation id="7038683108611689168">వినియోగ గణాంకాలను మరియు క్రాష్ నివేదికలను సేకరించడానికి మమ్మల్ని అనుమతించడం ద్వారా Chromotingను మెరుగుపరచడంలో మాకు సహాయపడండి.</translation>
 <translation id="7067321367069083429">స్క్రీన్, టచ్ స్క్రీన్ వలె పనిచేస్తుంది</translation>
 <translation id="7116737094673640201">Chrome రిమోట్ డెస్క్‌టాప్‌కు స్వాగతం</translation>
diff --git a/remoting/resources/remoting_strings_zh-CN.xtb b/remoting/resources/remoting_strings_zh-CN.xtb
index 1f0f6c6..215169d 100644
--- a/remoting/resources/remoting_strings_zh-CN.xtb
+++ b/remoting/resources/remoting_strings_zh-CN.xtb
@@ -136,6 +136,7 @@
 <translation id="405887016757208221">远程计算机未能将该会话初始化。如果问题仍然存在,请尝试重新配置主机。</translation>
 <translation id="4068946408131579958">所有连接</translation>
 <translation id="409800995205263688">注意:策略设置仅允许您网络内的计算机之间建立连接。</translation>
+<translation id="4126409073460786861">请在设置完毕后刷新此页面,然后您只需选择设备并输入相应的 PIN 码,便可访问这台计算机</translation>
 <translation id="4145029455188493639">以 <ph name="EMAIL_ADDRESS" /> 的身份登录。</translation>
 <translation id="4155497795971509630">缺少某些必需的组件。请确保您已安装该软件的最新版本,然后重试。</translation>
 <translation id="4156740505453712750">为防止他人擅自访问此计算机,请选用一个<ph name="BOLD_START" />至少 6 位数<ph name="BOLD_END" />的 PIN。当从其他位置连接时,将需要输入此 PIN。</translation>
@@ -270,6 +271,7 @@
 <translation id="6998989275928107238">至</translation>
 <translation id="7019153418965365059">无法识别的主机错误:<ph name="HOST_OFFLINE_REASON" />。</translation>
 <translation id="701976023053394610">远程协助</translation>
+<translation id="7026930240735156896">按照说明设置计算机以供远程访问</translation>
 <translation id="7038683108611689168">允许我们收集使用情况统计信息和崩溃报告,以帮助改进 Chrome 远程访问。</translation>
 <translation id="7067321367069083429">屏幕充当触摸屏</translation>
 <translation id="7116737094673640201">欢迎使用 Chrome 远程桌面</translation>
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 98822642..3374963 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -38,9 +38,8 @@
     "delay_buffer.h",
     "device_notifier.cc",
     "device_notifier.h",
-    "group_coordinator.cc",
+    "group_coordinator-impl.h",
     "group_coordinator.h",
-    "group_member.h",
     "in_process_audio_manager_accessor.cc",
     "in_process_audio_manager_accessor.h",
     "input_controller.cc",
@@ -57,6 +56,9 @@
     "log_factory_adapter.h",
     "log_factory_manager.cc",
     "log_factory_manager.h",
+    "loopback_coordinator.cc",
+    "loopback_coordinator.h",
+    "loopback_group_member.h",
     "loopback_stream.cc",
     "loopback_stream.h",
     "output_controller.cc",
@@ -124,9 +126,11 @@
     "test/debug_recording_session_unittest.cc",
     "test/fake_consumer.cc",
     "test/fake_consumer.h",
-    "test/fake_group_member.cc",
-    "test/fake_group_member.h",
+    "test/fake_loopback_group_member.cc",
+    "test/fake_loopback_group_member.h",
     "test/in_process_service_test.cc",
+    "test/mock_group_coordinator.cc",
+    "test/mock_group_coordinator.h",
     "test/mock_group_member.cc",
     "test/mock_group_member.h",
     "test/mock_log.cc",
diff --git a/services/audio/group_coordinator-impl.h b/services/audio/group_coordinator-impl.h
new file mode 100644
index 0000000..dab5633
--- /dev/null
+++ b/services/audio/group_coordinator-impl.h
@@ -0,0 +1,141 @@
+// 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 SERVICES_AUDIO_GROUP_COORDINATOR_IMPL_H_
+#define SERVICES_AUDIO_GROUP_COORDINATOR_IMPL_H_
+
+namespace audio {
+
+template <typename Member>
+GroupCoordinator<Member>::GroupCoordinator() {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+template <typename Member>
+GroupCoordinator<Member>::~GroupCoordinator() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(groups_.empty());
+}
+
+template <typename Member>
+void GroupCoordinator<Member>::RegisterMember(
+    const base::UnguessableToken& group_id,
+    Member* member) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(member);
+
+  const auto it = FindGroup(group_id);
+  std::vector<Member*>& members = it->second.members;
+  DCHECK(!base::ContainsValue(members, member));
+  members.push_back(member);
+
+  for (Observer* observer : it->second.observers) {
+    observer->OnMemberJoinedGroup(member);
+  }
+}
+
+template <typename Member>
+void GroupCoordinator<Member>::UnregisterMember(
+    const base::UnguessableToken& group_id,
+    Member* member) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(member);
+
+  const auto group_it = FindGroup(group_id);
+  std::vector<Member*>& members = group_it->second.members;
+  const auto member_it = std::find(members.begin(), members.end(), member);
+  DCHECK(member_it != members.end());
+  members.erase(member_it);
+
+  for (Observer* observer : group_it->second.observers) {
+    observer->OnMemberLeftGroup(member);
+  }
+
+  MaybePruneGroupMapEntry(group_it);
+}
+
+template <typename Member>
+void GroupCoordinator<Member>::AddObserver(
+    const base::UnguessableToken& group_id,
+    Observer* observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(observer);
+
+  std::vector<Observer*>& observers = FindGroup(group_id)->second.observers;
+  DCHECK(!base::ContainsValue(observers, observer));
+  observers.push_back(observer);
+}
+
+template <typename Member>
+void GroupCoordinator<Member>::RemoveObserver(
+    const base::UnguessableToken& group_id,
+    Observer* observer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(observer);
+
+  const auto group_it = FindGroup(group_id);
+  std::vector<Observer*>& observers = group_it->second.observers;
+  const auto it = std::find(observers.begin(), observers.end(), observer);
+  DCHECK(it != observers.end());
+  observers.erase(it);
+
+  MaybePruneGroupMapEntry(group_it);
+}
+
+template <typename Member>
+const std::vector<Member*>& GroupCoordinator<Member>::GetCurrentMembers(
+    const base::UnguessableToken& group_id) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  for (const auto& entry : groups_) {
+    if (entry.first == group_id) {
+      return entry.second.members;
+    }
+  }
+
+  static const std::vector<Member*> empty_set;
+  return empty_set;
+}
+
+template <typename Member>
+typename GroupCoordinator<Member>::GroupMap::iterator
+GroupCoordinator<Member>::FindGroup(const base::UnguessableToken& group_id) {
+  for (auto it = groups_.begin(); it != groups_.end(); ++it) {
+    if (it->first == group_id) {
+      return it;
+    }
+  }
+
+  // Group does not exist. Create a new entry.
+  groups_.emplace_back();
+  const auto new_it = groups_.end() - 1;
+  new_it->first = group_id;
+  return new_it;
+}
+
+template <typename Member>
+void GroupCoordinator<Member>::MaybePruneGroupMapEntry(
+    typename GroupMap::iterator it) {
+  if (it->second.members.empty() && it->second.observers.empty()) {
+    groups_.erase(it);
+  }
+}
+
+template <typename Member>
+GroupCoordinator<Member>::Observer::~Observer() = default;
+
+template <typename Member>
+GroupCoordinator<Member>::Group::Group() = default;
+template <typename Member>
+GroupCoordinator<Member>::Group::~Group() = default;
+template <typename Member>
+GroupCoordinator<Member>::Group::Group(
+    GroupCoordinator<Member>::Group&& other) = default;
+template <typename Member>
+typename GroupCoordinator<Member>::Group& GroupCoordinator<Member>::Group::
+operator=(GroupCoordinator::Group&& other) = default;
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_GROUP_COORDINATOR_IMPL_H_
diff --git a/services/audio/group_coordinator.cc b/services/audio/group_coordinator.cc
deleted file mode 100644
index 1533b81..0000000
--- a/services/audio/group_coordinator.cc
+++ /dev/null
@@ -1,121 +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 "services/audio/group_coordinator.h"
-
-#include <algorithm>
-
-#include "base/stl_util.h"
-#include "services/audio/group_member.h"
-
-namespace audio {
-
-GroupCoordinator::GroupCoordinator() {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-GroupCoordinator::~GroupCoordinator() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(groups_.empty());
-}
-
-void GroupCoordinator::RegisterGroupMember(GroupMember* member) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(member);
-
-  const auto it = FindGroup(member->GetGroupId());
-  std::vector<GroupMember*>& members = it->second.members;
-  DCHECK(!base::ContainsValue(members, member));
-  members.push_back(member);
-
-  for (Observer* observer : it->second.observers) {
-    observer->OnMemberJoinedGroup(member);
-  }
-}
-
-void GroupCoordinator::UnregisterGroupMember(GroupMember* member) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(member);
-
-  const auto group_it = FindGroup(member->GetGroupId());
-  std::vector<GroupMember*>& members = group_it->second.members;
-  const auto member_it = std::find(members.begin(), members.end(), member);
-  DCHECK(member_it != members.end());
-  members.erase(member_it);
-
-  for (Observer* observer : group_it->second.observers) {
-    observer->OnMemberLeftGroup(member);
-  }
-
-  MaybePruneGroupMapEntry(group_it);
-}
-
-void GroupCoordinator::AddObserver(const base::UnguessableToken& group_id,
-                                   Observer* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(observer);
-
-  std::vector<Observer*>& observers = FindGroup(group_id)->second.observers;
-  DCHECK(!base::ContainsValue(observers, observer));
-  observers.push_back(observer);
-}
-
-void GroupCoordinator::RemoveObserver(const base::UnguessableToken& group_id,
-                                      Observer* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(observer);
-
-  const auto group_it = FindGroup(group_id);
-  std::vector<Observer*>& observers = group_it->second.observers;
-  const auto it = std::find(observers.begin(), observers.end(), observer);
-  DCHECK(it != observers.end());
-  observers.erase(it);
-
-  MaybePruneGroupMapEntry(group_it);
-}
-
-const std::vector<GroupMember*>& GroupCoordinator::GetCurrentMembers(
-    const base::UnguessableToken& group_id) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  for (const auto& entry : groups_) {
-    if (entry.first == group_id) {
-      return entry.second.members;
-    }
-  }
-
-  static const std::vector<GroupMember*> empty_set;
-  return empty_set;
-}
-
-GroupCoordinator::GroupMap::iterator GroupCoordinator::FindGroup(
-    const base::UnguessableToken& group_id) {
-  for (auto it = groups_.begin(); it != groups_.end(); ++it) {
-    if (it->first == group_id) {
-      return it;
-    }
-  }
-
-  // Group does not exist. Create a new entry.
-  groups_.emplace_back();
-  const auto new_it = groups_.end() - 1;
-  new_it->first = group_id;
-  return new_it;
-}
-
-void GroupCoordinator::MaybePruneGroupMapEntry(GroupMap::iterator it) {
-  if (it->second.members.empty() && it->second.observers.empty()) {
-    groups_.erase(it);
-  }
-}
-
-GroupCoordinator::Observer::~Observer() = default;
-
-GroupCoordinator::Group::Group() = default;
-GroupCoordinator::Group::~Group() = default;
-GroupCoordinator::Group::Group(GroupCoordinator::Group&& other) = default;
-GroupCoordinator::Group& GroupCoordinator::Group::operator=(
-    GroupCoordinator::Group&& other) = default;
-
-}  // namespace audio
diff --git a/services/audio/group_coordinator.h b/services/audio/group_coordinator.h
index 8bd9bf4c..14f49c49 100644
--- a/services/audio/group_coordinator.h
+++ b/services/audio/group_coordinator.h
@@ -5,27 +5,28 @@
 #ifndef SERVICES_AUDIO_GROUP_COORDINATOR_H_
 #define SERVICES_AUDIO_GROUP_COORDINATOR_H_
 
+#include <algorithm>
 #include <utility>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/sequence_checker.h"
+#include "base/stl_util.h"
 #include "base/unguessable_token.h"
 
 namespace audio {
 
-class GroupMember;
-
 // Manages a registry of group members and notifies observers as membership in
 // the group changes.
+template <typename Member>
 class GroupCoordinator {
  public:
   // Interface for entities that wish to montior and take action as members
   // join/leave a particular group.
   class Observer {
    public:
-    virtual void OnMemberJoinedGroup(GroupMember* member) = 0;
-    virtual void OnMemberLeftGroup(GroupMember* member) = 0;
+    virtual void OnMemberJoinedGroup(Member* member) = 0;
+    virtual void OnMemberLeftGroup(Member* member) = 0;
 
    protected:
     virtual ~Observer();
@@ -35,9 +36,9 @@
   ~GroupCoordinator();
 
   // Registers/Unregisters a group |member|. The member must remain valid until
-  // after UnregisterGroupMember() is called.
-  void RegisterGroupMember(GroupMember* member);
-  void UnregisterGroupMember(GroupMember* member);
+  // after UnregisterMember() is called.
+  void RegisterMember(const base::UnguessableToken& group_id, Member* member);
+  void UnregisterMember(const base::UnguessableToken& group_id, Member* member);
 
   void AddObserver(const base::UnguessableToken& group_id, Observer* observer);
   void RemoveObserver(const base::UnguessableToken& group_id,
@@ -46,12 +47,12 @@
   // Returns the current members in the group having the given |group_id|. Note
   // that the validity of the returned reference is uncertain once any of the
   // other non-const methods are called.
-  const std::vector<GroupMember*>& GetCurrentMembers(
+  const std::vector<Member*>& GetCurrentMembers(
       const base::UnguessableToken& group_id) const;
 
  private:
   struct Group {
-    std::vector<GroupMember*> members;
+    std::vector<Member*> members;
     std::vector<Observer*> observers;
 
     Group();
@@ -67,10 +68,10 @@
 
   // Returns an iterator to the entry associated with the given |group_id|,
   // creating a new one if necessary.
-  GroupMap::iterator FindGroup(const base::UnguessableToken& group_id);
+  typename GroupMap::iterator FindGroup(const base::UnguessableToken& group_id);
 
   // Deletes the entry in |groups_| if it has no members or observers remaining.
-  void MaybePruneGroupMapEntry(GroupMap::iterator it);
+  void MaybePruneGroupMapEntry(typename GroupMap::iterator it);
 
   GroupMap groups_;
 
diff --git a/services/audio/group_coordinator_unittest.cc b/services/audio/group_coordinator_unittest.cc
index 087877a..39eb6f5 100644
--- a/services/audio/group_coordinator_unittest.cc
+++ b/services/audio/group_coordinator_unittest.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "services/audio/group_coordinator.h"
+#include "services/audio/test/mock_group_coordinator.h"
 
 #include "base/stl_util.h"
 #include "base/unguessable_token.h"
-#include "services/audio/group_member.h"
 #include "services/audio/test/mock_group_member.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,28 +20,29 @@
 using testing::_;
 
 namespace audio {
+
 namespace {
 
-class MockGroupObserver : public GroupCoordinator::Observer {
+class MockGroupObserver : public GroupCoordinator<MockGroupMember>::Observer {
  public:
   MockGroupObserver() = default;
   ~MockGroupObserver() override = default;
 
-  MOCK_METHOD1(OnMemberJoinedGroup, void(GroupMember* member));
-  MOCK_METHOD1(OnMemberLeftGroup, void(GroupMember* member));
+  MOCK_METHOD1(OnMemberJoinedGroup, void(MockGroupMember* member));
+  MOCK_METHOD1(OnMemberLeftGroup, void(MockGroupMember* member));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockGroupObserver);
 };
 
 TEST(GroupCoordinatorTest, NeverUsed) {
-  GroupCoordinator coordinator;
+  GroupCoordinator<MockGroupMember> coordinator;
 }
 
 TEST(GroupCoordinatorTest, RegistersMembersInSameGroup) {
   const UnguessableToken group_id = UnguessableToken::Create();
-  StrictMock<MockGroupMember> member1(group_id);
-  StrictMock<MockGroupMember> member2(group_id);
+  StrictMock<MockGroupMember> member1;
+  StrictMock<MockGroupMember> member2;
 
   // An observer should see each member join and leave the group once.
   StrictMock<MockGroupObserver> observer;
@@ -56,12 +56,12 @@
   EXPECT_CALL(observer, OnMemberLeftGroup(&member2))
       .InSequence(join_leave_sequence);
 
-  GroupCoordinator coordinator;
+  GroupCoordinator<MockGroupMember> coordinator;
   coordinator.AddObserver(group_id, &observer);
-  coordinator.RegisterGroupMember(&member1);
-  coordinator.RegisterGroupMember(&member2);
+  coordinator.RegisterMember(group_id, &member1);
+  coordinator.RegisterMember(group_id, &member2);
 
-  const std::vector<GroupMember*>& members =
+  const std::vector<MockGroupMember*>& members =
       coordinator.GetCurrentMembers(group_id);
   EXPECT_EQ(2u, members.size());
   EXPECT_TRUE(base::ContainsValue(members, &member1));
@@ -69,8 +69,8 @@
   EXPECT_TRUE(
       coordinator.GetCurrentMembers(UnguessableToken::Create()).empty());
 
-  coordinator.UnregisterGroupMember(&member1);
-  coordinator.UnregisterGroupMember(&member2);
+  coordinator.UnregisterMember(group_id, &member1);
+  coordinator.UnregisterMember(group_id, &member2);
   EXPECT_TRUE(coordinator.GetCurrentMembers(group_id).empty());
 
   coordinator.RemoveObserver(group_id, &observer);
@@ -79,8 +79,8 @@
 
 TEST(GroupCoordinatorTest, RegistersMembersInDifferentGroups) {
   const UnguessableToken group_id_a = UnguessableToken::Create();
-  StrictMock<MockGroupMember> member_a_1(group_id_a);
-  StrictMock<MockGroupMember> member_a_2(group_id_a);
+  StrictMock<MockGroupMember> member_a_1;
+  StrictMock<MockGroupMember> member_a_2;
 
   StrictMock<MockGroupObserver> observer_a;
   Sequence join_leave_sequence_a;
@@ -94,7 +94,7 @@
       .InSequence(join_leave_sequence_a);
 
   const UnguessableToken group_id_b = UnguessableToken::Create();
-  StrictMock<MockGroupMember> member_b_1(group_id_b);
+  StrictMock<MockGroupMember> member_b_1;
 
   StrictMock<MockGroupObserver> observer_b;
   Sequence join_leave_sequence_b;
@@ -103,30 +103,30 @@
   EXPECT_CALL(observer_b, OnMemberLeftGroup(&member_b_1))
       .InSequence(join_leave_sequence_b);
 
-  GroupCoordinator coordinator;
+  GroupCoordinator<MockGroupMember> coordinator;
   coordinator.AddObserver(group_id_a, &observer_a);
   coordinator.AddObserver(group_id_b, &observer_b);
-  coordinator.RegisterGroupMember(&member_a_1);
-  coordinator.RegisterGroupMember(&member_b_1);
-  coordinator.RegisterGroupMember(&member_a_2);
-  const std::vector<GroupMember*>& members_a =
+  coordinator.RegisterMember(group_id_a, &member_a_1);
+  coordinator.RegisterMember(group_id_b, &member_b_1);
+  coordinator.RegisterMember(group_id_a, &member_a_2);
+  const std::vector<MockGroupMember*>& members_a =
       coordinator.GetCurrentMembers(group_id_a);
   EXPECT_EQ(2u, members_a.size());
   EXPECT_TRUE(base::ContainsValue(members_a, &member_a_1));
   EXPECT_TRUE(base::ContainsValue(members_a, &member_a_2));
-  EXPECT_EQ(std::vector<GroupMember*>({&member_b_1}),
+  EXPECT_EQ(std::vector<MockGroupMember*>({&member_b_1}),
             coordinator.GetCurrentMembers(group_id_b));
   EXPECT_TRUE(
       coordinator.GetCurrentMembers(UnguessableToken::Create()).empty());
 
-  coordinator.UnregisterGroupMember(&member_a_1);
-  EXPECT_EQ(std::vector<GroupMember*>({&member_a_2}),
+  coordinator.UnregisterMember(group_id_a, &member_a_1);
+  EXPECT_EQ(std::vector<MockGroupMember*>({&member_a_2}),
             coordinator.GetCurrentMembers(group_id_a));
 
-  coordinator.UnregisterGroupMember(&member_b_1);
+  coordinator.UnregisterMember(group_id_b, &member_b_1);
   EXPECT_TRUE(coordinator.GetCurrentMembers(group_id_b).empty());
 
-  coordinator.UnregisterGroupMember(&member_a_2);
+  coordinator.UnregisterMember(group_id_a, &member_a_2);
   EXPECT_TRUE(coordinator.GetCurrentMembers(group_id_a).empty());
 
   coordinator.RemoveObserver(group_id_a, &observer_a);
@@ -137,14 +137,14 @@
 
 TEST(GroupCoordinatorTest, TracksMembersWithoutAnObserverPresent) {
   const UnguessableToken group_id = UnguessableToken::Create();
-  StrictMock<MockGroupMember> member1(group_id);
-  StrictMock<MockGroupMember> member2(group_id);
+  StrictMock<MockGroupMember> member1;
+  StrictMock<MockGroupMember> member2;
 
-  GroupCoordinator coordinator;
-  coordinator.RegisterGroupMember(&member1);
-  coordinator.RegisterGroupMember(&member2);
+  GroupCoordinator<MockGroupMember> coordinator;
+  coordinator.RegisterMember(group_id, &member1);
+  coordinator.RegisterMember(group_id, &member2);
 
-  const std::vector<GroupMember*>& members =
+  const std::vector<MockGroupMember*>& members =
       coordinator.GetCurrentMembers(group_id);
   EXPECT_EQ(2u, members.size());
   EXPECT_TRUE(base::ContainsValue(members, &member1));
@@ -152,15 +152,15 @@
   EXPECT_TRUE(
       coordinator.GetCurrentMembers(UnguessableToken::Create()).empty());
 
-  coordinator.UnregisterGroupMember(&member1);
-  coordinator.UnregisterGroupMember(&member2);
+  coordinator.UnregisterMember(group_id, &member1);
+  coordinator.UnregisterMember(group_id, &member2);
   EXPECT_TRUE(coordinator.GetCurrentMembers(group_id).empty());
 }
 
 TEST(GroupCoordinatorTest, NotifiesOnlyWhileObserving) {
   const UnguessableToken group_id = UnguessableToken::Create();
-  StrictMock<MockGroupMember> member1(group_id);
-  StrictMock<MockGroupMember> member2(group_id);
+  StrictMock<MockGroupMember> member1;
+  StrictMock<MockGroupMember> member2;
 
   // The observer will only be around at the time when member2 joins the group
   // and when member1 leaves the group.
@@ -173,28 +173,28 @@
       .InSequence(join_leave_sequence);
   EXPECT_CALL(observer, OnMemberLeftGroup(&member2)).Times(0);
 
-  GroupCoordinator coordinator;
-  coordinator.RegisterGroupMember(&member1);
-  EXPECT_EQ(std::vector<GroupMember*>({&member1}),
+  GroupCoordinator<MockGroupMember> coordinator;
+  coordinator.RegisterMember(group_id, &member1);
+  EXPECT_EQ(std::vector<MockGroupMember*>({&member1}),
             coordinator.GetCurrentMembers(group_id));
 
   coordinator.AddObserver(group_id, &observer);
-  coordinator.RegisterGroupMember(&member2);
-  const std::vector<GroupMember*>& members =
+  coordinator.RegisterMember(group_id, &member2);
+  const std::vector<MockGroupMember*>& members =
       coordinator.GetCurrentMembers(group_id);
   EXPECT_EQ(2u, members.size());
   EXPECT_TRUE(base::ContainsValue(members, &member1));
   EXPECT_TRUE(base::ContainsValue(members, &member2));
 
-  coordinator.UnregisterGroupMember(&member1);
-  EXPECT_EQ(std::vector<GroupMember*>({&member2}),
+  coordinator.UnregisterMember(group_id, &member1);
+  EXPECT_EQ(std::vector<MockGroupMember*>({&member2}),
             coordinator.GetCurrentMembers(group_id));
 
   coordinator.RemoveObserver(group_id, &observer);
-  EXPECT_EQ(std::vector<GroupMember*>({&member2}),
+  EXPECT_EQ(std::vector<MockGroupMember*>({&member2}),
             coordinator.GetCurrentMembers(group_id));
 
-  coordinator.UnregisterGroupMember(&member2);
+  coordinator.UnregisterMember(group_id, &member2);
   EXPECT_TRUE(coordinator.GetCurrentMembers(group_id).empty());
 }
 
diff --git a/services/audio/group_member.h b/services/audio/group_member.h
deleted file mode 100644
index 28df1c40..0000000
--- a/services/audio/group_member.h
+++ /dev/null
@@ -1,68 +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 SERVICES_AUDIO_GROUP_MEMBER_H_
-#define SERVICES_AUDIO_GROUP_MEMBER_H_
-
-#include "base/time/time.h"
-
-namespace base {
-class UnguessableToken;
-}
-
-namespace media {
-class AudioBus;
-class AudioParameters;
-}  // namespace media
-
-namespace audio {
-
-// Interface for accessing signal data and controlling a members of an audio
-// group. A group is defined by a common group identifier that all members
-// share.
-//
-// The purpose of the grouping concept is to allow a feature to identify all
-// audio flows that come from the same logical unit, such as a browser tab. The
-// audio flows can then be duplicated, or other group-wide control exercised on
-// all members (such as audio muting).
-class GroupMember {
- public:
-  class Snooper {
-   public:
-    // Provides read-only access to the data flowing through a GroupMember.
-    virtual void OnData(const media::AudioBus& audio_bus,
-                        base::TimeTicks reference_time,
-                        double volume) = 0;
-
-   protected:
-    virtual ~Snooper() = default;
-  };
-
-  // Returns the string identifier of the group. This must not change for the
-  // lifetime of this group member.
-  virtual const base::UnguessableToken& GetGroupId() = 0;
-
-  // Returns the audio parameters of the snoopable audio data. The parameters
-  // must not change for the lifetime of this group member, but can be different
-  // than those of other members.
-  virtual const media::AudioParameters& GetAudioParameters() = 0;
-
-  // Starts/Stops snooping on the audio data flowing through this group member.
-  virtual void StartSnooping(Snooper* snooper) = 0;
-  virtual void StopSnooping(Snooper* snooper) = 0;
-
-  // Starts/Stops muting of the outbound audio signal from this group member.
-  // However, the audio data being sent to Snoopers should be the original,
-  // unmuted audio. Note that an equal number of start versus stop calls here is
-  // not required, and the implementation should ignore redundant calls.
-  virtual void StartMuting() = 0;
-  virtual void StopMuting() = 0;
-
- protected:
-  virtual ~GroupMember() = default;
-};
-
-}  // namespace audio
-
-#endif  // SERVICES_AUDIO_GROUP_MEMBER_H_
diff --git a/services/audio/local_muter.cc b/services/audio/local_muter.cc
index 17e3d26..290c51f 100644
--- a/services/audio/local_muter.cc
+++ b/services/audio/local_muter.cc
@@ -6,17 +6,18 @@
 
 #include <utility>
 
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_group_member.h"
 
 namespace audio {
 
-LocalMuter::LocalMuter(GroupCoordinator* coordinator,
+LocalMuter::LocalMuter(LoopbackCoordinator* coordinator,
                        const base::UnguessableToken& group_id)
     : coordinator_(coordinator), group_id_(group_id) {
   DCHECK(coordinator_);
 
   coordinator_->AddObserver(group_id_, this);
-  for (GroupMember* member : coordinator_->GetCurrentMembers(group_id_)) {
+  for (LoopbackGroupMember* member :
+       coordinator_->GetCurrentMembers(group_id_)) {
     member->StartMuting();
   }
 
@@ -27,7 +28,8 @@
 LocalMuter::~LocalMuter() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  for (GroupMember* member : coordinator_->GetCurrentMembers(group_id_)) {
+  for (LoopbackGroupMember* member :
+       coordinator_->GetCurrentMembers(group_id_)) {
     member->StopMuting();
   }
 
@@ -46,13 +48,13 @@
   bindings_.AddBinding(this, std::move(request));
 }
 
-void LocalMuter::OnMemberJoinedGroup(GroupMember* member) {
+void LocalMuter::OnMemberJoinedGroup(LoopbackGroupMember* member) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   member->StartMuting();
 }
 
-void LocalMuter::OnMemberLeftGroup(GroupMember* member) {
+void LocalMuter::OnMemberLeftGroup(LoopbackGroupMember* member) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // No change to muting state.
diff --git a/services/audio/local_muter.h b/services/audio/local_muter.h
index 225b213..9b398e76 100644
--- a/services/audio/local_muter.h
+++ b/services/audio/local_muter.h
@@ -10,19 +10,20 @@
 #include "base/sequence_checker.h"
 #include "base/unguessable_token.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
-#include "services/audio/group_coordinator.h"
+#include "services/audio/loopback_coordinator.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
 
 namespace audio {
 
-class GroupMember;
+class LoopbackGroupMember;
 
 // Mutes a group of streams, from construction time until destruction time. In
 // between, LocalMuter ensures new group members are also muted. Holds all
 // mojom::LocalMuter bindings.
-class LocalMuter : public mojom::LocalMuter, public GroupCoordinator::Observer {
+class LocalMuter : public mojom::LocalMuter,
+                   public LoopbackCoordinator::Observer {
  public:
-  LocalMuter(GroupCoordinator* coordinator,
+  LocalMuter(LoopbackCoordinator* coordinator,
              const base::UnguessableToken& group_id);
 
   ~LocalMuter() final;
@@ -34,15 +35,15 @@
   void SetAllBindingsLostCallback(base::OnceClosure callback);
   void AddBinding(mojom::LocalMuterAssociatedRequest request);
 
-  // GroupCoordinator::Observer implementation.
-  void OnMemberJoinedGroup(GroupMember* member) final;
-  void OnMemberLeftGroup(GroupMember* member) final;
+  // LoopbackCoordinator::Observer implementation.
+  void OnMemberJoinedGroup(LoopbackGroupMember* member) final;
+  void OnMemberLeftGroup(LoopbackGroupMember* member) final;
 
  private:
   // Runs the |all_bindings_lost_callback_| when |bindings_| becomes empty.
   void OnBindingLost();
 
-  GroupCoordinator* const coordinator_;
+  LoopbackCoordinator* const coordinator_;
   const base::UnguessableToken group_id_;
 
   mojo::AssociatedBindingSet<mojom::LocalMuter> bindings_;
diff --git a/services/audio/local_muter_unittest.cc b/services/audio/local_muter_unittest.cc
index 5e20479..7dd0fb6 100644
--- a/services/audio/local_muter_unittest.cc
+++ b/services/audio/local_muter_unittest.cc
@@ -9,8 +9,8 @@
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/unguessable_token.h"
-#include "services/audio/group_coordinator.h"
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_coordinator.h"
+#include "services/audio/loopback_group_member.h"
 #include "services/audio/test/mock_group_member.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,24 +25,24 @@
 namespace {
 
 TEST(LocalMuterTest, MutesExistingMembers) {
-  GroupCoordinator coordinator;
+  LoopbackCoordinator coordinator;
 
   // Create a group with two members.
   const UnguessableToken group_id = UnguessableToken::Create();
-  StrictMock<MockGroupMember> member1(group_id);
-  StrictMock<MockGroupMember> member2(group_id);
+  StrictMock<MockGroupMember> member1;
+  StrictMock<MockGroupMember> member2;
 
   // Create another group with one member, which should never have its mute
   // state changed.
   const UnguessableToken other_group_id = UnguessableToken::Create();
   ASSERT_NE(group_id, other_group_id);
-  StrictMock<MockGroupMember> non_member(other_group_id);
+  StrictMock<MockGroupMember> non_member;
   EXPECT_CALL(non_member, StartMuting()).Times(0);
   EXPECT_CALL(non_member, StopMuting()).Times(0);
 
   // When the members join the group, no mute change should occur.
-  coordinator.RegisterGroupMember(&member1);
-  coordinator.RegisterGroupMember(&member2);
+  coordinator.RegisterMember(group_id, &member1);
+  coordinator.RegisterMember(group_id, &member2);
 
   // When the muter is created, both members should be muted.
   EXPECT_CALL(member1, StartMuting());
@@ -58,34 +58,34 @@
   Mock::VerifyAndClearExpectations(&member1);
   Mock::VerifyAndClearExpectations(&member2);
 
-  coordinator.UnregisterGroupMember(&member1);
-  coordinator.UnregisterGroupMember(&member2);
+  coordinator.UnregisterMember(group_id, &member1);
+  coordinator.UnregisterMember(group_id, &member2);
 }
 
 TEST(LocalMuterTest, MutesJoiningMembers) {
-  GroupCoordinator coordinator;
+  LoopbackCoordinator coordinator;
   const UnguessableToken group_id = UnguessableToken::Create();
 
   LocalMuter muter(&coordinator, group_id);
 
-  StrictMock<MockGroupMember> member(group_id);
+  StrictMock<MockGroupMember> member;
 
   // Since muting is in-effect, the group member is immediately muted when
   // joining the group.
   EXPECT_CALL(member, StartMuting());
-  coordinator.RegisterGroupMember(&member);
+  coordinator.RegisterMember(group_id, &member);
   Mock::VerifyAndClearExpectations(&member);
 
   // Leaving the group should have no effect on the mute state of the member.
   EXPECT_CALL(member, StartMuting()).Times(0);
   EXPECT_CALL(member, StopMuting()).Times(0);
-  coordinator.UnregisterGroupMember(&member);
+  coordinator.UnregisterMember(group_id, &member);
   Mock::VerifyAndClearExpectations(&member);
 }
 
 TEST(LocalMuter, UnmutesWhenLastBindingIsLost) {
   base::test::ScopedTaskEnvironment task_environment;
-  GroupCoordinator coordinator;
+  LoopbackCoordinator coordinator;
   const UnguessableToken group_id = UnguessableToken::Create();
 
   // Later in this test, once both bindings have been closed, the following
@@ -108,9 +108,9 @@
   ASSERT_TRUE(!!muter_ptr2);
 
   // A member joins the group and should be muted.
-  StrictMock<MockGroupMember> member(group_id);
+  StrictMock<MockGroupMember> member;
   EXPECT_CALL(member, StartMuting());
-  coordinator.RegisterGroupMember(&member);
+  coordinator.RegisterMember(group_id, &member);
   Mock::VerifyAndClearExpectations(&member);
 
   // Nothing happens to the member when one of the bindings is closed.
@@ -128,7 +128,7 @@
   // At this point, the LocalMuter should have been destroyed.
   EXPECT_FALSE(muter);
 
-  coordinator.UnregisterGroupMember(&member);
+  coordinator.UnregisterMember(group_id, &member);
 }
 
 }  // namespace
diff --git a/services/audio/loopback_coordinator.cc b/services/audio/loopback_coordinator.cc
new file mode 100644
index 0000000..43450bca
--- /dev/null
+++ b/services/audio/loopback_coordinator.cc
@@ -0,0 +1,10 @@
+// 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 "services/audio/loopback_coordinator.h"
+#include "services/audio/group_coordinator-impl.h"
+
+namespace audio {
+template class GroupCoordinator<LoopbackGroupMember>;
+}  // namespace audio
diff --git a/services/audio/loopback_coordinator.h b/services/audio/loopback_coordinator.h
new file mode 100644
index 0000000..f819d06
--- /dev/null
+++ b/services/audio/loopback_coordinator.h
@@ -0,0 +1,15 @@
+// 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 SERVICES_AUDIO_LOOPBACK_COORDINATOR_H_
+#define SERVICES_AUDIO_LOOPBACK_COORDINATOR_H_
+
+#include "services/audio/group_coordinator.h"
+#include "services/audio/loopback_group_member.h"
+
+namespace audio {
+using LoopbackCoordinator = GroupCoordinator<LoopbackGroupMember>;
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_LOOPBACK_COORDINATOR_H_
diff --git a/services/audio/loopback_group_member.h b/services/audio/loopback_group_member.h
new file mode 100644
index 0000000..603f819
--- /dev/null
+++ b/services/audio/loopback_group_member.h
@@ -0,0 +1,25 @@
+// 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 SERVICES_AUDIO_LOOPBACK_GROUP_MEMBER_H_
+#define SERVICES_AUDIO_LOOPBACK_GROUP_MEMBER_H_
+
+#include "services/audio/muteable.h"
+#include "services/audio/snoopable.h"
+
+namespace audio {
+
+// Interface for accessing signal data and controlling a members of an audio
+// group. A group is defined by a common group identifier that all members
+// share.
+//
+// The purpose of the grouping concept is to allow a feature to identify all
+// audio flows that come from the same logical unit, such as a browser tab. The
+// audio flows can then be duplicated, or other group-wide control exercised on
+// all members (such as audio muting).
+class LoopbackGroupMember : public Snoopable, public Muteable {};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_LOOPBACK_GROUP_MEMBER_H_
diff --git a/services/audio/loopback_stream.cc b/services/audio/loopback_stream.cc
index 2c38242..866ca18 100644
--- a/services/audio/loopback_stream.cc
+++ b/services/audio/loopback_stream.cc
@@ -35,7 +35,7 @@
     media::mojom::AudioInputStreamObserverPtr observer,
     const media::AudioParameters& params,
     uint32_t shared_memory_count,
-    GroupCoordinator* coordinator,
+    LoopbackCoordinator* coordinator,
     const base::UnguessableToken& group_id)
     : binding_lost_callback_(std::move(binding_lost_callback)),
       binding_(this, std::move(request)),
@@ -108,7 +108,8 @@
   if (network_) {
     if (network_->is_started()) {
       coordinator_->RemoveObserver(group_id_, this);
-      for (GroupMember* member : coordinator_->GetCurrentMembers(group_id_)) {
+      for (LoopbackGroupMember* member :
+           coordinator_->GetCurrentMembers(group_id_)) {
         OnMemberLeftGroup(member);
       }
     }
@@ -128,7 +129,8 @@
   // Begin snooping on all group members. This will set up the mixer network
   // and begin accumulating audio data in the Snoopers' buffers.
   DCHECK(snoopers_.empty());
-  for (GroupMember* member : coordinator_->GetCurrentMembers(group_id_)) {
+  for (LoopbackGroupMember* member :
+       coordinator_->GetCurrentMembers(group_id_)) {
     OnMemberJoinedGroup(member);
   }
   coordinator_->AddObserver(group_id_, this);
@@ -158,7 +160,7 @@
   }
 }
 
-void LoopbackStream::OnMemberJoinedGroup(GroupMember* member) {
+void LoopbackStream::OnMemberJoinedGroup(LoopbackGroupMember* member) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!network_) {
@@ -174,11 +176,11 @@
       std::forward_as_tuple(input_params, network_->output_params()));
   DCHECK(emplace_result.second);  // There was no pre-existing map entry.
   SnooperNode* const snooper = &(emplace_result.first->second);
-  member->StartSnooping(snooper);
+  member->StartSnooping(snooper, Snoopable::SnoopingMode::kDeferred);
   network_->AddInput(snooper);
 }
 
-void LoopbackStream::OnMemberLeftGroup(GroupMember* member) {
+void LoopbackStream::OnMemberLeftGroup(LoopbackGroupMember* member) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!network_) {
@@ -190,7 +192,7 @@
   const auto snoop_it = snoopers_.find(member);
   DCHECK(snoop_it != snoopers_.end());
   SnooperNode* const snooper = &(snoop_it->second);
-  member->StopSnooping(snooper);
+  member->StopSnooping(snooper, Snoopable::SnoopingMode::kDeferred);
   network_->RemoveInput(snooper);
   snoopers_.erase(snoop_it);
 }
diff --git a/services/audio/loopback_stream.h b/services/audio/loopback_stream.h
index 23f7f15..3907bd1 100644
--- a/services/audio/loopback_stream.h
+++ b/services/audio/loopback_stream.h
@@ -25,10 +25,10 @@
 #include "media/mojo/interfaces/audio_data_pipe.mojom.h"
 #include "media/mojo/interfaces/audio_input_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "services/audio/group_coordinator.h"
-#include "services/audio/group_member.h"
 #include "services/audio/input_controller.h"
 #include "services/audio/input_sync_writer.h"
+#include "services/audio/loopback_coordinator.h"
+#include "services/audio/loopback_group_member.h"
 #include "services/audio/snooper_node.h"
 
 namespace base {
@@ -53,7 +53,7 @@
 // a different task runner, to take all the audio collected in the SnooperNodes
 // and mix it into a single data stream.
 class LoopbackStream : public media::mojom::AudioInputStream,
-                       public GroupCoordinator::Observer {
+                       public LoopbackCoordinator::Observer {
  public:
   using CreatedCallback =
       base::OnceCallback<void(media::mojom::ReadOnlyAudioDataPipePtr)>;
@@ -67,7 +67,7 @@
                  media::mojom::AudioInputStreamObserverPtr observer,
                  const media::AudioParameters& params,
                  uint32_t shared_memory_count,
-                 GroupCoordinator* coordinator,
+                 LoopbackCoordinator* coordinator,
                  const base::UnguessableToken& group_id);
 
   ~LoopbackStream() final;
@@ -78,11 +78,11 @@
   void Record() final;
   void SetVolume(double volume) final;
 
-  // GroupCoordinator::Observer implementation. When a member joins a group, a
-  // SnooperNode is created for it, and a loopback flow from GroupMember →
-  // SnooperNode → FlowNetwork is built-up.
-  void OnMemberJoinedGroup(GroupMember* member) final;
-  void OnMemberLeftGroup(GroupMember* member) final;
+  // LoopbackCoordinator::Observer implementation. When a member joins
+  // a group, a SnooperNode is created for it, and a loopback flow from
+  // LoopbackGroupMember → SnooperNode → FlowNetwork is built-up.
+  void OnMemberJoinedGroup(LoopbackGroupMember* member) final;
+  void OnMemberLeftGroup(LoopbackGroupMember* member) final;
 
   // Overrides for unit testing. These must be called before Record().
   void set_clock_for_testing(const base::TickClock* clock) {
@@ -99,8 +99,8 @@
   static constexpr double kMaxVolume = 2.0;
 
   // The amount of time in the past from which to capture the audio. The audio
-  // recorded from each GroupMember is being generated with a target playout
-  // time in the near future (usually 1 to 20 ms). To avoid underflow,
+  // recorded from each LoopbackGroupMember is being generated with a target
+  // playout time in the near future (usually 1 to 20 ms). To avoid underflow,
   // LoopbackStream fetches the audio from a position in the recent past.
   static constexpr base::TimeDelta kCaptureDelay =
       base::TimeDelta::FromMilliseconds(20);
@@ -220,12 +220,12 @@
   media::mojom::AudioInputStreamObserverPtr observer_;
 
   // Used for identifying group members and snooping on their audio data flow.
-  GroupCoordinator* const coordinator_;
+  LoopbackCoordinator* const coordinator_;
   const base::UnguessableToken group_id_;
 
   // The snoopers associated with each group member. This is not a flat_map
   // because SnooperNodes cannot move around in memory while in operation.
-  std::map<GroupMember*, SnooperNode> snoopers_;
+  std::map<LoopbackGroupMember*, SnooperNode> snoopers_;
 
   // The flow network that generates the single loopback result stream. It is
   // owned by LoopbackStream, but it's destruction must be carried out by the
diff --git a/services/audio/loopback_stream_unittest.cc b/services/audio/loopback_stream_unittest.cc
index f357e99..466747a8 100644
--- a/services/audio/loopback_stream_unittest.cc
+++ b/services/audio/loopback_stream_unittest.cc
@@ -16,10 +16,10 @@
 #include "media/base/audio_parameters.h"
 #include "media/base/audio_timestamp_helper.h"
 #include "media/base/channel_layout.h"
-#include "services/audio/group_coordinator.h"
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_coordinator.h"
+#include "services/audio/loopback_group_member.h"
 #include "services/audio/test/fake_consumer.h"
-#include "services/audio/test/fake_group_member.h"
+#include "services/audio/test/fake_loopback_group_member.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -31,7 +31,7 @@
 namespace audio {
 namespace {
 
-// Volume settings for the FakeGroupMember (source) and LoopbackStream.
+// Volume settings for the FakeLoopbackGroupMember (source) and LoopbackStream.
 constexpr double kSnoopVolume = 0.25;
 constexpr double kLoopbackVolume = 0.5;
 
@@ -136,7 +136,7 @@
     stream_ = nullptr;
 
     for (const auto& source : sources_) {
-      coordinator_.UnregisterGroupMember(source.get());
+      coordinator_.UnregisterMember(group_id_, source.get());
     }
     sources_.clear();
 
@@ -149,22 +149,21 @@
 
   void RunMojoTasks() { task_runner_->RunUntilIdle(); }
 
-  FakeGroupMember* AddSource(int channels, int sample_rate) {
-    sources_.emplace_back(std::make_unique<FakeGroupMember>(
-        group_id_,
+  FakeLoopbackGroupMember* AddSource(int channels, int sample_rate) {
+    sources_.emplace_back(std::make_unique<FakeLoopbackGroupMember>(
         media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                                media::GuessChannelLayout(channels), sample_rate,
                                (sample_rate * kBufferDuration) /
                                    base::TimeDelta::FromSeconds(1))));
-    coordinator_.RegisterGroupMember(sources_.back().get());
+    coordinator_.RegisterMember(group_id_, sources_.back().get());
     return sources_.back().get();
   }
 
-  void RemoveSource(FakeGroupMember* source) {
+  void RemoveSource(FakeLoopbackGroupMember* source) {
     const auto it = std::find_if(sources_.begin(), sources_.end(),
                                  base::MatchesUniquePtr(source));
     if (it != sources_.end()) {
-      coordinator_.UnregisterGroupMember(source);
+      coordinator_.UnregisterMember(group_id_, source);
       sources_.erase(it);
     }
   }
@@ -254,9 +253,9 @@
 
  private:
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  GroupCoordinator coordinator_;
+  LoopbackCoordinator coordinator_;
   const base::UnguessableToken group_id_;
-  std::vector<std::unique_ptr<FakeGroupMember>> sources_;
+  std::vector<std::unique_ptr<FakeLoopbackGroupMember>> sources_;
   NiceMock<MockClientAndObserver> client_;
   std::unique_ptr<LoopbackStream> stream_;
   FakeSyncWriter* consumer_ = nullptr;  // Owned by |stream_|.
@@ -327,7 +326,8 @@
   }
 
 TEST_F(LoopbackStreamTest, ProducesAudioFromASingleSource) {
-  FakeGroupMember* const source = AddSource(1, 48000);  // Monaural, 48 kHz.
+  FakeLoopbackGroupMember* const source =
+      AddSource(1, 48000);  // Monaural, 48 kHz.
   source->SetChannelTone(0, kMiddleAFreq);
   source->SetVolume(kSnoopVolume);
 
@@ -346,7 +346,7 @@
   // Start the first source (of a middle-A note) before creating the loopback
   // stream.
   const int channels = GetLoopbackStreamParams().channels();
-  FakeGroupMember* const source1 = AddSource(channels, 48000);
+  FakeLoopbackGroupMember* const source1 = AddSource(channels, 48000);
   source1->SetChannelTone(0, kMiddleAFreq);
   source1->SetVolume(kSnoopVolume);
 
@@ -357,7 +357,7 @@
 
   // Start the second source (of a middle-C note) while the loopback stream is
   // running. The second source has a different sample rate than the first.
-  FakeGroupMember* const source2 = AddSource(channels, 44100);
+  FakeLoopbackGroupMember* const source2 = AddSource(channels, 44100);
   source2->SetChannelTone(1, kMiddleCFreq);
   source2->SetVolume(kSnoopVolume);
 
@@ -380,7 +380,8 @@
 }
 
 TEST_F(LoopbackStreamTest, AudioChangesVolume) {
-  FakeGroupMember* const source = AddSource(1, 48000);  // Monaural, 48 kHz.
+  FakeLoopbackGroupMember* const source =
+      AddSource(1, 48000);  // Monaural, 48 kHz.
   source->SetChannelTone(0, kMiddleAFreq);
   source->SetVolume(kSnoopVolume);
 
diff --git a/services/audio/muteable.h b/services/audio/muteable.h
new file mode 100644
index 0000000..d36c436
--- /dev/null
+++ b/services/audio/muteable.h
@@ -0,0 +1,23 @@
+// 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 SERVICES_AUDIO_MUTEABLE_H_
+#define SERVICES_AUDIO_MUTEABLE_H_
+
+namespace audio {
+class Muteable {
+ public:
+  // Starts/Stops muting of the outbound audio signal from this group member.
+  // However, the audio data being sent to Snoopers should be the original,
+  // unmuted audio. Note that an equal number of start versus stop calls here is
+  // not required, and the implementation should ignore redundant calls.
+  virtual void StartMuting() = 0;
+  virtual void StopMuting() = 0;
+
+ protected:
+  virtual ~Muteable() = default;
+};
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_MUTEABLE_H_
diff --git a/services/audio/output_controller.cc b/services/audio/output_controller.cc
index b9378329..b2fdd651 100644
--- a/services/audio/output_controller.cc
+++ b/services/audio/output_controller.cc
@@ -92,14 +92,12 @@
                                    EventHandler* handler,
                                    const media::AudioParameters& params,
                                    const std::string& output_device_id,
-                                   const base::UnguessableToken& group_id,
                                    SyncReader* sync_reader)
     : audio_manager_(audio_manager),
       params_(params),
       handler_(handler),
       task_runner_(audio_manager->GetTaskRunner()),
       output_device_id_(output_device_id),
-      group_id_(group_id),
       stream_(NULL),
       disable_local_output_(false),
       should_duplicate_(0),
@@ -394,17 +392,20 @@
   state_ = kEmpty;
 }
 
-const base::UnguessableToken& OutputController::GetGroupId() {
-  return group_id_;
-}
-
-const media::AudioParameters& OutputController::GetAudioParameters() {
+const media::AudioParameters& OutputController::GetAudioParameters() const {
   return params_;
 }
 
-void OutputController::StartSnooping(Snooper* snooper) {
+std::string OutputController::GetDeviceId() const {
+  // FIXME(ossu): Should this return "" or
+  // AudioDeviceDescription::kDefaultDeviceId for the default device.
+  return output_device_id_;
+}
+
+void OutputController::StartSnooping(Snooper* snooper, SnoopingMode mode) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(snooper);
+  DCHECK_EQ(mode, SnoopingMode::kDeferred);
 
   if (snoopers_.empty())
     should_duplicate_.Increment();
@@ -412,8 +413,9 @@
   snoopers_.push_back(snooper);
 }
 
-void OutputController::StopSnooping(Snooper* snooper) {
+void OutputController::StopSnooping(Snooper* snooper, SnoopingMode mode) {
   DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK_EQ(mode, SnoopingMode::kDeferred);
 
   const auto it = std::find(snoopers_.begin(), snoopers_.end(), snooper);
   DCHECK(it != snoopers_.end());
diff --git a/services/audio/output_controller.h b/services/audio/output_controller.h
index e507e9a..dfb20ce 100644
--- a/services/audio/output_controller.h
+++ b/services/audio/output_controller.h
@@ -26,7 +26,7 @@
 #include "media/audio/audio_manager.h"
 #include "media/audio/audio_power_monitor.h"
 #include "media/audio/audio_source_diverter.h"
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_group_member.h"
 
 // An OutputController controls an AudioOutputStream and provides data to this
 // output stream. It executes audio operations like play, pause, stop, etc. on
@@ -60,7 +60,7 @@
 namespace audio {
 
 class OutputController : public media::AudioOutputStream::AudioSourceCallback,
-                         public GroupMember,
+                         public LoopbackGroupMember,
                          public media::AudioManager::AudioDeviceListener {
  public:
   // An event handler that receives events from the OutputController. The
@@ -108,7 +108,6 @@
                    EventHandler* handler,
                    const media::AudioParameters& params,
                    const std::string& output_device_id,
-                   const base::UnguessableToken& group_id,
                    SyncReader* sync_reader);
   ~OutputController() override;
 
@@ -149,11 +148,11 @@
                  media::AudioBus* dest) override;
   void OnError() override;
 
-  // GroupMember implementation.
-  const base::UnguessableToken& GetGroupId() override;
-  const media::AudioParameters& GetAudioParameters() override;
-  void StartSnooping(Snooper* snooper) override;
-  void StopSnooping(Snooper* snooper) override;
+  // LoopbackGroupMember implementation.
+  const media::AudioParameters& GetAudioParameters() const override;
+  std::string GetDeviceId() const override;
+  void StartSnooping(Snooper* snooper, SnoopingMode mode) override;
+  void StopSnooping(Snooper* snooper, SnoopingMode mode) override;
   void StartMuting() override;
   void StopMuting() override;
 
@@ -239,9 +238,6 @@
   // default output device.
   const std::string output_device_id_;
 
-  // A token indicating membership in a group of output controllers/streams.
-  const base::UnguessableToken group_id_;
-
   media::AudioOutputStream* stream_;
 
   // When true, local audio output should be muted; either by having audio
diff --git a/services/audio/output_controller_unittest.cc b/services/audio/output_controller_unittest.cc
index 55dce2f..16cffed 100644
--- a/services/audio/output_controller_unittest.cc
+++ b/services/audio/output_controller_unittest.cc
@@ -33,7 +33,7 @@
 #include "media/base/audio_bus.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/gmock_callback_support.h"
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_group_member.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -216,7 +216,7 @@
   DISALLOW_COPY_AND_ASSIGN(MockAudioOutputStream);
 };
 
-class MockSnooper : public GroupMember::Snooper {
+class MockSnooper : public Snoopable::Snooper {
  public:
   MockSnooper() = default;
   ~MockSnooper() override = default;
@@ -315,7 +315,7 @@
 
   void SetUp() override {
     controller_.emplace(&audio_manager_, &mock_event_handler_, GetTestParams(),
-                        std::string(), group_id_, &mock_sync_reader_);
+                        std::string(), &mock_sync_reader_);
     controller_->SetVolume(kTestVolume);
   }
 
@@ -403,7 +403,7 @@
   }
 
   void StartSnooping(MockSnooper* snooper) {
-    controller_->StartSnooping(snooper);
+    controller_->StartSnooping(snooper, Snoopable::SnoopingMode::kDeferred);
   }
 
   void WaitForSnoopedData(MockSnooper* snooper) {
@@ -416,7 +416,7 @@
   }
 
   void StopSnooping(MockSnooper* snooper) {
-    controller_->StopSnooping(snooper);
+    controller_->StopSnooping(snooper, Snoopable::SnoopingMode::kDeferred);
   }
 
   void Close() {
diff --git a/services/audio/output_stream.cc b/services/audio/output_stream.cc
index 45015f87..7536c21 100644
--- a/services/audio/output_stream.cc
+++ b/services/audio/output_stream.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
-#include "services/audio/group_coordinator.h"
 
 namespace audio {
 
@@ -28,8 +27,8 @@
     media::AudioManager* audio_manager,
     const std::string& output_device_id,
     const media::AudioParameters& params,
-    GroupCoordinator* coordinator,
-    const base::UnguessableToken& group_id)
+    LoopbackCoordinator* coordinator,
+    const base::UnguessableToken& loopback_group_id)
     : foreign_socket_(),
       delete_callback_(std::move(delete_callback)),
       binding_(this, std::move(stream_request)),
@@ -43,12 +42,8 @@
                    : base::DoNothing(),
               params,
               &foreign_socket_),
-      controller_(audio_manager,
-                  this,
-                  params,
-                  output_device_id,
-                  group_id,
-                  &reader_),
+      controller_(audio_manager, this, params, output_device_id, &reader_),
+      loopback_group_id_(loopback_group_id),
       weak_factory_(this) {
   DCHECK(binding_.is_bound());
   DCHECK(created_callback);
@@ -71,7 +66,7 @@
   if (log_)
     log_->get()->OnCreated(params, output_device_id);
 
-  coordinator_->RegisterGroupMember(&controller_);
+  coordinator_->RegisterMember(loopback_group_id_, &controller_);
   if (!reader_.IsValid() || !controller_.Create(false)) {
     // Either SyncReader initialization failed or the controller failed to
     // create the stream. In the latter case, the controller will have called
@@ -96,7 +91,7 @@
         std::string());
 
   controller_.Close();
-  coordinator_->UnregisterGroupMember(&controller_);
+  coordinator_->UnregisterMember(loopback_group_id_, &controller_);
 
   if (is_audible_)
     TRACE_EVENT_NESTABLE_ASYNC_END0("audio", "Audible", this);
diff --git a/services/audio/output_stream.h b/services/audio/output_stream.h
index 9112c42..9af7a9d 100644
--- a/services/audio/output_stream.h
+++ b/services/audio/output_stream.h
@@ -22,6 +22,7 @@
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
+#include "services/audio/loopback_coordinator.h"
 #include "services/audio/output_controller.h"
 #include "services/audio/sync_reader.h"
 
@@ -36,8 +37,6 @@
 
 namespace audio {
 
-class GroupCoordinator;
-
 class OutputStream final : public media::mojom::AudioOutputStream,
                            public OutputController::EventHandler {
  public:
@@ -53,8 +52,8 @@
                media::AudioManager* audio_manager,
                const std::string& output_device_id,
                const media::AudioParameters& params,
-               GroupCoordinator* coordinator,
-               const base::UnguessableToken& group_id);
+               LoopbackCoordinator* coordinator,
+               const base::UnguessableToken& loopback_group_id);
 
   ~OutputStream() final;
 
@@ -83,10 +82,12 @@
   mojo::Binding<AudioOutputStream> binding_;
   media::mojom::AudioOutputStreamObserverAssociatedPtr observer_;
   const scoped_refptr<media::mojom::ThreadSafeAudioLogPtr> log_;
-  GroupCoordinator* const coordinator_;
+  LoopbackCoordinator* const coordinator_;
 
   SyncReader reader_;
   OutputController controller_;
+  // A token indicating membership in a group of output controllers/streams.
+  const base::UnguessableToken loopback_group_id_;
 
   // This flag ensures that we only send OnStreamStateChanged notifications
   // and (de)register with the stream monitor when the state actually changes.
diff --git a/services/audio/snoopable.h b/services/audio/snoopable.h
new file mode 100644
index 0000000..0089dcf
--- /dev/null
+++ b/services/audio/snoopable.h
@@ -0,0 +1,56 @@
+// 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 SERVICES_AUDIO_SNOOPABLE_H_
+#define SERVICES_AUDIO_SNOOPABLE_H_
+
+#include <string>
+
+#include "base/time/time.h"
+
+namespace media {
+class AudioBus;
+class AudioParameters;
+}  // namespace media
+
+namespace audio {
+class Snoopable {
+ public:
+  class Snooper {
+   public:
+    // Provides read-only access to the data flowing through a GroupMember.
+    virtual void OnData(const media::AudioBus& audio_bus,
+                        base::TimeTicks reference_time,
+                        double volume) = 0;
+
+   protected:
+    virtual ~Snooper() = default;
+  };
+
+  enum class SnoopingMode {
+    kDeferred,  // Deferred snooping is done on the audio thread.
+    kRealtime   // Realtime snooping is done on the device thread. Must be fast!
+  };
+
+  // Returns the audio parameters of the snoopable audio data. The parameters
+  // must not change for the lifetime of this group member, but can be different
+  // than those of other members.
+  virtual const media::AudioParameters& GetAudioParameters() const = 0;
+
+  // Returns the id of the device the snoopable stream is connected to.
+  virtual std::string GetDeviceId() const = 0;
+
+  // Starts/Stops snooping on the audio data flowing through this group member.
+  // The snooping modes are handled individually, so it's possible (though
+  // inadvisable) to call StartSnooping twice with the same snooper, but with
+  // different modes.
+  virtual void StartSnooping(Snooper* snooper, SnoopingMode mode) = 0;
+  virtual void StopSnooping(Snooper* snooper, SnoopingMode mode) = 0;
+
+ protected:
+  virtual ~Snoopable() = default;
+};
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_SNOOPABLE_H_
diff --git a/services/audio/snooper_node.h b/services/audio/snooper_node.h
index 496f5fc..4f6ebc3f 100644
--- a/services/audio/snooper_node.h
+++ b/services/audio/snooper_node.h
@@ -15,7 +15,7 @@
 #include "media/base/channel_mixer.h"
 #include "media/base/multi_channel_resampler.h"
 #include "services/audio/delay_buffer.h"
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_group_member.h"
 
 namespace media {
 class AudioBus;
@@ -53,7 +53,7 @@
 // because the inbound audio is from a source that pre-renders audio for playout
 // in the near future, while the outbound audio is audio that would have been
 // played-out in the recent past.
-class SnooperNode : public GroupMember::Snooper {
+class SnooperNode : public LoopbackGroupMember::Snooper {
  public:
   // Use sample counts as a precise measure of audio signal position and time
   // duration.
diff --git a/services/audio/snooper_node_unittest.cc b/services/audio/snooper_node_unittest.cc
index 7700837..79ab584 100644
--- a/services/audio/snooper_node_unittest.cc
+++ b/services/audio/snooper_node_unittest.cc
@@ -15,7 +15,7 @@
 #include "media/base/audio_parameters.h"
 #include "media/base/channel_layout.h"
 #include "services/audio/test/fake_consumer.h"
-#include "services/audio/test/fake_group_member.h"
+#include "services/audio/test/fake_loopback_group_member.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace audio {
@@ -76,7 +76,7 @@
     return GetParam().output;
   }
 
-  FakeGroupMember* group_member() { return &*group_member_; }
+  FakeLoopbackGroupMember* group_member() { return &*group_member_; }
   SnooperNode* node() { return &*node_; }
   FakeConsumer* consumer() { return &*consumer_; }
 
@@ -89,7 +89,7 @@
   }
 
   void CreateNewPipeline() {
-    group_member_.emplace(base::UnguessableToken(), input_params());
+    group_member_.emplace(input_params());
     group_member_->SetChannelTone(0, kLeftChannelFrequency);
     if (input_params().channels() > 1) {
       // Set the right channel to kRightChannelFrequency unless the test
@@ -103,7 +103,7 @@
     group_member_->SetVolume(kSourceVolume);
 
     node_.emplace(input_params(), output_params());
-    group_member_->StartSnooping(node());
+    group_member_->StartSnooping(node(), Snoopable::SnoopingMode::kDeferred);
 
     consumer_.emplace(output_params().channels(),
                       output_params().sample_rate());
@@ -131,10 +131,10 @@
         break;
       }
 
-      // FakeGroupMember pushes audio into the SnooperNode.
+      // FakeLoopbackGroupMember pushes audio into the SnooperNode.
       task_runner_->PostDelayedTask(
           FROM_HERE,
-          base::BindOnce(&FakeGroupMember::RenderMoreAudio,
+          base::BindOnce(&FakeLoopbackGroupMember::RenderMoreAudio,
                          base::Unretained(group_member()), next_time),
           next_time - start_time);
     }
@@ -195,7 +195,7 @@
 
  private:
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::Optional<FakeGroupMember> group_member_;
+  base::Optional<FakeLoopbackGroupMember> group_member_;
   base::Optional<SnooperNode> node_;
   base::Optional<FakeConsumer> consumer_;
 };
diff --git a/services/audio/stream_factory.h b/services/audio/stream_factory.h
index 187c852..14ab16f8 100644
--- a/services/audio/stream_factory.h
+++ b/services/audio/stream_factory.h
@@ -17,7 +17,7 @@
 #include "media/mojo/interfaces/audio_logging.mojom.h"
 #include "media/mojo/interfaces/audio_output_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/audio/group_coordinator.h"
+#include "services/audio/loopback_coordinator.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
 #include "services/audio/traced_service_ref.h"
 
@@ -101,7 +101,7 @@
   mojo::BindingSet<mojom::StreamFactory, TracedServiceRef> bindings_;
 
   // Order of the following members is important for a clean shutdown.
-  GroupCoordinator coordinator_;
+  LoopbackCoordinator coordinator_;
   std::vector<std::unique_ptr<LocalMuter>> muters_;
   std::vector<std::unique_ptr<LoopbackStream>> loopback_streams_;
   InputStreamSet input_streams_;
diff --git a/services/audio/test/fake_group_member.cc b/services/audio/test/fake_group_member.cc
deleted file mode 100644
index d72fee4a..0000000
--- a/services/audio/test/fake_group_member.cc
+++ /dev/null
@@ -1,76 +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 "services/audio/test/fake_group_member.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/numerics/math_constants.h"
-#include "media/base/audio_bus.h"
-
-namespace audio {
-
-FakeGroupMember::FakeGroupMember(const base::UnguessableToken& group_id,
-                                 const media::AudioParameters& params)
-    : group_id_(group_id),
-      params_(params),
-      audio_bus_(media::AudioBus::Create(params_)),
-      frequency_by_channel_(params_.channels(), 0.0) {
-  CHECK(params_.IsValid());
-}
-
-FakeGroupMember::~FakeGroupMember() = default;
-
-void FakeGroupMember::SetChannelTone(int ch, double frequency) {
-  frequency_by_channel_[ch] = frequency;
-}
-
-void FakeGroupMember::SetVolume(double volume) {
-  CHECK_GE(volume, 0.0);
-  CHECK_LE(volume, 1.0);
-  volume_ = volume;
-}
-
-void FakeGroupMember::RenderMoreAudio(base::TimeTicks output_timestamp) {
-  if (snooper_) {
-    for (int ch = 0; ch < params_.channels(); ++ch) {
-      const double step = 2.0 * base::kPiDouble * frequency_by_channel_[ch] /
-                          params_.sample_rate();
-      float* const samples = audio_bus_->channel(ch);
-      for (int frame = 0; frame < params_.frames_per_buffer(); ++frame) {
-        samples[frame] = std::sin((at_frame_ + frame) * step);
-      }
-    }
-    snooper_->OnData(*audio_bus_, output_timestamp, volume_);
-  }
-  at_frame_ += params_.frames_per_buffer();
-}
-
-const base::UnguessableToken& FakeGroupMember::GetGroupId() {
-  return group_id_;
-}
-
-const media::AudioParameters& FakeGroupMember::GetAudioParameters() {
-  return params_;
-}
-
-void FakeGroupMember::StartSnooping(Snooper* snooper) {
-  CHECK(!snooper_);
-  snooper_ = snooper;
-}
-
-void FakeGroupMember::StopSnooping(Snooper* snooper) {
-  snooper_ = nullptr;
-}
-
-void FakeGroupMember::StartMuting() {
-  // No effect for this fake implementation.
-}
-
-void FakeGroupMember::StopMuting() {
-  // No effect for this fake implementation.
-}
-
-}  // namespace audio
diff --git a/services/audio/test/fake_group_member.h b/services/audio/test/fake_group_member.h
deleted file mode 100644
index aa75f1d2..0000000
--- a/services/audio/test/fake_group_member.h
+++ /dev/null
@@ -1,74 +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 SERVICES_AUDIO_TEST_FAKE_GROUP_MEMBER_H_
-#define SERVICES_AUDIO_TEST_FAKE_GROUP_MEMBER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "base/unguessable_token.h"
-#include "media/base/audio_parameters.h"
-#include "services/audio/group_member.h"
-
-namespace media {
-class AudioBus;
-}
-
-namespace audio {
-
-// An implementation of GroupMember that can be snooped upon. It generates sine
-// wave tones, configurable per channel. Test procedures call RenderMoreAudio()
-// to push more data to the Snooper.
-//
-// This class is not thread-safe. The caller must guarantee method calls are not
-// being made simultaneously in multithreaded tests.
-class FakeGroupMember : public GroupMember {
- public:
-  FakeGroupMember(const base::UnguessableToken& group_id,
-                  const media::AudioParameters& params);
-
-  ~FakeGroupMember() override;
-
-  // Sets the sine wave |frequency| rendered into channel |ch|. Note that
-  // setting the frequency to zero will zero-out the channel signal.
-  void SetChannelTone(int ch, double frequency);
-
-  // Sets the volume of this FakeGroupMember. This simulates the current output
-  // volume of an audio::OutputStream.
-  void SetVolume(double volume);
-
-  // Renders a continuation of the sine wave signal, attaching
-  // |output_timestamp| as the timestamp associated with the first frame in the
-  // AudioBus being delivered to the Snooper.
-  void RenderMoreAudio(base::TimeTicks output_timestamp);
-
-  // GroupMember implementation.
-  const base::UnguessableToken& GetGroupId() override;
-  const media::AudioParameters& GetAudioParameters() override;
-  void StartSnooping(Snooper* snooper) override;
-  void StopSnooping(Snooper* snooper) override;
-  void StartMuting() override;
-  void StopMuting() override;
-
- private:
-  const base::UnguessableToken group_id_;
-  const media::AudioParameters params_;
-  const std::unique_ptr<media::AudioBus> audio_bus_;
-
-  std::vector<double> frequency_by_channel_;
-  double volume_ = 0.0;
-
-  int64_t at_frame_ = 0;
-
-  Snooper* snooper_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeGroupMember);
-};
-
-}  // namespace audio
-
-#endif  // SERVICES_AUDIO_TEST_FAKE_GROUP_MEMBER_H_
diff --git a/services/audio/test/fake_loopback_group_member.cc b/services/audio/test/fake_loopback_group_member.cc
new file mode 100644
index 0000000..ee43f1cc
--- /dev/null
+++ b/services/audio/test/fake_loopback_group_member.cc
@@ -0,0 +1,80 @@
+// 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 "services/audio/test/fake_loopback_group_member.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/numerics/math_constants.h"
+#include "media/base/audio_bus.h"
+
+namespace audio {
+
+FakeLoopbackGroupMember::FakeLoopbackGroupMember(
+    const media::AudioParameters& params)
+    : params_(params),
+      audio_bus_(media::AudioBus::Create(params_)),
+      frequency_by_channel_(params_.channels(), 0.0) {
+  CHECK(params_.IsValid());
+}
+
+FakeLoopbackGroupMember::~FakeLoopbackGroupMember() = default;
+
+void FakeLoopbackGroupMember::SetChannelTone(int ch, double frequency) {
+  frequency_by_channel_[ch] = frequency;
+}
+
+void FakeLoopbackGroupMember::SetVolume(double volume) {
+  CHECK_GE(volume, 0.0);
+  CHECK_LE(volume, 1.0);
+  volume_ = volume;
+}
+
+void FakeLoopbackGroupMember::RenderMoreAudio(
+    base::TimeTicks output_timestamp) {
+  if (snooper_) {
+    for (int ch = 0; ch < params_.channels(); ++ch) {
+      const double step = 2.0 * base::kPiDouble * frequency_by_channel_[ch] /
+                          params_.sample_rate();
+      float* const samples = audio_bus_->channel(ch);
+      for (int frame = 0; frame < params_.frames_per_buffer(); ++frame) {
+        samples[frame] = std::sin((at_frame_ + frame) * step);
+      }
+    }
+    snooper_->OnData(*audio_bus_, output_timestamp, volume_);
+  }
+  at_frame_ += params_.frames_per_buffer();
+}
+
+const media::AudioParameters& FakeLoopbackGroupMember::GetAudioParameters()
+    const {
+  return params_;
+}
+
+std::string FakeLoopbackGroupMember::GetDeviceId() const {
+  // FIXME(ossu): Provide a device ID or return default!
+  return "";
+}
+
+void FakeLoopbackGroupMember::StartSnooping(Snooper* snooper,
+                                            SnoopingMode mode) {
+  CHECK(!snooper_);
+  snooper_ = snooper;
+}
+
+void FakeLoopbackGroupMember::StopSnooping(Snooper* snooper,
+                                           SnoopingMode mode) {
+  snooper_ = nullptr;
+}
+
+void FakeLoopbackGroupMember::StartMuting() {
+  // No effect for this fake implementation.
+}
+
+void FakeLoopbackGroupMember::StopMuting() {
+  // No effect for this fake implementation.
+}
+
+}  // namespace audio
diff --git a/services/audio/test/fake_loopback_group_member.h b/services/audio/test/fake_loopback_group_member.h
new file mode 100644
index 0000000..61c7d162
--- /dev/null
+++ b/services/audio/test/fake_loopback_group_member.h
@@ -0,0 +1,72 @@
+// 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 SERVICES_AUDIO_TEST_FAKE_LOOPBACK_GROUP_MEMBER_H_
+#define SERVICES_AUDIO_TEST_FAKE_LOOPBACK_GROUP_MEMBER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "media/base/audio_parameters.h"
+#include "services/audio/loopback_group_member.h"
+
+namespace media {
+class AudioBus;
+}
+
+namespace audio {
+
+// An implementation of LoopbackGroupMember that can be snooped upon. It
+// generates sine wave tones, configurable per channel. Test procedures call
+// RenderMoreAudio() to push more data to the Snooper.
+//
+// This class is not thread-safe. The caller must guarantee method calls are not
+// being made simultaneously in multithreaded tests.
+class FakeLoopbackGroupMember : public LoopbackGroupMember {
+ public:
+  explicit FakeLoopbackGroupMember(const media::AudioParameters& params);
+
+  ~FakeLoopbackGroupMember() override;
+
+  // Sets the sine wave |frequency| rendered into channel |ch|. Note that
+  // setting the frequency to zero will zero-out the channel signal.
+  void SetChannelTone(int ch, double frequency);
+
+  // Sets the volume of this FakeLoopbackGroupMember. This simulates the current
+  // output volume of an audio::OutputStream.
+  void SetVolume(double volume);
+
+  // Renders a continuation of the sine wave signal, attaching
+  // |output_timestamp| as the timestamp associated with the first frame in the
+  // AudioBus being delivered to the Snooper.
+  void RenderMoreAudio(base::TimeTicks output_timestamp);
+
+  // LoopbackGroupMember implementation.
+  const media::AudioParameters& GetAudioParameters() const override;
+  std::string GetDeviceId() const override;
+  void StartSnooping(Snooper* snooper, SnoopingMode mode) override;
+  void StopSnooping(Snooper* snooper, SnoopingMode mode) override;
+  void StartMuting() override;
+  void StopMuting() override;
+
+ private:
+  const media::AudioParameters params_;
+  const std::unique_ptr<media::AudioBus> audio_bus_;
+
+  std::vector<double> frequency_by_channel_;
+  double volume_ = 0.0;
+
+  int64_t at_frame_ = 0;
+
+  Snooper* snooper_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeLoopbackGroupMember);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_TEST_FAKE_LOOPBACK_GROUP_MEMBER_H_
diff --git a/services/audio/test/mock_group_coordinator.cc b/services/audio/test/mock_group_coordinator.cc
new file mode 100644
index 0000000..05d8d49e
--- /dev/null
+++ b/services/audio/test/mock_group_coordinator.cc
@@ -0,0 +1,10 @@
+// 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 "services/audio/test/mock_group_coordinator.h"
+#include "services/audio/group_coordinator-impl.h"
+
+namespace audio {
+template class GroupCoordinator<MockGroupMember>;
+}  // namespace audio
diff --git a/services/audio/test/mock_group_coordinator.h b/services/audio/test/mock_group_coordinator.h
new file mode 100644
index 0000000..33db95fb
--- /dev/null
+++ b/services/audio/test/mock_group_coordinator.h
@@ -0,0 +1,15 @@
+// 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 SERVICES_AUDIO_TEST_MOCK_GROUP_COORDINATOR_H_
+#define SERVICES_AUDIO_TEST_MOCK_GROUP_COORDINATOR_H_
+
+#include "services/audio/group_coordinator.h"
+#include "services/audio/test/mock_group_member.h"
+
+namespace audio {
+using MockGroupCoordinator = GroupCoordinator<MockGroupMember>;
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_TEST_MOCK_GROUP_COORDINATOR_H_
diff --git a/services/audio/test/mock_group_member.cc b/services/audio/test/mock_group_member.cc
index 95dfd51..ff75367 100644
--- a/services/audio/test/mock_group_member.cc
+++ b/services/audio/test/mock_group_member.cc
@@ -6,13 +6,7 @@
 
 namespace audio {
 
-MockGroupMember::MockGroupMember(const base::UnguessableToken& group_id)
-    : group_id_(group_id) {}
-
+MockGroupMember::MockGroupMember() = default;
 MockGroupMember::~MockGroupMember() = default;
 
-const base::UnguessableToken& MockGroupMember::GetGroupId() {
-  return group_id_;
-}
-
 }  // namespace audio
diff --git a/services/audio/test/mock_group_member.h b/services/audio/test/mock_group_member.h
index 2a634813..992d18f 100644
--- a/services/audio/test/mock_group_member.h
+++ b/services/audio/test/mock_group_member.h
@@ -8,30 +8,25 @@
 #include "services/audio/group_coordinator.h"
 
 #include "base/macros.h"
-#include "base/unguessable_token.h"
 #include "media/base/audio_parameters.h"
-#include "services/audio/group_member.h"
+#include "services/audio/loopback_group_member.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace audio {
 
-class MockGroupMember : public GroupMember {
+class MockGroupMember : public LoopbackGroupMember {
  public:
-  explicit MockGroupMember(const base::UnguessableToken& group_id);
-
+  MockGroupMember();
   ~MockGroupMember() override;
 
-  const base::UnguessableToken& GetGroupId() override;
-  MOCK_METHOD0(GetAudioParameters, const media::AudioParameters&());
-  MOCK_METHOD1(StartSnooping, void(Snooper* snooper));
-  MOCK_METHOD1(StopSnooping, void(Snooper* snooper));
+  MOCK_CONST_METHOD0(GetAudioParameters, const media::AudioParameters&());
+  MOCK_CONST_METHOD0(GetDeviceId, std::string());
+  MOCK_METHOD2(StartSnooping, void(Snooper* snooper, SnoopingMode mode));
+  MOCK_METHOD2(StopSnooping, void(Snooper* snooper, SnoopingMode mode));
   MOCK_METHOD0(StartMuting, void());
   MOCK_METHOD0(StopMuting, void());
   MOCK_METHOD0(IsMuting, bool());
 
- private:
-  const base::UnguessableToken group_id_;
-
   DISALLOW_COPY_AND_ASSIGN(MockGroupMember);
 };
 
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index d4afb95..4df6370 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -239,6 +239,12 @@
   DCHECK(forwarding_client_);
   DCHECK(!is_waiting_follow_redirect_call_);
 
+  if (request_.fetch_redirect_mode == mojom::FetchRedirectMode::kManual) {
+    is_waiting_follow_redirect_call_ = true;
+    forwarding_client_->OnReceiveRedirect(redirect_info, response_head);
+    return;
+  }
+
   // If |CORS flag| is set and a CORS check for |request| and |response| returns
   // failure, then return a network error.
   if (fetch_cors_flag_ &&
@@ -270,15 +276,13 @@
     return;
   }
 
-  // TODO(yhirano): Implement the following:
-  // If |request|’s mode is "cors", |actualResponse|’s location URL includes
-  // credentials, and either |request|’s tainted origin flag is set or
-  // |request|’s origin is not same origin with |actualResponse|’s location
-  // URL’s origin, then return a network error.
-
-  // TODO(yhirano): Implement the following:
-  // If |CORS flag| is set and |actualResponse|’s location URL includes
-  // credentials, then return a network error.
+  const auto error_status = CheckRedirectLocation(
+      redirect_info.new_url, request_.fetch_request_mode,
+      request_.request_initiator, fetch_cors_flag_, tainted_);
+  if (error_status) {
+    HandleComplete(URLLoaderCompletionStatus(*error_status));
+    return;
+  }
 
   // TODO(yhirano): Implement the following (Note: this is needed when upload
   // streaming is implemented):
diff --git a/services/network/cross_origin_read_blocking.cc b/services/network/cross_origin_read_blocking.cc
index 242b3c4..3931c53 100644
--- a/services/network/cross_origin_read_blocking.cc
+++ b/services/network/cross_origin_read_blocking.cc
@@ -541,14 +541,12 @@
 
 CrossOriginReadBlocking::ResponseAnalyzer::ResponseAnalyzer(
     const net::URLRequest& request,
-    const ResourceResponse& response,
-    base::StringPiece excluded_initiator_scheme) {
+    const ResourceResponse& response) {
   content_length_ = response.head.content_length;
   http_response_code_ =
       response.head.headers ? response.head.headers->response_code() : 0;
 
-  should_block_based_on_headers_ =
-      ShouldBlockBasedOnHeaders(request, response, excluded_initiator_scheme);
+  should_block_based_on_headers_ = ShouldBlockBasedOnHeaders(request, response);
   if (should_block_based_on_headers_ == kNeedToSniffMore)
     CreateSniffers();
 }
@@ -558,8 +556,7 @@
 CrossOriginReadBlocking::ResponseAnalyzer::BlockingDecision
 CrossOriginReadBlocking::ResponseAnalyzer::ShouldBlockBasedOnHeaders(
     const net::URLRequest& request,
-    const ResourceResponse& response,
-    base::StringPiece excluded_initiator_scheme) {
+    const ResourceResponse& response) {
   // The checks in this method are ordered to rule out blocking in most cases as
   // quickly as possible.  Checks that are likely to lead to returning false or
   // that are inexpensive should be near the top.
@@ -587,14 +584,6 @@
   if (initiator.scheme() == url::kFileScheme)
     return kAllow;
 
-  // Give embedder a chance to skip document blocking of some initiator schemes
-  // (e.g. chrome-extension to avoid blocking requests initiated by content
-  // scripts).
-  if (!excluded_initiator_scheme.empty() &&
-      initiator.scheme() == excluded_initiator_scheme) {
-    return kAllow;
-  }
-
   // Allow the response through if it has valid CORS headers.
   std::string cors_header;
   response.head.headers->GetNormalizedHeader("access-control-allow-origin",
diff --git a/services/network/cross_origin_read_blocking.h b/services/network/cross_origin_read_blocking.h
index b2fc7ea..982b913 100644
--- a/services/network/cross_origin_read_blocking.h
+++ b/services/network/cross_origin_read_blocking.h
@@ -56,8 +56,7 @@
     // Creates a ResponseAnalyzer for the |request|, |response| pair.  The
     // ResponseAnalyzer will decide whether |response| needs to be blocked.
     ResponseAnalyzer(const net::URLRequest& request,
-                     const ResourceResponse& response,
-                     base::StringPiece excluded_initiator_scheme);
+                     const ResourceResponse& response);
 
     ~ResponseAnalyzer();
 
@@ -121,8 +120,7 @@
     };
     BlockingDecision ShouldBlockBasedOnHeaders(
         const net::URLRequest& request,
-        const ResourceResponse& response,
-        base::StringPiece excluded_initiator_scheme);
+        const ResourceResponse& response);
 
     // Populates |sniffers_| container based on |canonical_mime_type_|.  Called
     // if ShouldBlockBasedOnHeaders returns kNeedToSniffMore
diff --git a/services/network/data_pipe_element_reader_unittest.cc b/services/network/data_pipe_element_reader_unittest.cc
index f64cc83..eae5fc4 100644
--- a/services/network/data_pipe_element_reader_unittest.cc
+++ b/services/network/data_pipe_element_reader_unittest.cc
@@ -17,7 +17,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
-#include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom.h"
diff --git a/services/network/http_cache_data_remover.h b/services/network/http_cache_data_remover.h
index 692d9f6..09be3dc 100644
--- a/services/network/http_cache_data_remover.h
+++ b/services/network/http_cache_data_remover.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "net/base/completion_callback.h"
 #include "services/network/conditional_cache_deletion_helper.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "url/gurl.h"
diff --git a/services/network/ignore_errors_cert_verifier.cc b/services/network/ignore_errors_cert_verifier.cc
index a682cfa..b6a67488 100644
--- a/services/network/ignore_errors_cert_verifier.cc
+++ b/services/network/ignore_errors_cert_verifier.cc
@@ -12,7 +12,6 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "crypto/sha2.h"
-#include "net/base/completion_callback.h"
 #include "net/base/hash_value.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_export.h"
@@ -23,7 +22,6 @@
 #include "services/network/public/cpp/network_switches.h"
 
 using ::net::CertVerifier;
-using ::net::CompletionCallback;
 using ::net::HashValue;
 using ::net::SHA256HashValue;
 using ::net::X509Certificate;
diff --git a/services/network/ignore_errors_cert_verifier.h b/services/network/ignore_errors_cert_verifier.h
index 9300e36..ce0984c 100644
--- a/services/network/ignore_errors_cert_verifier.h
+++ b/services/network/ignore_errors_cert_verifier.h
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/component_export.h"
 #include "base/containers/flat_set.h"
+#include "net/base/completion_once_callback.h"
 #include "net/cert/cert_verifier.h"
 
 namespace net {
diff --git a/services/network/ignore_errors_cert_verifier_unittest.cc b/services/network/ignore_errors_cert_verifier_unittest.cc
index 1db9450..5f31699a 100644
--- a/services/network/ignore_errors_cert_verifier_unittest.cc
+++ b/services/network/ignore_errors_cert_verifier_unittest.cc
@@ -27,7 +27,6 @@
 
 using net::CertVerifier;
 using net::MockCertVerifier;
-using net::CompletionCallback;
 using net::HashValue;
 using net::SHA256HashValue;
 using net::X509Certificate;
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 5de6671..78a320b6 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1030,7 +1030,7 @@
   std::unique_ptr<PrefService> pref_service;
   if (params_->http_server_properties_path) {
     scoped_refptr<JsonPrefStore> json_pref_store(new JsonPrefStore(
-        *params_->http_server_properties_path,
+        *params_->http_server_properties_path, nullptr,
         base::CreateSequencedTaskRunnerWithTraits(
             {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN,
              base::TaskPriority::BEST_EFFORT})));
diff --git a/services/network/p2p/socket_manager.cc b/services/network/p2p/socket_manager.cc
index b7b457d..8b7e29d1 100644
--- a/services/network/p2p/socket_manager.cc
+++ b/services/network/p2p/socket_manager.cc
@@ -12,7 +12,6 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "net/base/network_interfaces.h"
 #include "net/base/sys_addrinfo.h"
diff --git a/services/network/p2p/socket_tcp.h b/services/network/p2p/socket_tcp.h
index 064a5fa..6087f33 100644
--- a/services/network/p2p/socket_tcp.h
+++ b/services/network/p2p/socket_tcp.h
@@ -15,7 +15,6 @@
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "net/base/completion_callback.h"
 #include "net/base/ip_endpoint.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/p2p/socket.h"
diff --git a/services/network/p2p/socket_test_utils.cc b/services/network/p2p/socket_test_utils.cc
index 5efa3953..c59048cd 100644
--- a/services/network/p2p/socket_test_utils.cc
+++ b/services/network/p2p/socket_test_utils.cc
@@ -10,7 +10,6 @@
 #include "base/sys_byteorder.h"
 #include "base/test/bind_test_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_address.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
diff --git a/services/network/proxy_resolving_client_socket.h b/services/network/proxy_resolving_client_socket.h
index da4d179a..9b931b7 100644
--- a/services/network/proxy_resolving_client_socket.h
+++ b/services/network/proxy_resolving_client_socket.h
@@ -15,7 +15,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "net/base/completion_callback.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
 #include "net/log/net_log_with_source.h"
diff --git a/services/network/proxy_resolving_socket_mojo.h b/services/network/proxy_resolving_socket_mojo.h
index 9e643837..7b127c5 100644
--- a/services/network/proxy_resolving_socket_mojo.h
+++ b/services/network/proxy_resolving_socket_mojo.h
@@ -10,7 +10,6 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "net/base/completion_callback.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/proxy_resolving_client_socket.h"
 #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
diff --git a/services/network/proxy_resolving_socket_mojo_unittest.cc b/services/network/proxy_resolving_socket_mojo_unittest.cc
index 7f6936b..018a55c 100644
--- a/services/network/proxy_resolving_socket_mojo_unittest.cc
+++ b/services/network/proxy_resolving_socket_mojo_unittest.cc
@@ -11,8 +11,6 @@
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
-#include "net/base/completion_callback.h"
-#include "net/base/completion_once_callback.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc
index cee5a6e..53348a6 100644
--- a/services/network/public/cpp/cors/cors.cc
+++ b/services/network/public/cpp/cors/cors.cc
@@ -258,26 +258,33 @@
   return CORSErrorStatus(error, error_status->failed_parameter);
 }
 
-base::Optional<mojom::CORSError> CheckRedirectLocation(const GURL& redirect_url,
-                                                       bool skip_scheme_check) {
-  if (!skip_scheme_check) {
-    // Block non HTTP(S) schemes as specified in the step 4 in
-    // https://fetch.spec.whatwg.org/#http-redirect-fetch. Chromium also allows
-    // the data scheme.
-    auto& schemes = url::GetCORSEnabledSchemes();
-    if (std::find(std::begin(schemes), std::end(schemes),
-                  redirect_url.scheme()) == std::end(schemes)) {
-      return mojom::CORSError::kRedirectDisallowedScheme;
-    }
+base::Optional<CORSErrorStatus> CheckRedirectLocation(
+    const GURL& url,
+    mojom::FetchRequestMode request_mode,
+    const base::Optional<url::Origin>& origin,
+    bool cors_flag,
+    bool tainted) {
+  // If |actualResponse|’s location URL’s scheme is not an HTTP(S) scheme,
+  // then return a network error.
+  // This should be addressed in //net.
+
+  // Note: The redirect count check is done elsewhere.
+
+  const bool url_has_credentials = url.has_username() || url.has_password();
+  // If |request|’s mode is "cors", |actualResponse|’s location URL includes
+  // credentials, and either |request|’s tainted origin flag is set or
+  // |request|’s origin is not same origin with |actualResponse|’s location
+  // URL’s origin, then return a network error.
+  DCHECK(!IsCORSEnabledRequestMode(request_mode) || origin);
+  if (IsCORSEnabledRequestMode(request_mode) && url_has_credentials &&
+      (tainted || !origin->IsSameOriginWith(url::Origin::Create(url)))) {
+    return CORSErrorStatus(mojom::CORSError::kRedirectContainsCredentials);
   }
 
-  // Block URLs including credentials as specified in the step 9 in
-  // https://fetch.spec.whatwg.org/#http-redirect-fetch.
-  //
-  // TODO(tyoshino): This check should be performed also when request's
-  // origin is not same origin with the redirect destination's origin.
-  if (redirect_url.has_username() || redirect_url.has_password())
-    return mojom::CORSError::kRedirectContainsCredentials;
+  // If CORS flag is set and |actualResponse|’s location URL includes
+  // credentials, then return a network error.
+  if (cors_flag && url_has_credentials)
+    return CORSErrorStatus(mojom::CORSError::kRedirectContainsCredentials);
 
   return base::nullopt;
 }
diff --git a/services/network/public/cpp/cors/cors.h b/services/network/public/cpp/cors/cors.h
index a5d703e..47e5d81 100644
--- a/services/network/public/cpp/cors/cors.h
+++ b/services/network/public/cpp/cors/cors.h
@@ -75,12 +75,13 @@
 // according to CORS. That is:
 // - the URL has a CORS supported scheme and
 // - the URL does not contain the userinfo production.
-// TODO(toyoshim): Remove |skip_scheme_check| that is used when customized
-// scheme check runs in Blink side in the legacy mode.
-// See https://crbug.com/800669.
 COMPONENT_EXPORT(NETWORK_CPP)
-base::Optional<mojom::CORSError> CheckRedirectLocation(const GURL& redirect_url,
-                                                       bool skip_scheme_check);
+base::Optional<CORSErrorStatus> CheckRedirectLocation(
+    const GURL& url,
+    mojom::FetchRequestMode request_mode,
+    const base::Optional<url::Origin>& origin,
+    bool cors_flag,
+    bool tainted);
 
 // Performs the required CORS checks on the response to a preflight request.
 // Returns |kPreflightSuccess| if preflight response was successful.
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc
index 349ad1ff8..ee9a42e 100644
--- a/services/network/public/cpp/cors/cors_unittest.cc
+++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -167,43 +167,119 @@
   EXPECT_EQ("fuga", error2->failed_parameter);
 }
 
-// Tests if cors::CheckRedirectLocation detects kRedirectDisallowedScheme and
+// Tests if cors::CheckRedirectLocation detects kCORSDisabledScheme and
 // kRedirectContainsCredentials errors correctly.
-TEST_F(CORSTest, CheckRedirectLocationDetectsErrors) {
-  // Following URLs should pass.
-  EXPECT_FALSE(cors::CheckRedirectLocation(GURL("http://example.com/"), false));
-  EXPECT_FALSE(
-      cors::CheckRedirectLocation(GURL("https://example.com/"), false));
-  EXPECT_FALSE(cors::CheckRedirectLocation(GURL("data:,Hello"), false));
-  EXPECT_FALSE(
-      cors::CheckRedirectLocation(GURL("file:///not_allow_scheme"), true));
+TEST_F(CORSTest, CheckRedirectLocation) {
+  struct TestCase {
+    GURL url;
+    mojom::FetchRequestMode request_mode;
+    bool cors_flag;
+    bool tainted;
+    base::Optional<CORSErrorStatus> expectation;
+  };
 
-  // Following URLs should result in kRedirectDisallowedScheme.
-  base::Optional<mojom::CORSError> error1 =
-      cors::CheckRedirectLocation(GURL("file:///not_allow_scheme"), false);
-  ASSERT_TRUE(error1);
-  EXPECT_EQ(mojom::CORSError::kRedirectDisallowedScheme, *error1);
+  const auto kCORS = mojom::FetchRequestMode::kCORS;
+  const auto kCORSWithForcedPreflight =
+      mojom::FetchRequestMode::kCORSWithForcedPreflight;
+  const auto kNoCORS = mojom::FetchRequestMode::kNoCORS;
 
-  // Following checks should result in the kRedirectContainsCredentials error.
-  base::Optional<mojom::CORSError> error2 = cors::CheckRedirectLocation(
-      GURL("http://yukari:tamura@example.com/"), false);
-  ASSERT_TRUE(error2);
-  EXPECT_EQ(mojom::CORSError::kRedirectContainsCredentials, *error2);
+  const url::Origin origin = url::Origin::Create(GURL("http://example.com/"));
+  const GURL same_origin_url("http://example.com/");
+  const GURL cross_origin_url("http://example2.com/");
+  const GURL data_url("data:,Hello");
+  const GURL same_origin_url_with_user("http://yukari@example.com/");
+  const GURL same_origin_url_with_pass("http://:tamura@example.com/");
+  const GURL cross_origin_url_with_user("http://yukari@example2.com/");
+  const GURL cross_origin_url_with_pass("http://:tamura@example2.com/");
+  const auto ok = base::nullopt;
+  const CORSErrorStatus kCORSDisabledScheme(
+      mojom::CORSError::kCORSDisabledScheme);
+  const CORSErrorStatus kRedirectContainsCredentials(
+      mojom::CORSError::kRedirectContainsCredentials);
 
-  base::Optional<mojom::CORSError> error3 = cors::CheckRedirectLocation(
-      GURL("http://yukari:tamura@example.com/"), true);
-  ASSERT_TRUE(error3);
-  EXPECT_EQ(mojom::CORSError::kRedirectContainsCredentials, *error3);
+  TestCase cases[] = {
+      // "cors", no credentials information
+      {same_origin_url, kCORS, false, false, ok},
+      {cross_origin_url, kCORS, false, false, ok},
+      {data_url, kCORS, false, false, ok},
+      {same_origin_url, kCORS, true, false, ok},
+      {cross_origin_url, kCORS, true, false, ok},
+      {data_url, kCORS, true, false, ok},
+      {same_origin_url, kCORS, false, true, ok},
+      {cross_origin_url, kCORS, false, true, ok},
+      {data_url, kCORS, false, true, ok},
+      {same_origin_url, kCORS, true, true, ok},
+      {cross_origin_url, kCORS, true, true, ok},
+      {data_url, kCORS, true, true, ok},
 
-  base::Optional<mojom::CORSError> error4 =
-      cors::CheckRedirectLocation(GURL("http://tamura@example.com/"), true);
-  ASSERT_TRUE(error4);
-  EXPECT_EQ(mojom::CORSError::kRedirectContainsCredentials, *error4);
+      // "cors" with forced preflight, no credentials information
+      {same_origin_url, kCORSWithForcedPreflight, false, false, ok},
+      {cross_origin_url, kCORSWithForcedPreflight, false, false, ok},
+      {data_url, kCORSWithForcedPreflight, false, false, ok},
+      {same_origin_url, kCORSWithForcedPreflight, true, false, ok},
+      {cross_origin_url, kCORSWithForcedPreflight, true, false, ok},
+      {data_url, kCORSWithForcedPreflight, true, false, ok},
+      {same_origin_url, kCORSWithForcedPreflight, false, true, ok},
+      {cross_origin_url, kCORSWithForcedPreflight, false, true, ok},
+      {data_url, kCORSWithForcedPreflight, false, true, ok},
+      {same_origin_url, kCORSWithForcedPreflight, true, true, ok},
+      {cross_origin_url, kCORSWithForcedPreflight, true, true, ok},
+      {data_url, kCORSWithForcedPreflight, true, true, ok},
 
-  base::Optional<mojom::CORSError> error5 =
-      cors::CheckRedirectLocation(GURL("http://yukari:@example.com/"), true);
-  ASSERT_TRUE(error5);
-  EXPECT_EQ(mojom::CORSError::kRedirectContainsCredentials, *error5);
+      // "no-cors", no credentials information
+      {same_origin_url, kNoCORS, false, false, ok},
+      {cross_origin_url, kNoCORS, false, false, ok},
+      {data_url, kNoCORS, false, false, ok},
+      {same_origin_url, kNoCORS, false, true, ok},
+      {cross_origin_url, kNoCORS, false, true, ok},
+      {data_url, kNoCORS, false, true, ok},
+
+      // with credentials information (same origin)
+      {same_origin_url_with_user, kCORS, false, false, ok},
+      {same_origin_url_with_user, kCORS, true, false,
+       kRedirectContainsCredentials},
+      {same_origin_url_with_user, kCORS, true, true,
+       kRedirectContainsCredentials},
+      {same_origin_url_with_user, kNoCORS, false, false, ok},
+      {same_origin_url_with_user, kNoCORS, false, true, ok},
+      {same_origin_url_with_pass, kCORS, false, false, ok},
+      {same_origin_url_with_pass, kCORS, true, false,
+       kRedirectContainsCredentials},
+      {same_origin_url_with_pass, kCORS, true, true,
+       kRedirectContainsCredentials},
+      {same_origin_url_with_pass, kNoCORS, false, false, ok},
+      {same_origin_url_with_pass, kNoCORS, false, true, ok},
+
+      // with credentials information (cross origin)
+      {cross_origin_url_with_user, kCORS, false, false,
+       kRedirectContainsCredentials},
+      {cross_origin_url_with_user, kCORS, true, false,
+       kRedirectContainsCredentials},
+      {cross_origin_url_with_user, kCORS, true, true,
+       kRedirectContainsCredentials},
+      {cross_origin_url_with_user, kNoCORS, false, true, ok},
+      {cross_origin_url_with_user, kNoCORS, false, false, ok},
+      {cross_origin_url_with_pass, kCORS, false, false,
+       kRedirectContainsCredentials},
+      {cross_origin_url_with_pass, kCORS, true, false,
+       kRedirectContainsCredentials},
+      {cross_origin_url_with_pass, kCORS, true, true,
+       kRedirectContainsCredentials},
+      {cross_origin_url_with_pass, kNoCORS, false, true, ok},
+      {cross_origin_url_with_pass, kNoCORS, false, false, ok},
+  };
+
+  for (const auto& test : cases) {
+    SCOPED_TRACE(testing::Message()
+                 << "url: " << test.url
+                 << ", request mode: " << test.request_mode
+                 << ", origin: " << origin << ", cors_flag: " << test.cors_flag
+                 << ", tainted: " << test.tainted);
+
+    EXPECT_EQ(test.expectation,
+              cors::CheckRedirectLocation(test.url, test.request_mode, origin,
+                                          test.cors_flag, test.tainted));
+  }
 }
 
 TEST_F(CORSTest, CheckPreflightDetectsErrors) {
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc
index 66431e6..e97e14d 100644
--- a/services/network/public/cpp/simple_url_loader.cc
+++ b/services/network/public/cpp/simple_url_loader.cc
@@ -206,6 +206,8 @@
       const OnRedirectCallback& on_redirect_callback) override;
   void SetOnResponseStartedCallback(
       OnResponseStartedCallback on_response_started_callback) override;
+  void SetOnUploadProgressCallback(
+      UploadProgressCallback on_upload_progress_callback) override;
   void SetAllowPartialResults(bool allow_partial_results) override;
   void SetAllowHttpErrorResults(bool allow_http_error_results) override;
   void AttachStringForUpload(const std::string& upload_data,
@@ -310,6 +312,7 @@
 
   std::vector<OnRedirectCallback> on_redirect_callback_;
   OnResponseStartedCallback on_response_started_callback_;
+  UploadProgressCallback on_upload_progress_callback_;
   bool allow_partial_results_ = false;
   bool allow_http_error_results_ = false;
 
@@ -1161,6 +1164,12 @@
   DCHECK(on_response_started_callback_);
 }
 
+void SimpleURLLoaderImpl::SetOnUploadProgressCallback(
+    UploadProgressCallback on_upload_progress_callback) {
+  on_upload_progress_callback_ = std::move(on_upload_progress_callback);
+  DCHECK(on_upload_progress_callback_);
+}
+
 void SimpleURLLoaderImpl::SetAllowPartialResults(bool allow_partial_results) {
   // Check if a request has not yet been started.
   DCHECK(!body_handler_);
@@ -1453,7 +1462,11 @@
 void SimpleURLLoaderImpl::OnUploadProgress(
     int64_t current_position,
     int64_t total_size,
-    OnUploadProgressCallback ack_callback) {}
+    OnUploadProgressCallback ack_callback) {
+  if (on_upload_progress_callback_)
+    on_upload_progress_callback_.Run(current_position, total_size);
+  std::move(ack_callback).Run();
+}
 
 void SimpleURLLoaderImpl::OnStartLoadingResponseBody(
     mojo::ScopedDataPipeConsumerHandle body) {
diff --git a/services/network/public/cpp/simple_url_loader.h b/services/network/public/cpp/simple_url_loader.h
index e6c36dd..3655064c 100644
--- a/services/network/public/cpp/simple_url_loader.h
+++ b/services/network/public/cpp/simple_url_loader.h
@@ -116,6 +116,11 @@
       base::OnceCallback<void(const GURL& final_url,
                               const ResourceResponseHead& response_head)>;
 
+  // Callback used when an upload progress is reported. It is safe to
+  // delete the SimpleURLLoader during the callback.
+  using UploadProgressCallback =
+      base::RepeatingCallback<void(uint64_t position, uint64_t total)>;
+
   // Creates a SimpleURLLoader for |resource_request|. The request can be
   // started by calling any one of the Download methods once. The loader may not
   // be reused.
@@ -207,6 +212,11 @@
   virtual void SetOnResponseStartedCallback(
       OnResponseStartedCallback on_response_started_callback) = 0;
 
+  // Sets callback to be invoked during resource uploads to provide
+  // progress information. Callback may delete the SimpleURLLoader.
+  virtual void SetOnUploadProgressCallback(
+      UploadProgressCallback on_upload_progress_callback) = 0;
+
   // Sets whether partially received results are allowed. Defaults to false.
   // When true, if an error is received after reading the body starts or the max
   // allowed body size exceeded, the partial response body that was received
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index 1a8e46e..b008406b8b1 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -78,10 +78,11 @@
 // Returns a string longer than
 // SimpleURLLoader::kMaxUploadStringAsStringLength, to test the path where
 // strings are streamed to the URLLoader.
-std::string GetLongUploadBody() {
+std::string GetLongUploadBody(
+    size_t size = SimpleURLLoader::kMaxUploadStringSizeToCopy) {
   std::string long_string;
-  long_string.reserve(SimpleURLLoader::kMaxUploadStringSizeToCopy);
-  while (long_string.length() <= SimpleURLLoader::kMaxUploadStringSizeToCopy) {
+  long_string.reserve(size);
+  while (long_string.length() <= size) {
     long_string.append(kShortUploadBody);
   }
   return long_string;
@@ -654,6 +655,7 @@
         std::make_unique<network::ResourceRequest>();
     resource_request->url = url;
     resource_request->method = method;
+    resource_request->enable_upload_progress = true;
     return std::make_unique<SimpleLoaderTestHelper>(std::move(resource_request),
                                                     GetParam());
   }
@@ -2888,5 +2890,61 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_P(SimpleURLLoaderTest, OnUploadProgressCallback) {
+  // The size of the payload cannot be bigger than
+  // net::test_server::<anonymous>::kRequestSizeLimit which is
+  // 64Mb. We set a pretty large value in order to ensure multiple
+  // progress update calls even on fast machines.
+  std::string long_string = GetLongUploadBody(63 * 1024 * 1024);
+  std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+      CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+  test_helper->simple_url_loader()->AttachStringForUpload(long_string,
+                                                          "text/plain");
+
+  uint64_t progress = 0;
+  test_helper->simple_url_loader()->SetOnUploadProgressCallback(
+      base::BindRepeating(
+          [](uint64_t* progress, uint64_t current, uint64_t total) {
+            EXPECT_GT(current, *progress);
+            EXPECT_GE(total, current);
+            *progress = current;
+          },
+          base::Unretained(&progress)));
+
+  test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+  EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+  EXPECT_EQ(long_string.size(), progress);
+  if (GetParam() != SimpleLoaderTestHelper::DownloadType::HEADERS_ONLY) {
+    ASSERT_TRUE(test_helper->response_body());
+    EXPECT_EQ(long_string, *test_helper->response_body());
+  }
+}
+
+// Ensure that deleting the SimpleURLLoader in the upload progress
+// callback is safe
+TEST_P(SimpleURLLoaderTest, DeleteInOnUploadProgressCallback) {
+  std::string long_string = GetLongUploadBody();
+  std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+      CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+  test_helper->simple_url_loader()->AttachStringForUpload(long_string,
+                                                          "text/plain");
+
+  SimpleLoaderTestHelper* unowned_test_helper = test_helper.get();
+  base::RunLoop run_loop;
+  unowned_test_helper->simple_url_loader()->SetOnUploadProgressCallback(
+      base::BindRepeating(
+          [](std::unique_ptr<SimpleLoaderTestHelper> test_helper,
+             base::RepeatingClosure quit_closure, uint64_t current,
+             uint64_t total) {
+            test_helper.reset();
+            std::move(quit_closure).Run();
+          },
+          base::Passed(std::move(test_helper)), run_loop.QuitClosure()));
+
+  unowned_test_helper->StartSimpleLoader(url_loader_factory_.get());
+
+  run_loop.Run();
+}
+
 }  // namespace
 }  // namespace network
diff --git a/services/network/public/mojom/cors.mojom b/services/network/public/mojom/cors.mojom
index b0e7b16..7a7e6c6f6 100644
--- a/services/network/public/mojom/cors.mojom
+++ b/services/network/public/mojom/cors.mojom
@@ -90,7 +90,6 @@
   // Not allowed by Access-Control-Allow-Headers in CORS-preflight response.
   kHeaderDisallowedByPreflightResponse,
 
-  // Redirect
-  kRedirectDisallowedScheme,
+  // Cross origin redirect location contains credentials such as 'user:pass'.
   kRedirectContainsCredentials,
 };
diff --git a/services/network/socket_data_pump.h b/services/network/socket_data_pump.h
index 6b36a21..ca732c0 100644
--- a/services/network/socket_data_pump.h
+++ b/services/network/socket_data_pump.h
@@ -14,7 +14,6 @@
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "net/base/address_family.h"
-#include "net/base/completion_callback.h"
 #include "net/base/ip_endpoint.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/net_adapters.h"
diff --git a/services/network/tcp_connected_socket.h b/services/network/tcp_connected_socket.h
index b3240b7..3f37d79 100644
--- a/services/network/tcp_connected_socket.h
+++ b/services/network/tcp_connected_socket.h
@@ -12,7 +12,6 @@
 #include "base/memory/ref_counted.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/address_family.h"
-#include "net/base/completion_callback.h"
 #include "net/base/ip_endpoint.h"
 #include "net/interfaces/address_family.mojom.h"
 #include "net/interfaces/ip_endpoint.mojom.h"
diff --git a/services/network/tcp_socket_unittest.cc b/services/network/tcp_socket_unittest.cc
index eae58e4e..db570fa 100644
--- a/services/network/tcp_socket_unittest.cc
+++ b/services/network/tcp_socket_unittest.cc
@@ -661,7 +661,7 @@
                         mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
                        std::move(callback).Run(result);
                      },
-                     std::move(callback->callback())));
+                     callback->callback()));
     accept_callbacks.push_back(std::move(callback));
   }
 
@@ -688,7 +688,7 @@
                       mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
                      std::move(callback).Run(result);
                    },
-                   std::move(callback->callback())));
+                   callback->callback()));
   EXPECT_EQ(net::OK, callback->WaitForResult());
 }
 
@@ -723,7 +723,7 @@
               mojom::TCPConnectedSocketPtr connected_socket,
               mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
               mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
-            std::move(callback->callback()).Run(result);
+            callback->callback().Run(result);
             connected_socket_result = std::move(connected_socket);
             receive_handle = std::move(receive_pipe_handle);
             send_handle = std::move(send_pipe_handle);
@@ -771,7 +771,7 @@
               mojom::TCPConnectedSocketPtr connected_socket,
               mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
               mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
-            std::move(callback->callback()).Run(result);
+            callback->callback().Run(result);
             connected_socket_result = std::move(connected_socket);
             receive_handle = std::move(receive_pipe_handle);
             send_handle = std::move(send_pipe_handle);
diff --git a/services/network/test/test_utils.cc b/services/network/test/test_utils.cc
index a3a15c69..75f902e 100644
--- a/services/network/test/test_utils.cc
+++ b/services/network/test/test_utils.cc
@@ -13,7 +13,7 @@
 
 std::string GetUploadData(const network::ResourceRequest& request) {
   auto body = request.request_body;
-  if (!body)
+  if (!body || body->elements()->empty())
     return std::string();
 
   CHECK_EQ(1u, body->elements()->size());
diff --git a/services/network/throttling/throttling_controller_unittest.cc b/services/network/throttling/throttling_controller_unittest.cc
index 1864e646..c23ad02f 100644
--- a/services/network/throttling/throttling_controller_unittest.cc
+++ b/services/network/throttling/throttling_controller_unittest.cc
@@ -10,12 +10,14 @@
 #include <string>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "net/base/chunked_upload_data_stream.h"
+#include "net/base/completion_repeating_callback.h"
 #include "net/http/http_transaction_test_util.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_with_source.h"
@@ -57,8 +59,8 @@
  public:
   ThrottlingControllerTestHelper()
       : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()),
-        completion_callback_(
-            base::Bind(&TestCallback::Run, base::Unretained(&callback_))),
+        completion_callback_(base::BindRepeating(&TestCallback::Run,
+                                                 base::Unretained(&callback_))),
         mock_transaction_(kSimpleGET_Transaction),
         buffer_(new net::IOBuffer(64)),
         net_log_(std::make_unique<net::NetLog>()),
@@ -151,7 +153,7 @@
   base::MessageLoop message_loop_;
   MockNetworkLayer network_layer_;
   TestCallback callback_;
-  net::CompletionCallback completion_callback_;
+  net::CompletionRepeatingCallback completion_callback_;
   MockTransaction mock_transaction_;
   std::unique_ptr<ThrottlingNetworkTransaction> transaction_;
   scoped_refptr<net::IOBuffer> buffer_;
diff --git a/services/network/throttling/throttling_upload_data_stream.h b/services/network/throttling/throttling_upload_data_stream.h
index 1b881362..fe1b318 100644
--- a/services/network/throttling/throttling_upload_data_stream.h
+++ b/services/network/throttling/throttling_upload_data_stream.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "net/base/completion_callback.h"
 #include "net/base/upload_data_stream.h"
 #include "services/network/throttling/throttling_network_interceptor.h"
 
diff --git a/services/network/tls_client_socket_unittest.cc b/services/network/tls_client_socket_unittest.cc
index 09bd80b7..8d1242f 100644
--- a/services/network/tls_client_socket_unittest.cc
+++ b/services/network/tls_client_socket_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
-#include "net/base/completion_callback.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
diff --git a/services/network/udp_socket.cc b/services/network/udp_socket.cc
index a02c956..5de2447 100644
--- a/services/network/udp_socket.cc
+++ b/services/network/udp_socket.cc
@@ -67,9 +67,9 @@
       net::IOBuffer* buf,
       int buf_len,
       const net::IPEndPoint& dest_addr,
-      const net::CompletionCallback& callback,
+      net::CompletionOnceCallback callback,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
-    return socket_.SendTo(buf, buf_len, dest_addr, callback);
+    return socket_.SendTo(buf, buf_len, dest_addr, std::move(callback));
   }
   int SetBroadcast(bool broadcast) override {
     return socket_.SetBroadcast(broadcast);
@@ -83,15 +83,15 @@
   int Write(
       net::IOBuffer* buf,
       int buf_len,
-      const net::CompletionCallback& callback,
+      net::CompletionOnceCallback callback,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
-    return socket_.Write(buf, buf_len, callback, traffic_annotation);
+    return socket_.Write(buf, buf_len, std::move(callback), traffic_annotation);
   }
   int RecvFrom(net::IOBuffer* buf,
                int buf_len,
                net::IPEndPoint* address,
-               const net::CompletionCallback& callback) override {
-    return socket_.RecvFrom(buf, buf_len, address, callback);
+               net::CompletionOnceCallback callback) override {
+    return socket_.RecvFrom(buf, buf_len, address, std::move(callback));
   }
 
  private:
diff --git a/services/network/udp_socket.h b/services/network/udp_socket.h
index b5b627a..84fbf90 100644
--- a/services/network/udp_socket.h
+++ b/services/network/udp_socket.h
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/address_family.h"
-#include "net/base/completion_callback.h"
+#include "net/base/completion_once_callback.h"
 #include "net/base/ip_endpoint.h"
 #include "net/interfaces/address_family.mojom.h"
 #include "net/interfaces/ip_endpoint.mojom.h"
@@ -53,12 +53,12 @@
         net::IOBuffer* buf,
         int buf_len,
         const net::IPEndPoint& dest_addr,
-        const net::CompletionCallback& callback,
+        net::CompletionOnceCallback callback,
         const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
     virtual int Write(
         net::IOBuffer* buf,
         int buf_len,
-        const net::CompletionCallback& callback,
+        net::CompletionOnceCallback callback,
         const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
     virtual int SetBroadcast(bool broadcast) = 0;
     virtual int JoinGroup(const net::IPAddress& group_address) = 0;
@@ -66,7 +66,7 @@
     virtual int RecvFrom(net::IOBuffer* buf,
                          int buf_len,
                          net::IPEndPoint* address,
-                         const net::CompletionCallback& callback) = 0;
+                         net::CompletionOnceCallback callback) = 0;
   };
 
   UDPSocket(mojom::UDPSocketReceiverPtr receiver, net::NetLog* net_log);
diff --git a/services/network/udp_socket_unittest.cc b/services/network/udp_socket_unittest.cc
index 3571b23..1f29183 100644
--- a/services/network/udp_socket_unittest.cc
+++ b/services/network/udp_socket_unittest.cc
@@ -53,7 +53,7 @@
       net::IOBuffer* buf,
       int buf_len,
       const net::IPEndPoint& dest_addr,
-      const net::CompletionCallback& callback,
+      net::CompletionOnceCallback callback,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTREACHED();
     return net::ERR_NOT_IMPLEMENTED;
@@ -73,7 +73,7 @@
   int Write(
       net::IOBuffer* buf,
       int buf_len,
-      const net::CompletionCallback& callback,
+      net::CompletionOnceCallback callback,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     NOTREACHED();
     return net::ERR_NOT_IMPLEMENTED;
@@ -81,7 +81,7 @@
   int RecvFrom(net::IOBuffer* buf,
                int buf_len,
                net::IPEndPoint* address,
-               const net::CompletionCallback& callback) override {
+               net::CompletionOnceCallback callback) override {
     NOTREACHED();
     return net::ERR_NOT_IMPLEMENTED;
   }
@@ -116,7 +116,7 @@
       net::IOBuffer* buf,
       int buf_len,
       const net::IPEndPoint& address,
-      const net::CompletionCallback& callback,
+      net::CompletionOnceCallback callback,
       const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     EXPECT_EQ(expected_data_,
               std::vector<unsigned char>(buf->data(), buf->data() + buf_len));
@@ -124,7 +124,7 @@
       return net::OK;
     pending_io_buffers_.push_back(buf);
     pending_io_buffer_lengths_.push_back(buf_len);
-    pending_send_requests_.push_back(callback);
+    pending_send_requests_.push_back(std::move(callback));
     return net::ERR_IO_PENDING;
   }
 
@@ -143,8 +143,8 @@
   // Completes all pending requests.
   void CompleteAllPendingRequests() {
     should_complete_requests_ = true;
-    for (auto request : pending_send_requests_) {
-      request.Run(net::OK);
+    for (auto& request : pending_send_requests_) {
+      std::move(request).Run(net::OK);
     }
     pending_send_requests_.clear();
   }
@@ -154,7 +154,7 @@
   bool should_complete_requests_ = false;
   std::vector<net::IOBuffer*> pending_io_buffers_;
   std::vector<int> pending_io_buffer_lengths_;
-  std::vector<net::CompletionCallback> pending_send_requests_;
+  std::vector<net::CompletionOnceCallback> pending_send_requests_;
 };
 
 // A Mock UDPSocket that returns 0 byte read.
@@ -169,7 +169,7 @@
   int RecvFrom(net::IOBuffer* buf,
                int buf_len,
                net::IPEndPoint* address,
-               const net::CompletionCallback& callback) override {
+               net::CompletionOnceCallback callback) override {
     *address = GetLocalHostWithAnyPort();
     return 0;
   }
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 1584563..e682291 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -676,14 +676,16 @@
                  base::Unretained(this)));
 
   // Figure out if we need to sniff (for MIME type detection or for CORB).
-  if (factory_params_->is_corb_enabled && !is_nocors_corb_excluded_request_) {
+  if (factory_params_->is_corb_enabled && !is_nocors_corb_excluded_request_ &&
+      (factory_params_->corb_excluded_initiator_scheme.empty() ||
+       factory_params_->corb_excluded_initiator_scheme !=
+           url_request->initiator().value_or(url::Origin()).scheme())) {
     CrossOriginReadBlocking::LogAction(
         CrossOriginReadBlocking::Action::kResponseStarted);
 
     corb_analyzer_ =
         std::make_unique<CrossOriginReadBlocking::ResponseAnalyzer>(
-            *url_request_, *response_,
-            factory_params_->corb_excluded_initiator_scheme);
+            *url_request_, *response_);
     is_more_corb_sniffing_needed_ = corb_analyzer_->needs_sniffing();
     if (corb_analyzer_->ShouldBlock()) {
       DCHECK(!is_more_corb_sniffing_needed_);
diff --git a/services/preferences/persistent_pref_store_impl.cc b/services/preferences/persistent_pref_store_impl.cc
index 68f9b1a..a0df6d6 100644
--- a/services/preferences/persistent_pref_store_impl.cc
+++ b/services/preferences/persistent_pref_store_impl.cc
@@ -129,6 +129,10 @@
   }
 
   void CommitPendingWrite(CommitPendingWriteCallback done_callback) override {
+    // Note: PersistentPrefStore's synchronous callback part of the
+    // CommitPendingWrite() API isn't supported on mojom::PersistentPrefStore at
+    // the moment (see PersistentPrefStoreClient::CommitPendingWrite() for
+    // details).
     pref_store_->CommitPendingWrite(std::move(done_callback));
   }
   void SchedulePendingLossyWrites() override {
diff --git a/services/preferences/persistent_pref_store_impl_unittest.cc b/services/preferences/persistent_pref_store_impl_unittest.cc
index 1291be4..152a2d70 100644
--- a/services/preferences/persistent_pref_store_impl_unittest.cc
+++ b/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -23,9 +23,12 @@
 
 class PersistentPrefStoreMock : public InMemoryPrefStore {
  public:
-  void CommitPendingWrite(base::OnceClosure callback) override {
+  void CommitPendingWrite(
+      base::OnceClosure reply_callback,
+      base::OnceClosure synchronous_done_callback) override {
     CommitPendingWriteMock();
-    InMemoryPrefStore::CommitPendingWrite(std::move(callback));
+    InMemoryPrefStore::CommitPendingWrite(std::move(reply_callback),
+                                          std::move(synchronous_done_callback));
   }
 
   MOCK_METHOD0(CommitPendingWriteMock, void());
diff --git a/services/preferences/public/cpp/persistent_pref_store_client.cc b/services/preferences/public/cpp/persistent_pref_store_client.cc
index 8c83478..47d806c 100644
--- a/services/preferences/public/cpp/persistent_pref_store_client.cc
+++ b/services/preferences/public/cpp/persistent_pref_store_client.cc
@@ -225,11 +225,17 @@
     ReadErrorDelegate* error_delegate) {}
 
 void PersistentPrefStoreClient::CommitPendingWrite(
-    base::OnceClosure done_callback) {
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
+  // Supporting |synchronous_done_callback| semantics would require a sync IPC.
+  // This isn't implemented as such at the moment as this functionality isn't
+  // used in practice (if it ever becomes necessary, this check will fire).
+  DCHECK(!synchronous_done_callback);
+
   DCHECK(pref_store_);
   if (!pending_writes_.empty())
     FlushPendingWrites();
-  pref_store_->CommitPendingWrite(std::move(done_callback));
+  pref_store_->CommitPendingWrite(std::move(reply_callback));
 }
 
 void PersistentPrefStoreClient::SchedulePendingLossyWrites() {
@@ -251,7 +257,7 @@
   if (!pref_store_)
     return;
 
-  CommitPendingWrite(base::OnceClosure());
+  CommitPendingWrite();
 }
 
 void PersistentPrefStoreClient::QueueWrite(
diff --git a/services/preferences/public/cpp/persistent_pref_store_client.h b/services/preferences/public/cpp/persistent_pref_store_client.h
index 51561f4..d863f14 100644
--- a/services/preferences/public/cpp/persistent_pref_store_client.h
+++ b/services/preferences/public/cpp/persistent_pref_store_client.h
@@ -54,7 +54,10 @@
   PrefReadError GetReadError() const override;
   PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
-  void CommitPendingWrite(base::OnceClosure done_callback) override;
+  void CommitPendingWrite(
+      base::OnceClosure reply_callback = base::OnceClosure(),
+      base::OnceClosure synchronous_done_callback =
+          base::OnceClosure()) override;
   void SchedulePendingLossyWrites() override;
   void ClearMutableValues() override;
   void OnStoreDeletionFromDisk() override;
diff --git a/services/preferences/tracked/segregated_pref_store.cc b/services/preferences/tracked/segregated_pref_store.cc
index 1fae1507..f62cc4d 100644
--- a/services/preferences/tracked/segregated_pref_store.cc
+++ b/services/preferences/tracked/segregated_pref_store.cc
@@ -161,12 +161,27 @@
   selected_pref_store_->ReadPrefsAsync(NULL);
 }
 
-void SegregatedPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
-  base::RepeatingClosure done_callback_wrapper =
-      done_callback ? base::BarrierClosure(2, std::move(done_callback))
-                    : base::RepeatingClosure();
-  default_pref_store_->CommitPendingWrite(done_callback_wrapper);
-  selected_pref_store_->CommitPendingWrite(done_callback_wrapper);
+void SegregatedPrefStore::CommitPendingWrite(
+    base::OnceClosure reply_callback,
+    base::OnceClosure synchronous_done_callback) {
+  // A BarrierClosure will run its callback wherever the last instance of the
+  // returned wrapper is invoked. As such it is guaranteed to respect the reply
+  // vs synchronous semantics assuming |default_pref_store_| and
+  // |selected_pref_store_| honor it.
+
+  base::RepeatingClosure reply_callback_wrapper =
+      reply_callback ? base::BarrierClosure(2, std::move(reply_callback))
+                     : base::RepeatingClosure();
+
+  base::RepeatingClosure synchronous_callback_wrapper =
+      synchronous_done_callback
+          ? base::BarrierClosure(2, std::move(synchronous_done_callback))
+          : base::RepeatingClosure();
+
+  default_pref_store_->CommitPendingWrite(reply_callback_wrapper,
+                                          synchronous_callback_wrapper);
+  selected_pref_store_->CommitPendingWrite(reply_callback_wrapper,
+                                           synchronous_callback_wrapper);
 }
 
 void SegregatedPrefStore::SchedulePendingLossyWrites() {
diff --git a/services/preferences/tracked/segregated_pref_store.h b/services/preferences/tracked/segregated_pref_store.h
index 1a43e50..18bdaef 100644
--- a/services/preferences/tracked/segregated_pref_store.h
+++ b/services/preferences/tracked/segregated_pref_store.h
@@ -72,7 +72,10 @@
   PrefReadError GetReadError() const override;
   PrefReadError ReadPrefs() override;
   void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
-  void CommitPendingWrite(base::OnceClosure done_callback) override;
+  void CommitPendingWrite(
+      base::OnceClosure reply_callback = base::OnceClosure(),
+      base::OnceClosure synchronous_done_callback =
+          base::OnceClosure()) override;
   void SchedulePendingLossyWrites() override;
   void ClearMutableValues() override;
   void OnStoreDeletionFromDisk() override;
diff --git a/services/preferences/tracked/segregated_pref_store_unittest.cc b/services/preferences/tracked/segregated_pref_store_unittest.cc
index 61b76efe..c9db593 100644
--- a/services/preferences/tracked/segregated_pref_store_unittest.cc
+++ b/services/preferences/tracked/segregated_pref_store_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/values.h"
 #include "components/prefs/persistent_pref_store.h"
@@ -56,8 +57,13 @@
 };
 
 enum class CommitPendingWriteMode {
+  // Basic mode.
   WITHOUT_CALLBACK,
+  // With reply callback.
   WITH_CALLBACK,
+  // With synchronous notify callback (synchronous after the write -- shouldn't
+  // require pumping messages to observe).
+  WITH_SYNCHRONOUS_CALLBACK,
 };
 
 class SegregatedPrefStoreTest
@@ -131,13 +137,28 @@
   ASSERT_FALSE(selected_store_->committed());
   ASSERT_FALSE(default_store_->committed());
 
-  if (GetParam() == CommitPendingWriteMode::WITHOUT_CALLBACK) {
-    segregated_store_->CommitPendingWrite(base::OnceClosure());
-    base::RunLoop().RunUntilIdle();
-  } else {
-    base::RunLoop run_loop;
-    segregated_store_->CommitPendingWrite(run_loop.QuitClosure());
-    run_loop.Run();
+  switch (GetParam()) {
+    case CommitPendingWriteMode::WITHOUT_CALLBACK: {
+      segregated_store_->CommitPendingWrite();
+      base::RunLoop().RunUntilIdle();
+      break;
+    }
+
+    case CommitPendingWriteMode::WITH_CALLBACK: {
+      base::RunLoop run_loop;
+      segregated_store_->CommitPendingWrite(run_loop.QuitClosure());
+      run_loop.Run();
+      break;
+    }
+
+    case CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK: {
+      base::WaitableEvent written;
+      segregated_store_->CommitPendingWrite(
+          base::OnceClosure(),
+          base::BindOnce(&base::WaitableEvent::Signal, Unretained(&written)));
+      written.Wait();
+      break;
+    }
   }
 
   ASSERT_TRUE(selected_store_->committed());
@@ -327,3 +348,7 @@
     WithCallback,
     SegregatedPrefStoreTest,
     ::testing::Values(CommitPendingWriteMode::WITH_CALLBACK));
+INSTANTIATE_TEST_CASE_P(
+    WithSynchronousCallback,
+    SegregatedPrefStoreTest,
+    ::testing::Values(CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK));
diff --git a/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
index 80c37a2..44d2522e 100644
--- a/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
+++ b/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -123,12 +123,12 @@
   PrefHashFilter* raw_protected_pref_hash_filter =
       protected_pref_hash_filter.get();
 
-  scoped_refptr<JsonPrefStore> unprotected_pref_store(
-      new JsonPrefStore(config->unprotected_pref_filename, io_task_runner.get(),
-                        std::move(unprotected_pref_hash_filter)));
-  scoped_refptr<JsonPrefStore> protected_pref_store(
-      new JsonPrefStore(config->protected_pref_filename, io_task_runner.get(),
-                        std::move(protected_pref_hash_filter)));
+  scoped_refptr<JsonPrefStore> unprotected_pref_store(new JsonPrefStore(
+      config->unprotected_pref_filename,
+      std::move(unprotected_pref_hash_filter), io_task_runner.get()));
+  scoped_refptr<JsonPrefStore> protected_pref_store(new JsonPrefStore(
+      config->protected_pref_filename, std::move(protected_pref_hash_filter),
+      io_task_runner.get()));
 
   SetupTrackedPreferencesMigration(
       unprotected_pref_names, protected_pref_names,
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_features.cc b/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
index b1ea6a7..9b0ffa03 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
@@ -25,6 +25,10 @@
 const base::Feature kPageAlmostIdle{"PageAlmostIdle",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables CPU/memory performance measurements on PageAlmostIdle events.
+const base::Feature kPerformanceMeasurement{"PerformanceMeasurement",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 namespace resource_coordinator {
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_features.h b/services/resource_coordinator/public/cpp/resource_coordinator_features.h
index ec485ac0..14f1fba6 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_features.h
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_features.h
@@ -19,6 +19,8 @@
     kGlobalResourceCoordinator;
 extern const SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT base::Feature
     kPageAlmostIdle;
+extern const SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT base::Feature
+    kPerformanceMeasurement;
 
 }  // namespace features
 
diff --git a/services/service_manager/README.md b/services/service_manager/README.md
index a5fbbc27..e8f3981 100644
--- a/services/service_manager/README.md
+++ b/services/service_manager/README.md
@@ -107,7 +107,7 @@
 
   // service_manager::Service:
   void OnStart() override;
-  void OnBindInterface(const service_manager::ServiceInfo& remote_info,
+  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle handle) override;
  private:
diff --git a/services/service_manager/sandbox/BUILD.gn b/services/service_manager/sandbox/BUILD.gn
index 9b0d5b0..1974757 100644
--- a/services/service_manager/sandbox/BUILD.gn
+++ b/services/service_manager/sandbox/BUILD.gn
@@ -8,6 +8,8 @@
 component("sandbox") {
   sources = [
     "export.h",
+    "features.cc",
+    "features.h",
     "sandbox.cc",
     "sandbox.h",
     "sandbox_delegate.h",
@@ -83,8 +85,6 @@
   }
   if (is_win) {
     sources += [
-      "features.cc",
-      "features.h",
       "win/sandbox_win.cc",
       "win/sandbox_win.h",
     ]
diff --git a/services/service_manager/sandbox/mac/BUILD.gn b/services/service_manager/sandbox/mac/BUILD.gn
index 277202f..1400738 100644
--- a/services/service_manager/sandbox/mac/BUILD.gn
+++ b/services/service_manager/sandbox/mac/BUILD.gn
@@ -5,6 +5,7 @@
 action_foreach("package_sb_files") {
   script = "package_sb_file.py"
   sources = [
+    "audio.sb",
     "cdm.sb",
     "common.sb",
     "common_v2.sb",
diff --git a/services/service_manager/sandbox/mac/audio.sb b/services/service_manager/sandbox/mac/audio.sb
new file mode 100644
index 0000000..775cc12
--- /dev/null
+++ b/services/service_manager/sandbox/mac/audio.sb
@@ -0,0 +1,46 @@
+; 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.
+
+; --- The contents of common.sb implicitly included here. ---
+
+; File access.
+(allow file-read*
+  (path (user-homedir-path "/Library/Caches/com.apple.coreaudio.components.plist"))
+  (regex (user-homedir-path #"/Library/Preferences/com.apple.coreaudio.*"))
+  (subpath (user-homedir-path "/Library/Audio/Plug-Ins"))
+  (subpath "/Library/Audio/Plug-Ins")
+  (subpath "/Library/Video/Plug-Ins")
+  (subpath "/Library/QuickTime")
+  (subpath "/System/Library/Components")
+  (subpath "/System/Library/Extensions"))
+
+(allow device-microphone)
+
+(allow iokit-open
+  (iokit-user-client-class "IOAudioControlUserClient")
+  (iokit-user-client-class "IOAudioEngineUserClient"))
+
+(allow ipc-posix-shm-read* ipc-posix-shm-write-data
+  (ipc-posix-name-regex #"^AudioIO"))
+
+; Mach IPC.
+(allow mach-lookup
+  (global-name "com.apple.audio.SystemSoundServer-OSX")
+  (global-name "com.apple.audio.VDCAssistant")
+  (global-name "com.apple.audio.coreaudiod")
+  (global-name "com.apple.audio.audiohald"))
+
+(if (>= os-version 1013)
+  (allow mach-lookup
+    (global-name "com.apple.audio.AudioComponentRegistrar")
+    (xpc-service-name "com.apple.audio.SandboxHelper")))
+
+; sysctls.
+(allow sysctl-read
+  (sysctl-name "hw.optional.avx2_0")
+  (sysctl-name "hw.optional.avx1_0")
+  (sysctl-name "hw.optional.sse4_2")
+  (sysctl-name "hw.optional.sse4_1")
+  (sysctl-name "hw.optional.sse3")
+  (sysctl-name "hw.optional.sse2"))
diff --git a/services/service_manager/sandbox/mac/common_v2.sb b/services/service_manager/sandbox/mac/common_v2.sb
index 8ec6abd..be20890 100644
--- a/services/service_manager/sandbox/mac/common_v2.sb
+++ b/services/service_manager/sandbox/mac/common_v2.sb
@@ -85,8 +85,9 @@
 (allow file-read* (subpath (param bundle-path)))
 
 ; Allow reads of system libraries and frameworks.
-(allow file-read-data
+(allow file-read*
   (subpath "/System/Library/Frameworks")
+  (subpath "/System/Library/Preferences/Logging")
   (subpath "/System/Library/PrivateFrameworks")
   (subpath "/usr/lib"))
 
diff --git a/services/service_manager/sandbox/mac/sandbox_mac.mm b/services/service_manager/sandbox/mac/sandbox_mac.mm
index d69fcc0..36b90f6 100644
--- a/services/service_manager/sandbox/mac/sandbox_mac.mm
+++ b/services/service_manager/sandbox/mac/sandbox_mac.mm
@@ -38,6 +38,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "sandbox/mac/sandbox_compiler.h"
+#include "services/service_manager/sandbox/mac/audio.sb.h"
 #include "services/service_manager/sandbox/mac/cdm.sb.h"
 #include "services/service_manager/sandbox/mac/common.sb.h"
 #include "services/service_manager/sandbox/mac/gpu.sb.h"
@@ -62,7 +63,6 @@
 // Mapping from sandbox process types to resource IDs containing the sandbox
 // profile for all process types known to service_manager.
 // TODO(tsepez): Implement profile for SANDBOX_TYPE_NETWORK.
-// TODO(https://crbug.com/850878): Implement profile for SANDBOX_TYPE_AUDIO.
 SandboxTypeToResourceIDMapping kDefaultSandboxTypeToResourceIDMapping[] = {
     {SANDBOX_TYPE_NO_SANDBOX, nullptr},
     {SANDBOX_TYPE_RENDERER, kSeatbeltPolicyString_renderer},
@@ -74,7 +74,7 @@
     {SANDBOX_TYPE_NACL_LOADER, kSeatbeltPolicyString_nacl_loader},
     {SANDBOX_TYPE_PDF_COMPOSITOR, kSeatbeltPolicyString_ppapi},
     {SANDBOX_TYPE_PROFILING, kSeatbeltPolicyString_utility},
-    {SANDBOX_TYPE_AUDIO, nullptr},
+    {SANDBOX_TYPE_AUDIO, kSeatbeltPolicyString_audio},
 };
 
 static_assert(arraysize(kDefaultSandboxTypeToResourceIDMapping) ==
diff --git a/services/service_manager/sandbox/sandbox_type.cc b/services/service_manager/sandbox/sandbox_type.cc
index cfd27c1..9a9568a1 100644
--- a/services/service_manager/sandbox/sandbox_type.cc
+++ b/services/service_manager/sandbox/sandbox_type.cc
@@ -7,11 +7,8 @@
 #include <string>
 
 #include "base/feature_list.h"
-#include "services/service_manager/sandbox/switches.h"
-
-#if defined(OS_WIN)
 #include "services/service_manager/sandbox/features.h"
-#endif
+#include "services/service_manager/sandbox/switches.h"
 
 namespace service_manager {
 
@@ -24,7 +21,7 @@
       return true;
 #endif
     case SANDBOX_TYPE_AUDIO:
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
       return !base::FeatureList::IsEnabled(
           service_manager::features::kAudioServiceSandbox);
 #else
diff --git a/services/shape_detection/text_detection_impl_win.cc b/services/shape_detection/text_detection_impl_win.cc
index 051022f..feff2624 100644
--- a/services/shape_detection/text_detection_impl_win.cc
+++ b/services/shape_detection/text_detection_impl_win.cc
@@ -15,6 +15,7 @@
 #include "base/win/windows_version.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/shape_detection/text_detection_impl.h"
+#include "ui/gfx/geometry/rect_f.h"
 
 namespace shape_detection {
 
@@ -23,6 +24,8 @@
 using ABI::Windows::Media::Ocr::IOcrEngineStatics;
 using ABI::Windows::Media::Ocr::IOcrLine;
 using ABI::Windows::Media::Ocr::OcrLine;
+using ABI::Windows::Media::Ocr::IOcrWord;
+using ABI::Windows::Media::Ocr::OcrWord;
 using base::win::GetActivationFactory;
 using base::win::ScopedHString;
 
@@ -200,7 +203,34 @@
     if (FAILED(hr))
       break;
 
+    // Gets bounding box with the words detected in the current line of Text.
+    Microsoft::WRL::ComPtr<IVectorView<OcrWord*>> ocr_words;
+    hr = line->get_Words(ocr_words.GetAddressOf());
+    if (FAILED(hr))
+      break;
+
+    uint32_t words_count;
+    hr = ocr_words->get_Size(&words_count);
+    if (FAILED(hr))
+      break;
+
     auto result = shape_detection::mojom::TextDetectionResult::New();
+    for (uint32_t i = 0; i < words_count; ++i) {
+      Microsoft::WRL::ComPtr<IOcrWord> word;
+      hr = ocr_words->GetAt(i, &word);
+      if (FAILED(hr))
+        break;
+
+      ABI::Windows::Foundation::Rect bounds;
+      hr = word->get_BoundingRect(&bounds);
+      if (FAILED(hr))
+        break;
+
+      result->bounding_box = gfx::UnionRects(
+          result->bounding_box,
+          gfx::RectF(bounds.X, bounds.Y, bounds.Width, bounds.Height));
+    }
+
     result->raw_value = ScopedHString(text).GetAsUTF8();
     results.push_back(std::move(result));
   }
diff --git a/services/shape_detection/text_detection_impl_win_unittest.cc b/services/shape_detection/text_detection_impl_win_unittest.cc
index 427fe276..c05d16d 100644
--- a/services/shape_detection/text_detection_impl_win_unittest.cc
+++ b/services/shape_detection/text_detection_impl_win_unittest.cc
@@ -89,7 +89,9 @@
   run_loop.Run();
   ASSERT_EQ(2u, results.size());
   EXPECT_EQ("The Chromium Project website is:", results[0]->raw_value);
+  EXPECT_EQ(gfx::RectF(51, 38, 272, 17), results[0]->bounding_box);
   EXPECT_EQ("https://www.chromium.org", results[1]->raw_value);
+  EXPECT_EQ(gfx::RectF(51, 63, 209, 17), results[1]->bounding_box);
 }
 
 }  // namespace shape_detection
diff --git a/services/ui/ws2/server_window.cc b/services/ui/ws2/server_window.cc
index 00ad453b..73d22ac 100644
--- a/services/ui/ws2/server_window.cc
+++ b/services/ui/ws2/server_window.cc
@@ -457,9 +457,6 @@
 
   additional_client_areas_ = additional_client_areas;
   client_area_ = insets;
-
-  // TODO(sky): update cursor if over this window.
-  NOTIMPLEMENTED_LOG_ONCE();
 }
 
 void ServerWindow::SetCaptureOwner(WindowTree* owner) {
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index c2d7424..86d1ac6c 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -197,6 +197,8 @@
 #define SK_SUPPORT_LEGACY_AAA_CHOICE
 #endif
 
+#define SK_LEGACY_COLORSPACE_XFORMER_IMPL
+
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/storage/browser/database/database_quota_client.cc b/storage/browser/database/database_quota_client.cc
index beae9b2f..84bb06c 100644
--- a/storage/browser/database/database_quota_client.cc
+++ b/storage/browser/database/database_quota_client.cc
@@ -62,8 +62,8 @@
   }
 }
 
-void DidGetOrigins(QuotaClient::GetOriginsCallback callback,
-                   std::set<url::Origin>* origins_ptr) {
+void DidGetQuotaClientOrigins(QuotaClient::GetOriginsCallback callback,
+                              std::set<url::Origin>* origins_ptr) {
   std::move(callback).Run(*origins_ptr);
 }
 
@@ -145,7 +145,7 @@
       FROM_HERE,
       base::BindOnce(&GetOriginsOnDBThread, base::RetainedRef(db_tracker_),
                      base::Unretained(origins_ptr)),
-      base::BindOnce(&DidGetOrigins, std::move(callback),
+      base::BindOnce(&DidGetQuotaClientOrigins, std::move(callback),
                      base::Owned(origins_ptr)));
 }
 
@@ -167,7 +167,7 @@
       base::BindOnce(&GetOriginsForHostOnDBThread,
                      base::RetainedRef(db_tracker_),
                      base::Unretained(origins_ptr), host),
-      base::BindOnce(&DidGetOrigins, std::move(callback),
+      base::BindOnce(&DidGetQuotaClientOrigins, std::move(callback),
                      base::Owned(origins_ptr)));
 }
 
diff --git a/storage/browser/database/database_tracker.cc b/storage/browser/database/database_tracker.cc
index d33b7067..e18b818 100644
--- a/storage/browser/database/database_tracker.cc
+++ b/storage/browser/database/database_tracker.cc
@@ -37,8 +37,8 @@
     FILE_PATH_LITERAL("databases-incognito");
 const base::FilePath::CharType kTrackerDatabaseFileName[] =
     FILE_PATH_LITERAL("Databases.db");
-static const int kCurrentVersion = 2;
-static const int kCompatibleVersion = 1;
+static const int kDatabaseTrackerCurrentSchemaVersion = 2;
+static const int kDatabaseTrackerCompatibleVersion = 1;
 
 const base::FilePath::CharType kTemporaryDirectoryPrefix[] =
     FILE_PATH_LITERAL("DeleteMe");
@@ -499,13 +499,15 @@
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   sql::Transaction transaction(db_.get());
   if (!transaction.Begin() ||
-      !meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion) ||
-      (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) ||
+      !meta_table_->Init(db_.get(), kDatabaseTrackerCurrentSchemaVersion,
+                         kDatabaseTrackerCompatibleVersion) ||
+      (meta_table_->GetCompatibleVersionNumber() >
+       kDatabaseTrackerCurrentSchemaVersion) ||
       !databases_table_->Init())
     return false;
 
-  if (meta_table_->GetVersionNumber() < kCurrentVersion)
-    meta_table_->SetVersionNumber(kCurrentVersion);
+  if (meta_table_->GetVersionNumber() < kDatabaseTrackerCurrentSchemaVersion)
+    meta_table_->SetVersionNumber(kDatabaseTrackerCurrentSchemaVersion);
 
   return transaction.Commit();
 }
diff --git a/storage/browser/fileapi/file_system_quota_client.cc b/storage/browser/fileapi/file_system_quota_client.cc
index af56ba2..fc30594a 100644
--- a/storage/browser/fileapi/file_system_quota_client.cc
+++ b/storage/browser/fileapi/file_system_quota_client.cc
@@ -58,8 +58,9 @@
     origins_ptr->insert(url::Origin::Create(origin));
 }
 
-void DidGetOrigins(storage::QuotaClient::GetOriginsCallback callback,
-                   std::set<url::Origin>* origins_ptr) {
+void DidGetFileSystemQuotaClientOrigins(
+    storage::QuotaClient::GetOriginsCallback callback,
+    std::set<url::Origin>* origins_ptr) {
   std::move(callback).Run(*origins_ptr);
 }
 
@@ -144,7 +145,7 @@
       base::BindOnce(&GetOriginsForTypeOnFileTaskRunner,
                      base::RetainedRef(file_system_context_), storage_type,
                      base::Unretained(origins_ptr)),
-      base::BindOnce(&DidGetOrigins, std::move(callback),
+      base::BindOnce(&DidGetFileSystemQuotaClientOrigins, std::move(callback),
                      base::Owned(origins_ptr)));
 }
 
@@ -166,7 +167,7 @@
       base::BindOnce(&GetOriginsForHostOnFileTaskRunner,
                      base::RetainedRef(file_system_context_), storage_type,
                      host, base::Unretained(origins_ptr)),
-      base::BindOnce(&DidGetOrigins, std::move(callback),
+      base::BindOnce(&DidGetFileSystemQuotaClientOrigins, std::move(callback),
                      base::Owned(origins_ptr)));
 }
 
diff --git a/storage/browser/fileapi/sandbox_directory_database.cc b/storage/browser/fileapi/sandbox_directory_database.cc
index b2660c9..f9a2482 100644
--- a/storage/browser/fileapi/sandbox_directory_database.cc
+++ b/storage/browser/fileapi/sandbox_directory_database.cc
@@ -72,16 +72,17 @@
     FILE_PATH_LITERAL("Paths");
 const char kChildLookupPrefix[] = "CHILD_OF:";
 const char kChildLookupSeparator[] = ":";
-const char kLastFileIdKey[] = "LAST_FILE_ID";
-const char kLastIntegerKey[] = "LAST_INTEGER";
-const int64_t kMinimumReportIntervalHours = 1;
-const char kInitStatusHistogramLabel[] = "FileSystem.DirectoryDatabaseInit";
-const char kDatabaseRepairHistogramLabel[] =
+const char kSandboxDirectoryLastFileIdKey[] = "LAST_FILE_ID";
+const char kSandboxDirectoryLastIntegerKey[] = "LAST_INTEGER";
+const int64_t kSandboxDirectoryMinimumReportIntervalHours = 1;
+const char kSandboxDirectoryInitStatusHistogramLabel[] =
+    "FileSystem.DirectoryDatabaseInit";
+const char kSandboxDirectoryDatabaseRepairHistogramLabel[] =
     "FileSystem.DirectoryDatabaseRepair";
 
 // These values are recorded in UMA. Changing existing values will invalidate
 // results for older Chrome releases. Only add new values.
-enum InitStatus {
+enum class SandboxDirectoryInitStatus {
   INIT_STATUS_OK = 0,
   INIT_STATUS_CORRUPTION,
   INIT_STATUS_IO_ERROR,
@@ -91,7 +92,7 @@
 
 // These values are recorded in UMA. Changing existing values will invalidate
 // results for older Chrome releases. Only add new values.
-enum RepairResult {
+enum class SandboxDirectoryRepairResult {
   DB_REPAIR_SUCCEEDED = 0,
   DB_REPAIR_FAILED,
   DB_REPAIR_MAX
@@ -113,11 +114,11 @@
 }
 
 const char* LastFileIdKey() {
-  return kLastFileIdKey;
+  return kSandboxDirectoryLastFileIdKey;
 }
 
 const char* LastIntegerKey() {
-  return kLastIntegerKey;
+  return kSandboxDirectoryLastIntegerKey;
 }
 
 std::string GetFileLookupKey(
@@ -213,7 +214,7 @@
       // key: "CHILD_OF:<parent_id>:<name>"
       // value: "<child_id>"
       ++num_hierarchy_links_in_db_;
-    } else if (key == kLastFileIdKey) {
+    } else if (key == kSandboxDirectoryLastFileIdKey) {
       // key: "LAST_FILE_ID"
       // value: "<last_file_id>"
       if (last_file_id_ >= 0 ||
@@ -222,7 +223,7 @@
 
       if (last_file_id_ < 0)
         return false;
-    } else if (key == kLastIntegerKey) {
+    } else if (key == kSandboxDirectoryLastIntegerKey) {
       // key: "LAST_INTEGER"
       // value: "<last_integer>"
       if (last_integer_ >= 0 ||
@@ -751,12 +752,15 @@
       LOG(WARNING) << "Corrupted SandboxDirectoryDatabase detected."
                    << " Attempting to repair.";
       if (RepairDatabase(path)) {
-        UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel,
-                                  DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX);
+        UMA_HISTOGRAM_ENUMERATION(
+            kSandboxDirectoryDatabaseRepairHistogramLabel,
+            SandboxDirectoryRepairResult::DB_REPAIR_SUCCEEDED,
+            SandboxDirectoryRepairResult::DB_REPAIR_MAX);
         return true;
       }
-      UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel,
-                                DB_REPAIR_FAILED, DB_REPAIR_MAX);
+      UMA_HISTOGRAM_ENUMERATION(kSandboxDirectoryDatabaseRepairHistogramLabel,
+                                SandboxDirectoryRepairResult::DB_REPAIR_FAILED,
+                                SandboxDirectoryRepairResult::DB_REPAIR_MAX);
       LOG(WARNING) << "Failed to repair SandboxDirectoryDatabase.";
       FALLTHROUGH;
     case DELETE_ON_CORRUPTION:
@@ -811,23 +815,29 @@
     const leveldb::Status& status) {
   base::Time now = base::Time::Now();
   const base::TimeDelta minimum_interval =
-      base::TimeDelta::FromHours(kMinimumReportIntervalHours);
+      base::TimeDelta::FromHours(kSandboxDirectoryMinimumReportIntervalHours);
   if (last_reported_time_ + minimum_interval >= now)
     return;
   last_reported_time_ = now;
 
   if (status.ok()) {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_OK, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(kSandboxDirectoryInitStatusHistogramLabel,
+                              SandboxDirectoryInitStatus::INIT_STATUS_OK,
+                              SandboxDirectoryInitStatus::INIT_STATUS_MAX);
   } else if (status.IsCorruption()) {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_CORRUPTION, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(
+        kSandboxDirectoryInitStatusHistogramLabel,
+        SandboxDirectoryInitStatus::INIT_STATUS_CORRUPTION,
+        SandboxDirectoryInitStatus::INIT_STATUS_MAX);
   } else if (status.IsIOError()) {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_IO_ERROR, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(kSandboxDirectoryInitStatusHistogramLabel,
+                              SandboxDirectoryInitStatus::INIT_STATUS_IO_ERROR,
+                              SandboxDirectoryInitStatus::INIT_STATUS_MAX);
   } else {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(
+        kSandboxDirectoryInitStatusHistogramLabel,
+        SandboxDirectoryInitStatus::INIT_STATUS_UNKNOWN_ERROR,
+        SandboxDirectoryInitStatus::INIT_STATUS_MAX);
   }
 }
 
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
index 06fc50f..fedd1918 100644
--- a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
+++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
@@ -90,13 +90,13 @@
   return known_type_strings;
 }
 
-class ObfuscatedOriginEnumerator
+class SandboxObfuscatedOriginEnumerator
     : public SandboxFileSystemBackendDelegate::OriginEnumerator {
  public:
-  explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) {
+  explicit SandboxObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) {
     enum_.reset(file_util->CreateOriginEnumerator());
   }
-  ~ObfuscatedOriginEnumerator() override = default;
+  ~SandboxObfuscatedOriginEnumerator() override = default;
 
   GURL Next() override { return enum_->Next(); }
 
@@ -109,12 +109,11 @@
   std::unique_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
 };
 
-void OpenFileSystemOnFileTaskRunner(
-    ObfuscatedFileUtil* file_util,
-    const GURL& origin_url,
-    FileSystemType type,
-    OpenFileSystemMode mode,
-    base::File::Error* error_ptr) {
+void OpenSandboxFileSystemOnFileTaskRunner(ObfuscatedFileUtil* file_util,
+                                           const GURL& origin_url,
+                                           FileSystemType type,
+                                           OpenFileSystemMode mode,
+                                           base::File::Error* error_ptr) {
   DCHECK(error_ptr);
   const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
   file_util->GetDirectoryForOriginAndType(
@@ -233,7 +232,7 @@
 
 SandboxFileSystemBackendDelegate::OriginEnumerator*
 SandboxFileSystemBackendDelegate::CreateOriginEnumerator() {
-  return new ObfuscatedOriginEnumerator(obfuscated_file_util());
+  return new SandboxObfuscatedOriginEnumerator(obfuscated_file_util());
 }
 
 base::FilePath
@@ -276,8 +275,9 @@
   base::File::Error* error_ptr = new base::File::Error;
   file_task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::BindOnce(&OpenFileSystemOnFileTaskRunner, obfuscated_file_util(),
-                     origin_url, type, mode, base::Unretained(error_ptr)),
+      base::BindOnce(&OpenSandboxFileSystemOnFileTaskRunner,
+                     obfuscated_file_util(), origin_url, type, mode,
+                     base::Unretained(error_ptr)),
       base::BindOnce(&DidOpenFileSystem, weak_factory_.GetWeakPtr(),
                      std::move(quota_callback),
                      base::BindOnce(std::move(callback), root_url, name),
diff --git a/storage/browser/fileapi/sandbox_origin_database.cc b/storage/browser/fileapi/sandbox_origin_database.cc
index 19ffab2..1156c63 100644
--- a/storage/browser/fileapi/sandbox_origin_database.cc
+++ b/storage/browser/fileapi/sandbox_origin_database.cc
@@ -29,12 +29,14 @@
 const base::FilePath::CharType kOriginDatabaseName[] =
     FILE_PATH_LITERAL("Origins");
 const char kOriginKeyPrefix[] = "ORIGIN:";
-const char kLastPathKey[] = "LAST_PATH";
-const int64_t kMinimumReportIntervalHours = 1;
-const char kInitStatusHistogramLabel[] = "FileSystem.OriginDatabaseInit";
-const char kDatabaseRepairHistogramLabel[] = "FileSystem.OriginDatabaseRepair";
+const char kSandboxOriginLastPathKey[] = "LAST_PATH";
+const int64_t kSandboxOriginMinimumReportIntervalHours = 1;
+const char kSandboxOriginInitStatusHistogramLabel[] =
+    "FileSystem.OriginDatabaseInit";
+const char kSandboxOriginDatabaseRepairHistogramLabel[] =
+    "FileSystem.OriginDatabaseRepair";
 
-enum InitStatus {
+enum class InitSandboxOriginStatus {
   INIT_STATUS_OK = 0,
   INIT_STATUS_CORRUPTION,
   INIT_STATUS_IO_ERROR,
@@ -42,7 +44,7 @@
   INIT_STATUS_MAX
 };
 
-enum RepairResult {
+enum class SandboxOriginRepairResult {
   DB_REPAIR_SUCCEEDED = 0,
   DB_REPAIR_FAILED,
   DB_REPAIR_MAX
@@ -54,7 +56,7 @@
 }
 
 const char* LastPathKey() {
-  return kLastPathKey;
+  return kSandboxOriginLastPathKey;
 }
 
 }  // namespace
@@ -105,13 +107,16 @@
       LOG(WARNING) << "Attempting to repair SandboxOriginDatabase.";
 
       if (RepairDatabase(path)) {
-        UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel,
-                                  DB_REPAIR_SUCCEEDED, DB_REPAIR_MAX);
+        UMA_HISTOGRAM_ENUMERATION(
+            kSandboxOriginDatabaseRepairHistogramLabel,
+            SandboxOriginRepairResult::DB_REPAIR_SUCCEEDED,
+            SandboxOriginRepairResult::DB_REPAIR_MAX);
         LOG(WARNING) << "Repairing SandboxOriginDatabase completed.";
         return true;
       }
-      UMA_HISTOGRAM_ENUMERATION(kDatabaseRepairHistogramLabel,
-                                DB_REPAIR_FAILED, DB_REPAIR_MAX);
+      UMA_HISTOGRAM_ENUMERATION(kSandboxOriginDatabaseRepairHistogramLabel,
+                                SandboxOriginRepairResult::DB_REPAIR_FAILED,
+                                SandboxOriginRepairResult::DB_REPAIR_MAX);
       FALLTHROUGH;
     case DELETE_ON_CORRUPTION:
       if (!base::DeleteFile(file_system_directory_, true))
@@ -193,23 +198,28 @@
 void SandboxOriginDatabase::ReportInitStatus(const leveldb::Status& status) {
   base::Time now = base::Time::Now();
   base::TimeDelta minimum_interval =
-      base::TimeDelta::FromHours(kMinimumReportIntervalHours);
+      base::TimeDelta::FromHours(kSandboxOriginMinimumReportIntervalHours);
   if (last_reported_time_ + minimum_interval >= now)
     return;
   last_reported_time_ = now;
 
   if (status.ok()) {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_OK, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(kSandboxOriginInitStatusHistogramLabel,
+                              InitSandboxOriginStatus::INIT_STATUS_OK,
+                              InitSandboxOriginStatus::INIT_STATUS_MAX);
   } else if (status.IsCorruption()) {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_CORRUPTION, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(kSandboxOriginInitStatusHistogramLabel,
+                              InitSandboxOriginStatus::INIT_STATUS_CORRUPTION,
+                              InitSandboxOriginStatus::INIT_STATUS_MAX);
   } else if (status.IsIOError()) {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_IO_ERROR, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(kSandboxOriginInitStatusHistogramLabel,
+                              InitSandboxOriginStatus::INIT_STATUS_IO_ERROR,
+                              InitSandboxOriginStatus::INIT_STATUS_MAX);
   } else {
-    UMA_HISTOGRAM_ENUMERATION(kInitStatusHistogramLabel,
-                              INIT_STATUS_UNKNOWN_ERROR, INIT_STATUS_MAX);
+    UMA_HISTOGRAM_ENUMERATION(
+        kSandboxOriginInitStatusHistogramLabel,
+        InitSandboxOriginStatus::INIT_STATUS_UNKNOWN_ERROR,
+        InitSandboxOriginStatus::INIT_STATUS_MAX);
   }
 }
 
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc
index 2db8289..afda0ed 100644
--- a/storage/browser/quota/client_usage_tracker.cc
+++ b/storage/browser/quota/client_usage_tracker.cc
@@ -49,9 +49,10 @@
   return itr != origins.end() && base::ContainsKey(itr->second, origin);
 }
 
-void DidGetGlobalUsageForLimitedGlobalUsage(UsageCallback callback,
-                                            int64_t total_global_usage,
-                                            int64_t global_unlimited_usage) {
+void DidGetGlobalClientUsageForLimitedGlobalClientUsage(
+    UsageCallback callback,
+    int64_t total_global_usage,
+    int64_t global_unlimited_usage) {
   std::move(callback).Run(total_global_usage - global_unlimited_usage);
 }
 
@@ -85,8 +86,9 @@
 
 void ClientUsageTracker::GetGlobalLimitedUsage(UsageCallback callback) {
   if (!global_usage_retrieved_) {
-    GetGlobalUsage(base::BindOnce(&DidGetGlobalUsageForLimitedGlobalUsage,
-                                  std::move(callback)));
+    GetGlobalUsage(
+        base::BindOnce(&DidGetGlobalClientUsageForLimitedGlobalClientUsage,
+                       std::move(callback)));
     return;
   }
 
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc
index 6e46117..e759bcf4 100644
--- a/storage/browser/quota/quota_database.cc
+++ b/storage/browser/quota/quota_database.cc
@@ -29,8 +29,8 @@
 
 // Definitions for database schema.
 
-const int kCurrentVersion = 5;
-const int kCompatibleVersion = 2;
+const int kQuotaDatabaseCurrentSchemaVersion = 5;
+const int kQuotaDatabaseCompatibleVersion = 2;
 
 const char kHostQuotaTable[] = "HostQuotaTable";
 const char kOriginInfoTable[] = "OriginInfoTable";
@@ -568,19 +568,21 @@
   static const size_t kIndexCount = arraysize(kIndexes);
   if (!sql::MetaTable::DoesTableExist(db_.get()))
     return CreateSchema(db_.get(), meta_table_.get(),
-                        kCurrentVersion, kCompatibleVersion,
-                        kTables, kTableCount,
+                        kQuotaDatabaseCurrentSchemaVersion,
+                        kQuotaDatabaseCompatibleVersion, kTables, kTableCount,
                         kIndexes, kIndexCount);
 
-  if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion))
+  if (!meta_table_->Init(db_.get(), kQuotaDatabaseCurrentSchemaVersion,
+                         kQuotaDatabaseCompatibleVersion))
     return false;
 
-  if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) {
+  if (meta_table_->GetCompatibleVersionNumber() >
+      kQuotaDatabaseCurrentSchemaVersion) {
     LOG(WARNING) << "Quota database is too new.";
     return false;
   }
 
-  if (meta_table_->GetVersionNumber() < kCurrentVersion) {
+  if (meta_table_->GetVersionNumber() < kQuotaDatabaseCurrentSchemaVersion) {
     if (!UpgradeSchema(meta_table_->GetVersionNumber()))
       return ResetSchema();
   }
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 5f99f64..8e833fe 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -1382,52 +1382,6 @@
       },
       {
         "args": [
-          "--enable-features=VizDisplayCompositor",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "viz_content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "viz_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 10
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 63349ce..b96d80f 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -37,12 +37,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -706,12 +700,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -1405,17 +1393,6 @@
             }
           ]
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2564,17 +2541,6 @@
             }
           ]
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -3723,17 +3689,6 @@
             }
           ]
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-15063"
-            }
-          ]
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -8123,6 +8078,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 20
+        },
+        "test": "chrome_public_test_apk"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_public_test_vr_apk"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -10228,12 +10227,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -10893,12 +10886,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -11528,12 +11515,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -12173,12 +12154,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -12827,12 +12802,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -13473,12 +13442,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -14047,12 +14010,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -14529,12 +14486,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -15195,12 +15146,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -15861,12 +15806,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -16527,12 +16466,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -17193,12 +17126,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -17859,12 +17786,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -18525,12 +18446,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -19191,12 +19106,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -19857,12 +19766,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -20523,12 +20426,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -21189,12 +21086,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -21870,17 +21761,6 @@
             }
           ]
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10"
-            }
-          ]
-        },
         "test": "blink_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index e1fa7c7..fb27fde8 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -353,12 +353,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -1942,12 +1936,6 @@
         "swarming": {
           "can_use_on_swarming_builders": false
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": false
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2952,7 +2940,6 @@
           "--browser=cros-chrome",
           "--remote=127.0.0.1",
           "--remote-ssh-port=9222",
-          "--skip=telemetry.core.tracing_controller_unittest.TracingControllerTest.testBattOrTracing",
           "--skip=telemetry.internal.app.android_app_unittest.AndroidAppTest.testWebView",
           "--skip=telemetry.internal.backends.browser_backend_unittest.BrowserBackendIntegrationTest.testSmokeIsBrowserRunningReturnFalse"
         ],
@@ -4010,12 +3997,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -4788,12 +4769,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -5589,15 +5564,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "args": [
-          "--enable-features=ViewsBrowserWindows"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index dd926ad..9db267c8 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -16086,28 +16086,6 @@
       },
       {
         "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=WebVrBrowserTest*:WebXrVrBrowserTest*",
-          "--enable-pixel-output-in-tests",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6613",
-              "os": "Windows-2008ServerR2-SP1",
-              "pool": "Chrome-GPU"
-            }
-          ]
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index d578263d..3786d125b 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -863,12 +863,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -1664,12 +1658,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2417,12 +2405,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -3121,17 +3103,6 @@
             }
           ]
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-16.04"
-            }
-          ]
-        },
         "test": "blink_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 902ef26..c8f79c3 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -36,12 +36,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -619,12 +613,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -1249,18 +1237,6 @@
             }
           ]
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ]
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2290,7 +2266,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "none",
+              "gpu": "8086:0a2e",
               "os": "Mac-10.12.6"
             }
           ],
@@ -2342,12 +2318,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2873,7 +2843,7 @@
       {
         "alternate_swarming_dimensions": [
           {
-            "gpu": "none",
+            "gpu": "8086:0a2e",
             "os": "Mac-10.12.6"
           }
         ],
@@ -2890,7 +2860,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "none",
+              "gpu": "8086:0a2e",
               "os": "Mac-10.13"
             }
           ],
@@ -2943,12 +2913,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index c96ede0c..35ffe13 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -572,6 +572,50 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "shards": 20
+        },
+        "test": "chrome_public_test_apk"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
             "chrome_public_test_vr_apk"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
@@ -2702,16 +2746,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-batch-limit=1",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -3588,12 +3622,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -5511,12 +5539,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -6162,12 +6184,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -6671,12 +6687,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -7117,10 +7127,5 @@
         "test": "wtf_unittests"
       }
     ]
-  },
-  "win-asan": {
-    "additional_compile_targets": [
-      "base_unittests"
-    ]
   }
 }
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 20b945a..4907f30 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -1447,6 +1447,50 @@
           ],
           "script": "//testing/trigger_scripts/perf_device_trigger.py"
         }
+      },
+      {
+        "args": [
+          "-v",
+          "--browser=release",
+          "--upload-results",
+          "--test-shard-map-filename=mac_1012_low_end_26_shard_map.json",
+          "--assert-gpu-compositing"
+        ],
+        "isolate_name": "performance_test_suite",
+        "merge": {
+          "args": [
+            "--service-account-file",
+            "/creds/service_accounts/service-account-chromium-perf-histograms.json"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_test_suite",
+        "override_compile_targets": [
+          "performance_test_suite"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "os": "Mac-10.12",
+              "pool": "chrome.tests.perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 25200,
+          "ignore_task_failure": false,
+          "io_timeout": 1800,
+          "shards": 26,
+          "upload_test_results": true
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
       }
     ]
   },
@@ -1540,6 +1584,50 @@
       },
       {
         "args": [
+          "-v",
+          "--browser=release",
+          "--upload-results",
+          "--test-shard-map-filename=mac_1013_high_end_26_shard_map.json",
+          "--assert-gpu-compositing"
+        ],
+        "isolate_name": "performance_test_suite",
+        "merge": {
+          "args": [
+            "--service-account-file",
+            "/creds/service_accounts/service-account-chromium-perf-histograms.json"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_test_suite",
+        "override_compile_targets": [
+          "performance_test_suite"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "os": "Mac-10.13",
+              "pool": "chrome.tests.perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 25200,
+          "ignore_task_failure": false,
+          "io_timeout": 1800,
+          "shards": 26,
+          "upload_test_results": true
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      },
+      {
+        "args": [
           "--gtest-benchmark-name",
           "views_perftests",
           "--non-telemetry=true",
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index fd42bd21c..4e1b640 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -37,12 +37,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -768,12 +762,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -1433,12 +1421,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2085,12 +2067,6 @@
       },
       {
         "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
         },
@@ -2157,12 +2133,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
@@ -2849,12 +2819,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "battor_agent_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "blink_common_unittests"
       },
       {
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 5dd0fb3d..83922a00 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -13,14 +13,13 @@
 -ProcessManagerBrowserTest.NestedURLNavigationsToExtensionAllowed
 -ProxySettingsApiTest.ProxyEventsInvalidProxy
 -RegisterProtocolHandlerBrowserTest.CustomHandler
--SSLUITest.TestBadHTTPSDownload/0
--SSLUITest.TestBadHTTPSDownload/1
 -SubresourceFilterBrowserTest.FailedProvisionalLoadInMainframe
 -WebViewTest.WebViewInBackgroundPage
 
 # These tests uses net::URLRequestFilter (through TestRequestInterceptor) to
-# mock out network responses. Unclear if the code being tested uses
-# SimpleURLLoader or URLFetcher.
+# mock out network responses, and use ExtensionDownloader to issue requests,
+# which has yet to be switched from URLFetcher.
+# https://crbug.com/844928
 -PolicyTest.ExtensionInstallBlacklistSharedModules
 -PolicyTest.ExtensionInstallForcelist
 -PolicyTest.ExtensionInstallForcelist_DefaultedUpdateUrl
@@ -28,6 +27,11 @@
 -PolicyTest.ExtensionMinimumVersionRequired
 -PolicyTest.ExtensionMinimumVersionRequiredAlt
 -PolicyTest.ExtensionRecommendedInstallationMode
+
+# These tests uses net::URLRequestFilter (through TestRequestInterceptor) to
+# mock out network responses, and use URLFetcherDownloader to issue requests,
+# which has yet to be switched from URLFetcher.
+# https://crbug.com/871542
 -PolicyUpdateServiceTest.Backoff
 -PolicyUpdateServiceTest.FailedUpdateRetries
 -PolicyUpdateServiceTest.PolicyCorruptedOnStartup
@@ -110,12 +114,6 @@
 # https://crbug.com/721398
 -WebViewTest.ClearDataCache
 
-# Need a test interface API that allows us to check on the CT status.
-# Then in ssl_browsertest.cc we can use that instead of the direct
-# call to the transport_security_state()
--SSLUITest.CertificateTransparencyEnforcementDisabledForUrls/0
--SSLUITest.CertificateTransparencyEnforcementDisabledForUrls/1
-
 # https://crbug.com/853256
 -ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked/0
 -ClientHintsBrowserTest.ClientHintsLifetimeNotAttachedCookiesBlocked/1
@@ -148,8 +146,6 @@
 -DnsProbeBrowserTest.NoInternetProbeResultWithSlowBrokenCorrections
 
 # crbug.com/776589 Intercepting requests with net::URLRequestFilter.
--PolicyTest.CertificateTransparencyEnforcementDisabledForUrls/0
--PolicyTest.CertificateTransparencyEnforcementDisabledForUrls/1
 -PolicyTest.ExtensionInstallSources
 
 # crbug.com/859594 Migrate storage::FileWriterDelegate to use SimpleURLLoader
@@ -187,11 +183,6 @@
 -IOThreadBrowserTestWithHangingPacRequest.Shutdown
 -ProxySettingsApiTest.ProxyEventsParseError
 
-# http://crbug.com/721414
-# TODO(rockot): add support for webRequest API.
-# Note WebRequestUnloadImmediately is disabled on Linux
--ExtensionWebRequestApiTest.WebRequestUnloadImmediately
-
 # http://crbug.com/827582
 # Editing response cookies through headers with webRequest is not supported with
 # the network service.
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 48a5e5d..79ffc675 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -171,10 +171,6 @@
     "label": "//base:base_unittests",
     "type": "console_test_launcher",
   },
-  "battor_agent_unittests": {
-    "label": "//tools/battor_agent:battor_agent_unittests",
-    "type": "console_test_launcher",
-  },
   "blink_common_unittests": {
     "label": "//third_party/blink/common:blink_common_unittests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 5d87eda..c23bb401 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -260,12 +260,6 @@
     ],
   },
   'chrome_public_test_apk': {
-    'remove_from': [
-      # chromium.clang
-      'ToTAndroidCFI',  # https://crbug.com/862581
-      # chromium.memory
-      'Android CFI',  # https://crbug.com/862581
-    ],
     'modifications': {
       # chromium.android
       'android-kitkat-arm-rel': {
@@ -1277,6 +1271,8 @@
       # chromium.android
       # GL OOM error triggered on KitKat. crbug.com/863049
       'android-kitkat-arm-rel',
+      # Several failures that need to be triaged. crbug.com/871519
+      'KitKat Phone Tester (dbg)',
       # Currently flaky timeouts on Windows 10. crbug.com/839824
       'Win10 Tests x64 (dbg)',
     ],
@@ -1642,7 +1638,7 @@
         'swarming': {
           'dimension_sets': [
             {
-              'gpu': 'none',
+              'gpu': '8086:0a2e',
               'os': 'Mac-10.12.6',
             },
           ],
@@ -1653,7 +1649,7 @@
         # TODO(crbug.com/853356): Switch this to 10.13.
         'use_multi_dimension_trigger_script': True,
         'alternate_swarming_dimensions': [{
-          'gpu': 'none',
+          'gpu': '8086:0a2e',
           'os': 'Mac-10.12.6',
         }],
 
@@ -1662,7 +1658,7 @@
         'swarming': {
           'dimension_sets': [
             {
-              'gpu': 'none',
+              'gpu': '8086:0a2e',
               'os': 'Mac-10.13',
             },
           ],
@@ -1814,6 +1810,8 @@
       # This exception probably needs to stay due to lack of capacity
       # on the Win AMD bots.
       'Win7 FYI Debug (AMD)',
+      # Fails on the bot, http://crbug.com/868143
+      'Win7 FYI Release (AMD)',
     ],
   },
 }
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index f86561f..7847c5ff 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -446,8 +446,6 @@
         # By default, CrOS VMs' ssh servers listen on local port 9222.
         '--remote=127.0.0.1',
         '--remote-ssh-port=9222',
-        # Flaky.
-        '--skip=telemetry.core.tracing_controller_unittest.TracingControllerTest.testBattOrTracing',
         # Always fails.
         '--skip=telemetry.internal.app.android_app_unittest.AndroidAppTest.testWebView',
         '--skip=telemetry.internal.backends.browser_backend_unittest.BrowserBackendIntegrationTest.testSmokeIsBrowserRunningReturnFalse',
@@ -1916,7 +1914,6 @@
   },
 
   'non_android_and_cast_and_chromeos_chromium_gtests': {
-    'battor_agent_unittests': {},
     'cronet_tests': {},
     'cronet_unittests': {},
     'headless_browsertests': {},
@@ -2176,7 +2173,6 @@
 
   'win7_32_bit_gtests': {
     'base_unittests': {},
-    'battor_agent_unittests': {},
     'browser_tests': {
       'swarming': {
         'shards': 10,
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index b366721..464dcbb 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2980,12 +2980,6 @@
           'gtest_tests': 'chromium_mac_gtests',
         },
       },
-      'win-asan': {
-        # TODO(thakis): test_suites 'gtest_tests': 'chromium_win_gtests' instead
-        'additional_compile_targets': [
-          'base_unittests',
-        ],
-      },
     },
   },
   {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index a08dbab..1c4ae6a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -409,7 +409,6 @@
     "AudioService": [
         {
             "platforms": [
-                "linux",
                 "windows"
             ],
             "experiments": [
@@ -430,6 +429,7 @@
             "platforms": [
                 "android",
                 "chromeos",
+                "linux",
                 "mac"
             ],
             "experiments": [
@@ -2505,6 +2505,24 @@
             ]
         }
     ],
+    "NewExtensionUpdaterService": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NewExtensionUpdaterService"
+                    ]
+                }
+            ]
+        }
+    ],
     "NewPrintPreview": [
         {
             "platforms": [
@@ -3796,25 +3814,6 @@
             ]
         }
     ],
-    "ServiceWorkerPaymentApps": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ServiceWorkerPaymentApps"
-                    ]
-                }
-            ]
-        }
-    ],
     "ServiceWorkerServicification": [
         {
             "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 7d1afe0..c5bb272 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -55,7 +55,6 @@
 /custom_tabs_client/src
 /cygwin
 /depot_tools
-/deqp/src
 /devtools-node-modules
 /directxsdk
 /dom_distiller_js/dist
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 093d260..7ad2422 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -22,7 +22,7 @@
 crbug.com/591099 fast/block/marquee-width-shrinks-to-fit-in-fixed-size-container.html [ Failure ]
 
 # Whitespace differences only
-crbug.com/854889 accessibility/canvas-fallback-content-2.html [ Failure Timeout ]
+crbug.com/854889 accessibility/canvas-fallback-content-2.html [ Failure ]
 
 # Wrong quirks mode line height for pattern <div><a><img></a></div>
 crbug.com/854840 fast/table/backgr_border-table-quirks-collapsed-border.html [ Failure ]
@@ -64,15 +64,17 @@
 crbug.com/591099 compositing/iframes/floating-self-painting-frame.html [ Failure ]
 crbug.com/869265 compositing/layer-creation/stacking-context-overlap-nested.html [ Failure ]
 crbug.com/591099 css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ]
-crbug.com/591099 css3/filters/effect-brightness-clamping-hw.html [ Pass Timeout ]
 crbug.com/591099 css3/flexbox/bug646288.html [ Failure ]
 crbug.com/591099 css3/flexbox/flex-flow-margins-auto-size.html [ Failure ]
 crbug.com/591099 css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Failure ]
 crbug.com/591099 css3/flexbox/line-wrapping.html [ Failure ]
 crbug.com/591099 css3/flexbox/scrollbars-auto.html [ Failure ]
 crbug.com/714962 css3/masking/clip-path-reference-box-inline.html [ Failure ]
+crbug.com/591099 editing/inserting/insert-character-in-first-letter-crash.html [ Crash ]
 crbug.com/591099 editing/selection/continuations-with-move-caret-to-boundary.html [ Failure Pass ]
 crbug.com/591099 editing/selection/paint-hyphen.html [ Pass ]
+crbug.com/591099 editing/text-iterator/first-letter-word-boundary.html [ Crash ]
+crbug.com/591099 editing/text-iterator/read-past-cloned-first-letter.html [ Crash ]
 crbug.com/591099 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Pass ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.worker.html [ Timeout ]
@@ -89,7 +91,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Timeout ]
 crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
 crbug.com/591099 external/wpt/background-fetch/get-ids.https.window.html [ Crash Pass ]
-crbug.com/591099 external/wpt/background-fetch/get.https.window.html [ Pass ]
+crbug.com/591099 external/wpt/background-fetch/get.https.window.html [ Crash Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-004.xht [ Pass ]
@@ -229,8 +231,8 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Crash Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html [ Crash Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/emptyspan-1.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/emptyspan-4.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/remove-from-split-inline-6.html [ Pass ]
@@ -421,6 +423,10 @@
 crbug.com/807708 fast/css-intrinsic-dimensions/width-avoid-floats.html [ Failure ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
 crbug.com/591099 fast/css/case-transform.html [ Failure ]
+crbug.com/591099 fast/css/first-letter-block-form-controls-crash.html [ Crash ]
+crbug.com/591099 fast/css/first-letter-capitalized-edit-select-crash.html [ Crash ]
+crbug.com/591099 fast/css/first-letter-crash-document-disposal.html [ Crash ]
+crbug.com/591099 fast/css/first-letter-text-fragment-crash.html [ Crash ]
 crbug.com/835484 fast/css/focus-ring-continuations.html [ Failure ]
 crbug.com/835484 fast/css/focus-ring-recursive-continuations.html [ Failure ]
 crbug.com/835484 fast/css/focus-ring-recursive-inlines.html [ Failure ]
@@ -431,7 +437,6 @@
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
-crbug.com/591099 fast/forms/text-control-intrinsic-widths.html [ Pass Timeout ]
 crbug.com/591099 fast/inline-block/vertical-align-top-and-bottom-2.html [ Failure ]
 crbug.com/835484 fast/inline/continuation-outlines-with-layers-2.html [ Failure ]
 crbug.com/835484 fast/inline/continuation-outlines-with-layers.html [ Failure ]
@@ -444,6 +449,7 @@
 crbug.com/591099 fast/overflow/recompute-overflow-of-layout-root-container.html [ Failure ]
 crbug.com/591099 fast/replaced/table-replaced-element.html [ Failure ]
 crbug.com/591099 fast/ruby/position-after.html [ Failure ]
+crbug.com/591099 fast/ruby/ruby-first-letter.html [ Crash ]
 crbug.com/591099 fast/scrolling/content-box-smaller-than-scrollbar.html [ Failure ]
 crbug.com/591099 fast/scrolling/jquery-rtl-scroll-type.html [ Failure ]
 crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Pass ]
@@ -455,7 +461,7 @@
 crbug.com/591099 fast/table/empty-table-percent-height.html [ Failure ]
 crbug.com/591099 fast/table/height-percent-test-vertical.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure Pass ]
-crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure Pass ]
+crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-replaced-content-in-cell.html [ Failure ]
 crbug.com/858998 fast/table/table-continuation-outline-paint-crash.html [ Failure ]
 crbug.com/591099 fast/table/table-display-types-vertical.html [ Failure ]
@@ -484,7 +490,7 @@
 crbug.com/855039 html/details_summary/details-writing-mode-align-right.html [ Failure ]
 crbug.com/855039 html/details_summary/details-writing-mode.html [ Failure ]
 crbug.com/591099 http/tests/devtools/console-resource-errors.js [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/console/console-correct-suggestions.js [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/console/console-correct-suggestions.js [ Pass ]
 crbug.com/591099 http/tests/devtools/console/console-search.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js [ Failure ]
@@ -499,7 +505,7 @@
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-appcache.https.html [ Crash Failure ]
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.https.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash ]
-crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Crash Pass Timeout ]
+crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Pass ]
 crbug.com/714962 images/color-profile-background-clip-text.html [ Failure ]
 crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/714962 inspector-protocol/css/css-get-platform-fonts.js [ Failure ]
@@ -574,16 +580,12 @@
 crbug.com/591099 paint/invalidation/window-resize/window-resize-viewport-percent.html [ Failure ]
 crbug.com/591099 paint/overflow/background-mask-should-be-recorded-full.html [ Failure ]
 crbug.com/591099 paint/pagination/pagination-change-clip-crash.html [ Failure ]
-crbug.com/714962 paint/text/text-match-highlights-big-line-height.html [ Failure ]
+crbug.com/714962 paint/text/text-match-highlights-big-line-height.html [ Failure Pass ]
 crbug.com/591099 printing/absolute-position-headers-and-footers.html [ Failure ]
 crbug.com/591099 printing/iframe-svg-in-object-print.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
-crbug.com/591099 storage/indexeddb/cursor-continue-validity.html [ Pass Timeout ]
-crbug.com/591099 storage/indexeddb/index-cursor.html [ Pass Timeout ]
-crbug.com/591099 storage/indexeddb/mozilla/indexes.html [ Pass Timeout ]
-crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass Timeout ]
+crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass ]
 crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ]
-crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Pass Timeout ]
 crbug.com/591099 svg/custom/object-sizing-no-width-height.xhtml [ Failure ]
 crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ]
 crbug.com/591099 svg/in-html/sizing/svg-inline.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
index 1ae914b..fa8cbcf 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
@@ -147,8 +147,8 @@
 crbug.com/855688 transitions/transition-end-event-destroy-iframe.html [ Timeout ]
 crbug.com/855688 virtual/threaded/transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ]
 crbug.com/855688 virtual/threaded/transitions/transition-end-event-destroy-iframe.html [ Timeout ]
-crbug.com/855691 virtual/threaded/fast/animationworklet/animation-worklet-animator-animate.html [ Failure ]
-crbug.com/855691 virtual/threaded/fast/animationworklet/animation-worklet-animator-with-options.html [ Failure ]
+crbug.com/855691 virtual/threaded/fast/animationworklet/animator-animate.html [ Failure ]
+crbug.com/855691 virtual/threaded/fast/animationworklet/animator-with-options.html [ Failure ]
 crbug.com/855691 virtual/threaded/fast/animationworklet/worklet-animation-currentTime.html [ Failure ]
 crbug.com/855702 virtual/threaded/animations/composited-filter-webkit-filter.html [ Failure ]
 crbug.com/855702 virtual/threaded/animations/img-element-transform.html [ Timeout Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 4d07ae5..be72a6d 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1685,7 +1685,6 @@
 
 # Failing tests in dictionary order.
 crbug.com/867834 virtual/outofblink-cors/external/wpt/fetch/api/cors/sandboxed-iframe.html [ Failure ]
-crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/access-control-and-redirects-async.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/access-control-sandboxed-iframe-denied-without-wildcard.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/access-control-sandboxed-iframe-denied.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/data-uri.htm [ Failure ]
@@ -1700,7 +1699,6 @@
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
 crbug.com/867834 virtual/outofblink-cors-ns/external/wpt/fetch/api/cors/sandboxed-iframe.html [ Failure ]
-crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/access-control-and-redirects-async.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/access-control-sandboxed-iframe-denied-without-wildcard.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/access-control-sandboxed-iframe-denied.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/data-uri.htm [ Failure ]
@@ -2701,6 +2699,14 @@
 crbug.com/870526 external/wpt/payment-handler/idlharness.https.any.serviceworker.html [ Skip ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux Win ] external/wpt/css/css-contain/contain-size-025.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-paint-clip-016.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-layout-cell-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-style-counters-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-layout-cell-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-paint-clip-015.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-size-monolithic-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ]
 crbug.com/868102 external/wpt/css/css-contain/contain-paint-021.html [ Failure ]
 crbug.com/870811 external/wpt/css/css-contain/contain-paint-001.html [ Failure ]
 crbug.com/870157 external/wpt/css/css-contain/contain-layout-016.html [ Failure ]
@@ -4577,8 +4583,9 @@
 # Sheriff 2018-06-06
 crbug.com/849975 external/wpt/css/css-animations/Element-getAnimations.tentative.html [ Pass Failure ]
 
-# This won't pass as a layout test until the linked bug is fixed.
+# These won't pass as layout tests until the linked bug is fixed.
 crbug.com/828858 external/wpt/css/selectors/focus-visible-007.html [ Failure ]
+crbug.com/828858 external/wpt/html/editing/focus/inert/inert-node-is-uneditable.html [ Failure ]
 
 # Sheriff 2018-06-07
 crbug.com/850349 external/wpt/css/css-animations/CSSAnimation-getComputedTiming.tentative.html [ Pass Failure ]
@@ -4829,7 +4836,6 @@
 crbug.com/868706 external/wpt/css/css-layout-api/auto-block-size-inflow.https.html [ Pass Failure ]
 
 # Sheriff 2018-07-31
-crbug.com/869470 external/wpt/background-fetch/get.https.window.html [ Pass Failure ]
 crbug.com/869364 css3/filters/filter-repaint-composited-fallback.html [ Pass Timeout ]
 crbug.com/869364 external/wpt/IndexedDB/parallel-cursors-upgrade.html [ Pass Timeout ]
 crbug.com/869364 http/tests/devtools/console/console-correct-suggestions.js [ Pass Timeout ]
@@ -4849,5 +4855,18 @@
 crbug.com/871578 [ Mac ] virtual/outofblink-cors/external/wpt/xhr/timeout-multiple-fetches.html [ Failure Pass ]
 crbug.com/871578 [ Mac ] virtual/outofblink-cors-ns/external/wpt/xhr/timeout-multiple-fetches.html [ Failure Pass ]
 
-# Only passes on bots with GPUs.
-crbug.com/871445 [ Mac ] http/tests/media/video-load-metadata-decode-error.html [ Timeout ]
+# Flaky on various bots
+crbug.com/869470 external/wpt/background-fetch/fetch.https.window.html [ Pass Failure ]
+crbug.com/869470 external/wpt/background-fetch/get.https.window.html [ Pass Failure ]
+crbug.com/869470 external/wpt/background-fetch/get-ids.https.window.html [ Pass Failure Crash ]
+
+# Flaky middleClinkAutoscroll increased flakiness on Mac
+crbug.com/851090 [ Mac ] fast/events/middleClickAutoscroll-click-hyperlink.html [ Failure Pass ]
+crbug.com/851090 [ Mac ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-nested-divs.html [ Failure Pass ]
+crbug.com/851090 [ Mac ] virtual/user-activation-v2/fast/events/autoscroll-over-scrollbar.html [ Failure Pass ]
+
+# Sherrif 2018-08-08
+crbug.com/871105 [ Linux ] svg/dom/remove-use-target-element-indirectly.html [ Pass Crash ]
+crbug.com/872025 [ Mac Linux ] fast/css-grid-layout/crash-large-positions.html [ Pass Timeout ]
+crbug.com/871416 fast/spatial-navigation/snav-stay-in-overflow-div.html [ Pass Failure ]
+crbug.com/872242 [ Mac10.10 ] fast/events/autoscroll-over-scrollbar.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index bf3ea3a1..96e3742 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -31,6 +31,11 @@
   },
   {
     "prefix": "threaded",
+    "base": "lifecycle",
+    "args": ["--enable-threaded-compositing"]
+  },
+  {
+    "prefix": "threaded",
     "base": "http/tests/worklet",
     "args": ["--enable-threaded-compositing"]
   },
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index b77e245a..a8654db 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -5989,6 +5989,30 @@
      {}
     ]
    ],
+   "speech-api/SpeechRecognition-abort-manual.https.html": [
+    [
+     "/speech-api/SpeechRecognition-abort-manual.https.html",
+     {}
+    ]
+   ],
+   "speech-api/SpeechRecognition-onerror-manual.https.html": [
+    [
+     "/speech-api/SpeechRecognition-onerror-manual.https.html",
+     {}
+    ]
+   ],
+   "speech-api/SpeechRecognition-onresult-manual.https.html": [
+    [
+     "/speech-api/SpeechRecognition-onresult-manual.https.html",
+     {}
+    ]
+   ],
+   "speech-api/SpeechRecognition-stop-manual.https.html": [
+    [
+     "/speech-api/SpeechRecognition-stop-manual.https.html",
+     {}
+    ]
+   ],
    "storage/persist-permission-manual.https.html": [
     [
      "/storage/persist-permission-manual.https.html",
@@ -35615,6 +35639,150 @@
      {}
     ]
    ],
+   "css/css-contain/contain-layout-cell-001.html": [
+    [
+     "/css/css-contain/contain-layout-cell-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-cell-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-cell-002.html": [
+    [
+     "/css/css-contain/contain-layout-cell-002.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-cell-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ifc-022.html": [
+    [
+     "/css/css-contain/contain-layout-ifc-022.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ifc-022-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-013.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-013.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-014.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-014.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-015.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-015.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-016.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-016.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-017.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-017.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-018.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-018.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-019.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-019.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-ink-overflow-020.html": [
+    [
+     "/css/css-contain/contain-layout-ink-overflow-020.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-layout-size-003.html": [
+    [
+     "/css/css-contain/contain-layout-size-003.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-size-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-paint-001.html": [
     [
      "/css/css-contain/contain-paint-001.html",
@@ -35639,18 +35807,6 @@
      {}
     ]
    ],
-   "css/css-contain/contain-paint-003.html": [
-    [
-     "/css/css-contain/contain-paint-003.html",
-     [
-      [
-       "/css/reference/pass_if_pass_below.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-contain/contain-paint-004.html": [
     [
      "/css/css-contain/contain-paint-004.html",
@@ -35867,6 +36023,234 @@
      {}
     ]
    ],
+   "css/css-contain/contain-paint-022.html": [
+    [
+     "/css/css-contain/contain-paint-022.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-022-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-023.html": [
+    [
+     "/css/css-contain/contain-paint-023.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-024.html": [
+    [
+     "/css/css-contain/contain-paint-024.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-047.html": [
+    [
+     "/css/css-contain/contain-paint-047.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-047-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-048.html": [
+    [
+     "/css/css-contain/contain-paint-048.html",
+     [
+      [
+       "/css/css-contain/reference/ref-if-there-is-no-red.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-cell-001.html": [
+    [
+     "/css/css-contain/contain-paint-cell-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-047-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-cell-002.html": [
+    [
+     "/css/css-contain/contain-paint-cell-002.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-047-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-011.html": [
+    [
+     "/css/css-contain/contain-paint-clip-011.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-012.html": [
+    [
+     "/css/css-contain/contain-paint-clip-012.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-013.html": [
+    [
+     "/css/css-contain/contain-paint-clip-013.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-014.html": [
+    [
+     "/css/css-contain/contain-paint-clip-014.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-015.html": [
+    [
+     "/css/css-contain/contain-paint-clip-015.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-clip-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-016.html": [
+    [
+     "/css/css-contain/contain-paint-clip-016.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-clip-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-017.html": [
+    [
+     "/css/css-contain/contain-paint-clip-017.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-clip-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-clip-018.html": [
+    [
+     "/css/css-contain/contain-paint-clip-018.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-clip-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-ifc-011.html": [
+    [
+     "/css/css-contain/contain-paint-ifc-011.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-ifc-011-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-size-001.html": [
+    [
+     "/css/css-contain/contain-paint-size-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-size-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-size-002.html": [
+    [
+     "/css/css-contain/contain-paint-size-002.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-size-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-paint-size-003.html": [
+    [
+     "/css/css-contain/contain-paint-size-003.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-size-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-size-001.html": [
     [
      "/css/css-contain/contain-size-001.html",
@@ -36023,6 +36407,138 @@
      {}
     ]
    ],
+   "css/css-contain/contain-size-021.html": [
+    [
+     "/css/css-contain/contain-size-021.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-021-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-023.html": [
+    [
+     "/css/css-contain/contain-size-023.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-021-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-025.html": [
+    [
+     "/css/css-contain/contain-size-025.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-021-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-027.html": [
+    [
+     "/css/css-contain/contain-size-027.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-021-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-041.html": [
+    [
+     "/css/css-contain/contain-size-041.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-021-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-042.html": [
+    [
+     "/css/css-contain/contain-size-042.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-022-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-051.html": [
+    [
+     "/css/css-contain/contain-size-051.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-051-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-052.html": [
+    [
+     "/css/css-contain/contain-size-052.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-051-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-056.html": [
+    [
+     "/css/css-contain/contain-size-056.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-056-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-061.html": [
+    [
+     "/css/css-contain/contain-size-061.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-061-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-size-062.html": [
+    [
+     "/css/css-contain/contain-size-062.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-062-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-size-borders.html": [
     [
      "/css/css-contain/contain-size-borders.html",
@@ -36083,6 +36599,54 @@
      {}
     ]
    ],
+   "css/css-contain/contain-size-monolithic-001.html": [
+    [
+     "/css/css-contain/contain-size-monolithic-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-monolithic-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-strict-001.html": [
+    [
+     "/css/css-contain/contain-strict-001.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-size-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-strict-002.html": [
+    [
+     "/css/css-contain/contain-strict-002.html",
+     [
+      [
+       "/css/css-contain/reference/contain-paint-size-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-strict-003.html": [
+    [
+     "/css/css-contain/contain-strict-003.html",
+     [
+      [
+       "/css/css-contain/reference/contain-layout-size-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-style-breaks-001.html": [
     [
      "/css/css-contain/contain-style-breaks-001.html",
@@ -36143,12 +36707,48 @@
      {}
     ]
    ],
-   "css/css-contain/contain-style-counters.html": [
+   "css/css-contain/contain-style-counters-001.html": [
     [
-     "/css/css-contain/contain-style-counters.html",
+     "/css/css-contain/contain-style-counters-001.html",
      [
       [
-       "/css/css-contain/contain-style-counters-ref.html",
+       "/css/css-contain/reference/contain-style-counters-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-style-counters-002.html": [
+    [
+     "/css/css-contain/contain-style-counters-002.html",
+     [
+      [
+       "/css/css-contain/reference/contain-style-counters-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-style-counters-003.html": [
+    [
+     "/css/css-contain/contain-style-counters-003.html",
+     [
+      [
+       "/css/css-contain/reference/contain-style-counters-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-contain/contain-style-counters-004.html": [
+    [
+     "/css/css-contain/contain-style-counters-004.html",
+     [
+      [
+       "/css/css-contain/reference/contain-style-counters-003-ref.html",
        "=="
       ]
      ],
@@ -54607,6 +55207,18 @@
      {}
     ]
    ],
+   "css/css-sizing/orthogonal-writing-mode-float-in-inline.html": [
+    [
+     "/css/css-sizing/orthogonal-writing-mode-float-in-inline.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-sizing/whitespace-and-break.html": [
     [
      "/css/css-sizing/whitespace-and-break.html",
@@ -100775,6 +101387,21 @@
      {}
     ]
    ],
+   ".well-known/origin-policy/policy-csp-1": [
+    [
+     {}
+    ]
+   ],
+   ".well-known/origin-policy/policy-csp-2": [
+    [
+     {}
+    ]
+   ],
+   ".well-known/origin-policy/policy-noimg": [
+    [
+     {}
+    ]
+   ],
    "2dcontext/2x2.png": [
     [
      {}
@@ -112850,6 +113477,41 @@
      {}
     ]
    ],
+   "css/css-contain/reference/contain-layout-cell-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-ifc-022-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-ink-overflow-013-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-ink-overflow-015-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-ink-overflow-019-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-ink-overflow-020-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-layout-size-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/contain-paint-001-ref.html": [
     [
      {}
@@ -112870,6 +113532,36 @@
      {}
     ]
    ],
+   "css/css-contain/reference/contain-paint-022-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-paint-047-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-paint-clip-015-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-paint-ifc-011-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-paint-size-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-paint-size-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/contain-size-004-ref.html": [
     [
      {}
@@ -112880,6 +113572,36 @@
      {}
     ]
    ],
+   "css/css-contain/reference/contain-size-021-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-size-022-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-size-051-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-size-056-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-size-061-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-size-062-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/contain-size-breaks-001-ref.html": [
     [
      {}
@@ -112900,6 +113622,11 @@
      {}
     ]
    ],
+   "css/css-contain/reference/contain-size-monolithic-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/contain-style-breaks-001-ref.html": [
     [
      {}
@@ -112910,6 +113637,16 @@
      {}
     ]
    ],
+   "css/css-contain/reference/contain-style-counters-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/reference/contain-style-counters-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-contain/reference/counter-scoping-001-ref.html": [
     [
      {}
@@ -112935,6 +113672,51 @@
      {}
     ]
    ],
+   "css/css-contain/reference/ref-if-there-is-no-red.xht": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/blue-100x100.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/blue50wBy23h.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/blue50wBy46h.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/pattern-gg-gr-100x100.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/swatch-blue.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/swatch-orange.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/swatch-red.png": [
+    [
+     {}
+    ]
+   ],
+   "css/css-contain/support/swatch-yellow.png": [
+    [
+     {}
+    ]
+   ],
    "css/css-content/META.yml": [
     [
      {}
@@ -123165,6 +123947,11 @@
      {}
     ]
    ],
+   "css/css-grid/alignment/grid-content-alignment-second-pass-002-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009-expected.txt": [
     [
      {}
@@ -158935,6 +159722,11 @@
      {}
     ]
    ],
+   "interfaces/README.md": [
+    [
+     {}
+    ]
+   ],
    "interfaces/ResizeObserver.idl": [
     [
      {}
@@ -159390,6 +160182,11 @@
      {}
     ]
    ],
+   "interfaces/screen-capture.idl": [
+    [
+     {}
+    ]
+   ],
    "interfaces/screen-orientation.idl": [
     [
      {}
@@ -159425,6 +160222,11 @@
      {}
     ]
    ],
+   "interfaces/speech-api.idl": [
+    [
+     {}
+    ]
+   ],
    "interfaces/storage.idl": [
     [
      {}
@@ -161495,6 +162297,16 @@
      {}
     ]
    ],
+   "origin-policy/origin-policy-single-report.https.tentative.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "origin-policy/sec-origin-policy-header.html.py": [
+    [
+     {}
+    ]
+   ],
    "page-visibility/META.yml": [
     [
      {}
@@ -165170,6 +165982,11 @@
      {}
     ]
    ],
+   "screen-capture/META.yml": [
+    [
+     {}
+    ]
+   ],
    "screen-orientation/META.yml": [
     [
      {}
@@ -168350,16 +169167,36 @@
      {}
     ]
    ],
+   "speech-api/SpeechRecognition-basics.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "speech-api/SpeechSynthesis-speak-ownership-expected.txt": [
     [
      {}
     ]
    ],
+   "speech-api/SpeechSynthesisUtterance-basics.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "speech-api/historical-expected.txt": [
     [
      {}
     ]
    ],
+   "speech-api/idlharness.window-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "speech-api/webspeech.js": [
+    [
+     {}
+    ]
+   ],
    "staticrange/idlharness-expected.txt": [
     [
      {}
@@ -168740,31 +169577,11 @@
      {}
     ]
    ],
-   "streams/transform-streams/constructor-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "streams/transform-streams/constructor.dedicatedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "streams/transform-streams/constructor.js": [
     [
      {}
     ]
    ],
-   "streams/transform-streams/constructor.serviceworker.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "streams/transform-streams/constructor.sharedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "streams/transform-streams/errors.js": [
     [
      {}
@@ -168790,31 +169607,11 @@
      {}
     ]
    ],
-   "streams/transform-streams/properties-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "streams/transform-streams/properties.dedicatedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "streams/transform-streams/properties.js": [
     [
      {}
     ]
    ],
-   "streams/transform-streams/properties.serviceworker.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "streams/transform-streams/properties.sharedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "streams/transform-streams/reentrant-strategies.js": [
     [
      {}
@@ -168860,31 +169657,11 @@
      {}
     ]
    ],
-   "streams/writable-streams/constructor-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "streams/writable-streams/constructor.dedicatedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "streams/writable-streams/constructor.js": [
     [
      {}
     ]
    ],
-   "streams/writable-streams/constructor.serviceworker.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "streams/writable-streams/constructor.sharedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "streams/writable-streams/count-queuing-strategy.js": [
     [
      {}
@@ -191456,6 +192233,18 @@
      {}
     ]
    ],
+   "css/css-grid/alignment/grid-content-alignment-second-pass-001.html": [
+    [
+     "/css/css-grid/alignment/grid-content-alignment-second-pass-001.html",
+     {}
+    ]
+   ],
+   "css/css-grid/alignment/grid-content-alignment-second-pass-002.html": [
+    [
+     "/css/css-grid/alignment/grid-content-alignment-second-pass-002.html",
+     {}
+    ]
+   ],
    "css/css-grid/alignment/grid-fit-content-tracks-dont-stretch-001.html": [
     [
      "/css/css-grid/alignment/grid-fit-content-tracks-dont-stretch-001.html",
@@ -192116,6 +192905,18 @@
      {}
     ]
    ],
+   "css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-001.html": [
+    [
+     "/css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-001.html",
+     {}
+    ]
+   ],
+   "css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-002.html": [
+    [
+     "/css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-002.html",
+     {}
+    ]
+   ],
    "css/css-grid/grid-definition/grid-shorthand-001.html": [
     [
      "/css/css-grid/grid-definition/grid-shorthand-001.html",
@@ -238446,6 +239247,18 @@
      {}
     ]
    ],
+   "origin-policy/origin-policy-single-report.https.tentative.html": [
+    [
+     "/origin-policy/origin-policy-single-report.https.tentative.html",
+     {}
+    ]
+   ],
+   "origin-policy/origin-policy.https.tentative.html": [
+    [
+     "/origin-policy/origin-policy.https.tentative.html",
+     {}
+    ]
+   ],
    "page-visibility/idlharness.window.js": [
     [
      "/page-visibility/idlharness.window.html",
@@ -248574,6 +249387,12 @@
      {}
     ]
    ],
+   "screen-capture/idlharness.window.js": [
+    [
+     "/screen-capture/idlharness.window.html",
+     {}
+    ]
+   ],
    "screen-orientation/idlharness.window.js": [
     [
      "/screen-orientation/idlharness.window.html",
@@ -250988,6 +251807,12 @@
      {}
     ]
    ],
+   "speech-api/SpeechRecognition-basics.https.html": [
+    [
+     "/speech-api/SpeechRecognition-basics.https.html",
+     {}
+    ]
+   ],
    "speech-api/SpeechSynthesis-speak-ownership.html": [
     [
      "/speech-api/SpeechSynthesis-speak-ownership.html",
@@ -251000,12 +251825,24 @@
      {}
     ]
    ],
+   "speech-api/SpeechSynthesisUtterance-basics.https.html": [
+    [
+     "/speech-api/SpeechSynthesisUtterance-basics.https.html",
+     {}
+    ]
+   ],
    "speech-api/historical.html": [
     [
      "/speech-api/historical.html",
      {}
     ]
    ],
+   "speech-api/idlharness.window.js": [
+    [
+     "/speech-api/idlharness.window.html",
+     {}
+    ]
+   ],
    "storage/estimate-indexeddb-worker.https.html": [
     [
      "/storage/estimate-indexeddb-worker.https.html",
@@ -259898,9 +260735,9 @@
      {}
     ]
    ],
-   "workers/WorkerGlobalScope_requestAnimationFrame.htm": [
+   "workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js": [
     [
-     "/workers/WorkerGlobalScope_requestAnimationFrame.htm",
+     "/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.html",
      {}
     ]
    ],
@@ -268545,6 +269382,18 @@
    "c6687ea38b936e06efda7e48c443250c289f3c62",
    "support"
   ],
+  ".well-known/origin-policy/policy-csp-1": [
+   "070be4634ad0a111db28d1fc63575c7c3dd8ff88",
+   "support"
+  ],
+  ".well-known/origin-policy/policy-csp-2": [
+   "688dee802c78eed8e76c060794e26e31894faf72",
+   "support"
+  ],
+  ".well-known/origin-policy/policy-noimg": [
+   "4b01fff64c21ac15a62c4e43d9b0f8169bd95e96",
+   "support"
+  ],
   "2dcontext/2x2.png": [
    "007be94902fda049d59255d281de42ab28cf109d",
    "support"
@@ -277778,7 +278627,7 @@
    "support"
   ],
   "content-security-policy/META.yml": [
-   "8b13100d5ecf0c606f74c249a18bf031ba77094d",
+   "011ec96db0c285d49cba50ec870cd9bd5c01d9c5",
    "support"
   ],
   "content-security-policy/OWNERS": [
@@ -278058,7 +278907,7 @@
    "support"
   ],
   "content-security-policy/embedded-enforcement/support/testharness-helper.sub.js": [
-   "16c95220e0fd759535481069dff71803eea5e22e",
+   "c42fdebea675008c48b82d53003604ba749e7ba7",
    "support"
   ],
   "content-security-policy/font-src/font-match-allowed.sub.html": [
@@ -300962,7 +301811,55 @@
    "reftest"
   ],
   "css/css-contain/contain-layout-breaks-002.html": [
-   "985252e8226e0cba567b49f44665804e3a12bc40",
+   "a5a39930e3f7489472ffa90105397dc26b568306",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-cell-001.html": [
+   "cc75ceacefd46a7baa4cdb8d05bb7ae8aeaa6d90",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-cell-002.html": [
+   "66b76b4bdb51a97820c265fec8648b2047f1f478",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ifc-022.html": [
+   "55b5be4e01f63d960fcae59e2e66b0de72080205",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-013.html": [
+   "4a223dc47213e5f1808bb0d24c8f4f4f28f3a86f",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-014.html": [
+   "1985080ae87a5bd9ced08281a8fa54bb61d656ce",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-015.html": [
+   "87053405b637a66054933e425c1f3ae2b63199a6",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-016.html": [
+   "77b124ac86a1ef769499e444c36709998c85092c",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-017.html": [
+   "8215d93f5e5774e048f1775b142866bab1c0ee51",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-018.html": [
+   "480db96813b6c13eb802bccbe095d8cc6e5469af",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-019.html": [
+   "30f861fab75ab9f008589f2ec3dbee550d3732f4",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-ink-overflow-020.html": [
+   "3d6950b80646467177f664e0330bc7cd62a97097",
+   "reftest"
+  ],
+  "css/css-contain/contain-layout-size-003.html": [
+   "b18a420c4c4f085a9fcbdeb4423e343ed56ffa48",
    "reftest"
   ],
   "css/css-contain/contain-paint-001.html": [
@@ -300973,10 +301870,6 @@
    "fdf31fdc298da8545f125406bc6b7d679bbe3132",
    "reftest"
   ],
-  "css/css-contain/contain-paint-003.html": [
-   "cb8c27b18abe50d15c0dc80520cc3e920aff2160",
-   "reftest"
-  ],
   "css/css-contain/contain-paint-004.html": [
    "7b4b39e623ee8e4845cde4eb51a9f81a2993cec2",
    "reftest"
@@ -301049,6 +301942,82 @@
    "18a6ee002c9bfec978eb71bac0301c51c1886410",
    "reftest"
   ],
+  "css/css-contain/contain-paint-022.html": [
+   "00fdc6d4de84f092cd425dca80ea3bf4d228b62e",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-023.html": [
+   "8fa462c192bf5dc5790f2659d91c17675f0e7f18",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-024.html": [
+   "d9096b3a466455a3c4aeb5dfb9521d8e25288187",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-047.html": [
+   "a9c19687a23dc2e7f5778f6489eb49894e339d79",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-048.html": [
+   "f1d52fc39313a1202f54adcfb3f2a203c6f8c6c9",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-cell-001.html": [
+   "4e60ccfc696c774411f407da84481a45afbae7ce",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-cell-002.html": [
+   "69487e5037dd523987c645f9dec4518c07ff5786",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-011.html": [
+   "9d0493207c0d7339f9b3c93cb62a44a77a70c952",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-012.html": [
+   "aaebf69a654832c720b80c8ecec5e070e78ecee1",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-013.html": [
+   "383888b4eff0f1f57f512521259fe3202bc65049",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-014.html": [
+   "e5d875441cc0436c933905eeedb8b7c2ac72b6d0",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-015.html": [
+   "00e205602ad36b080b813ec7962da5af1d3dbe23",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-016.html": [
+   "3a08a4edc9605a532500d174d664cf38b026c425",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-017.html": [
+   "f5e566ad546f550eb85c785e7116b2700adc13d4",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-clip-018.html": [
+   "81acf8f4bb2be45ed376ce61337fece68d2cd806",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-ifc-011.html": [
+   "a08f93e775150102f2c5a4bb7cb3577f9f76d866",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-size-001.html": [
+   "47fe839437bf6d197a2e7cb239177ddbbb544c3c",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-size-002.html": [
+   "4f94caf1344a63c2a1eb3f38a680a7c0e48a4d9d",
+   "reftest"
+  ],
+  "css/css-contain/contain-paint-size-003.html": [
+   "83c0857ff4f55caa708916a512d43801acf3b1e6",
+   "reftest"
+  ],
   "css/css-contain/contain-size-001.html": [
    "05060bb62063edcc4b7d7ad095e73f703c68eb01",
    "reftest"
@@ -301101,6 +302070,50 @@
    "8974279263fbd89e1b781ee9481c7466ce073f1e",
    "reftest"
   ],
+  "css/css-contain/contain-size-021.html": [
+   "0f6b235d4e822267d4475dba79da99e2a332de07",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-023.html": [
+   "06f9518922bc431341c7975ef1535da8c82bf7d9",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-025.html": [
+   "863285d13c260dceb09877d1433b51e9d06c26b1",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-027.html": [
+   "40e21c047dc24285a5f67ede16e59042efcc390c",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-041.html": [
+   "a76f33a011deaa9929a7353e741ae3bab24ff22a",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-042.html": [
+   "b24f3e65b417dcde5b1d5df3fff12bdb8db6dc4c",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-051.html": [
+   "3731282d5474b1408c3704e2c1a21db65be6d085",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-052.html": [
+   "d7a64a4718bab69e527f5fceb39552f568b99f74",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-056.html": [
+   "8856231969a386a3e5a2d05190cc908165aa7197",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-061.html": [
+   "75a53cbf2534db052f03e703a9ffd15075b3116c",
+   "reftest"
+  ],
+  "css/css-contain/contain-size-062.html": [
+   "df490e5791dc5afeaa283332efead466786ba961",
+   "reftest"
+  ],
   "css/css-contain/contain-size-borders.html": [
    "9c7036290a0a1f1617f23ae0a9d81ab1795f4cd6",
    "reftest"
@@ -301121,6 +302134,22 @@
    "c54ab91012e3985a283a84076789119d204cd7e2",
    "reftest"
   ],
+  "css/css-contain/contain-size-monolithic-001.html": [
+   "b81fcb776dc86a6418bd63ec4af9bd23d999c60e",
+   "reftest"
+  ],
+  "css/css-contain/contain-strict-001.html": [
+   "dbe7f485a5e4adb839caa9c1103030c6cebfd6ad",
+   "reftest"
+  ],
+  "css/css-contain/contain-strict-002.html": [
+   "d96f5f938dddd003e127116aacd036b3f9eeefed",
+   "reftest"
+  ],
+  "css/css-contain/contain-strict-003.html": [
+   "cdc076a73b0e999b4f7c5b1d497667fd766a92d3",
+   "reftest"
+  ],
   "css/css-contain/contain-style-breaks-001.html": [
    "cc6748966bc23c1f8be0aaa57384d0dc1d80c8d1",
    "reftest"
@@ -301141,14 +302170,26 @@
    "2c57f0016d0e8f43c5a37bd169cd948794c686ea",
    "reftest"
   ],
+  "css/css-contain/contain-style-counters-001.html": [
+   "a20afa2a1f6525e6c3394368f6f502940147002e",
+   "reftest"
+  ],
+  "css/css-contain/contain-style-counters-002.html": [
+   "7dc2109259c9b26351a50745e28f48aa007aadd6",
+   "reftest"
+  ],
+  "css/css-contain/contain-style-counters-003.html": [
+   "76497c919df7133e06622c873d4ee659f2b08d4e",
+   "reftest"
+  ],
+  "css/css-contain/contain-style-counters-004.html": [
+   "9a5f6f91d00eeb0389cc05f343bc2b031736797a",
+   "reftest"
+  ],
   "css/css-contain/contain-style-counters-ref.html": [
    "295abc8d8c2490f3ff16566e49e9c77bf125461f",
    "support"
   ],
-  "css/css-contain/contain-style-counters.html": [
-   "712b04117d388e4e2d6747edde2c955b54d397fd",
-   "reftest"
-  ],
   "css/css-contain/counter-scoping-001.html": [
    "237c7d44e913ef11a77260d6bf890f8da64a7cb6",
    "reftest"
@@ -301178,7 +302219,35 @@
    "reftest"
   ],
   "css/css-contain/reference/contain-layout-breaks-002-ref.html": [
-   "f5804830fd9d22117b027135bf5b9191f0f3f15e",
+   "43f4a3d6600e784971b1c4e4244b8854500786f1",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-cell-001-ref.html": [
+   "4b3d3c991df436405eb87038285ee074caad9317",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-ifc-022-ref.html": [
+   "90f9a52f72cedeb4f35741ce1b2c3df915dc8d3c",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-ink-overflow-013-ref.html": [
+   "b2c8bc9643b451e1029fc33fccb94b0242b6dfe4",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-ink-overflow-015-ref.html": [
+   "988c69d5781afbc9d30cfee599bd64a42be0d606",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-ink-overflow-019-ref.html": [
+   "312e991d7a47b1f7151eb0b4a410fbf0decc56fe",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-ink-overflow-020-ref.html": [
+   "219f11472fc26dc79f2a70cfac1a5bb111350763",
+   "support"
+  ],
+  "css/css-contain/reference/contain-layout-size-003-ref.html": [
+   "45ee3e722423eaa70770c828bf651d84b353d135",
    "support"
   ],
   "css/css-contain/reference/contain-paint-001-ref.html": [
@@ -301197,6 +302266,30 @@
    "c3d8d642f2b4b25df84170669222b61866ab3057",
    "support"
   ],
+  "css/css-contain/reference/contain-paint-022-ref.html": [
+   "71564f5299d8583f4ce4112efc352c6729e498f7",
+   "support"
+  ],
+  "css/css-contain/reference/contain-paint-047-ref.html": [
+   "fb700962a5225fd6a3c632dcdd90435192b8d7fa",
+   "support"
+  ],
+  "css/css-contain/reference/contain-paint-clip-015-ref.html": [
+   "1cba355455fb3271b6dc1a304441ee50fb63286f",
+   "support"
+  ],
+  "css/css-contain/reference/contain-paint-ifc-011-ref.html": [
+   "75bfa6d997e155272a275a26b2be6f106553cbe8",
+   "support"
+  ],
+  "css/css-contain/reference/contain-paint-size-001-ref.html": [
+   "ee9f7764dc0ffaa0c42baef9cd40fc89ce71e4e2",
+   "support"
+  ],
+  "css/css-contain/reference/contain-paint-size-003-ref.html": [
+   "e6196f015de2fb9d53b9cf2e97798ed95ed18d00",
+   "support"
+  ],
   "css/css-contain/reference/contain-size-004-ref.html": [
    "090aba85ddcf927a33de227157ac8e411fd5c268",
    "support"
@@ -301205,6 +302298,30 @@
    "9e7e20e4a3e117a5df896522f013ee48e76beabc",
    "support"
   ],
+  "css/css-contain/reference/contain-size-021-ref.html": [
+   "44a7c7f8d041400b735727bf9445f55dde5bb170",
+   "support"
+  ],
+  "css/css-contain/reference/contain-size-022-ref.html": [
+   "3efcec6c5a217a23be964eeee2d5af62247a9f5e",
+   "support"
+  ],
+  "css/css-contain/reference/contain-size-051-ref.html": [
+   "cc47886b1a0ed674f7290d59627564e31d657aa5",
+   "support"
+  ],
+  "css/css-contain/reference/contain-size-056-ref.html": [
+   "539b4508ecd9d0dbcfa6b6293bea328a04a9b580",
+   "support"
+  ],
+  "css/css-contain/reference/contain-size-061-ref.html": [
+   "bf474c4921334d41663020afa23f2613772f4737",
+   "support"
+  ],
+  "css/css-contain/reference/contain-size-062-ref.html": [
+   "2199ca80e78f0d1fffa7913209285a49de62d1c5",
+   "support"
+  ],
   "css/css-contain/reference/contain-size-breaks-001-ref.html": [
    "487fbbb9b8de0e27470ac15f0f0380750d91df88",
    "support"
@@ -301221,6 +302338,10 @@
    "8f2598bcb08c9cb15773a755f8647c416be6c035",
    "support"
   ],
+  "css/css-contain/reference/contain-size-monolithic-001-ref.html": [
+   "1f8720e4eb21996353d828abf6313d36c7d0ca30",
+   "support"
+  ],
   "css/css-contain/reference/contain-style-breaks-001-ref.html": [
    "e83eda6bb259dbe56969a12b0cf53f3ec9ce640d",
    "support"
@@ -301229,6 +302350,14 @@
    "54b59892617a57c9bf280f8ae9f0a4fa0dbb2e87",
    "support"
   ],
+  "css/css-contain/reference/contain-style-counters-001-ref.html": [
+   "db1e22454f2811f7ffde68fae4985284d246eab2",
+   "support"
+  ],
+  "css/css-contain/reference/contain-style-counters-003-ref.html": [
+   "6e284cf153a0c655f8a8abc10e4e64e094132085",
+   "support"
+  ],
   "css/css-contain/reference/counter-scoping-001-ref.html": [
    "997c185d5dc259acc32b21fd3fec87f853690f3a",
    "support"
@@ -301249,6 +302378,42 @@
    "6b72ea53450c5a08ef3ddd897608aa9cf7e68e00",
    "support"
   ],
+  "css/css-contain/reference/ref-if-there-is-no-red.xht": [
+   "36d2369f9c7e3220660a4e5496c2ac2f24a60962",
+   "support"
+  ],
+  "css/css-contain/support/blue-100x100.png": [
+   "d0b5fff876757ee51461e45ca7485e438c357df7",
+   "support"
+  ],
+  "css/css-contain/support/blue50wBy23h.png": [
+   "e89dfb012cc024ac69e2d2a9c3eb2ed6a9484ebf",
+   "support"
+  ],
+  "css/css-contain/support/blue50wBy46h.png": [
+   "0f7bb07c8832270c9f2fa490224cbb85c85f6426",
+   "support"
+  ],
+  "css/css-contain/support/pattern-gg-gr-100x100.png": [
+   "0516dde5ea228b58d6c1cccf8c704fee9f5c9552",
+   "support"
+  ],
+  "css/css-contain/support/swatch-blue.png": [
+   "e79958e10feeeed3db88dee9bae9ea80055593c5",
+   "support"
+  ],
+  "css/css-contain/support/swatch-orange.png": [
+   "10768a5177b772013e628c7397ae64725057295d",
+   "support"
+  ],
+  "css/css-contain/support/swatch-red.png": [
+   "eedea3e9a99c18f5fc2de3796be2c6f9da2ea07d",
+   "support"
+  ],
+  "css/css-contain/support/swatch-yellow.png": [
+   "9cc73897c2e1fc45f5224d81d02a6b87bf72b1fa",
+   "support"
+  ],
   "css/css-content/META.yml": [
    "825ebcde56cd23199e9cd90af312f2837d6b2301",
    "support"
@@ -313093,6 +314258,18 @@
    "d24ae3fb7aad80368ea4f22122e18157596bf45a",
    "testharness"
   ],
+  "css/css-grid/alignment/grid-content-alignment-second-pass-001.html": [
+   "e49de9c1b8182a6c62b3ce3a9a6cb060305cb11b",
+   "testharness"
+  ],
+  "css/css-grid/alignment/grid-content-alignment-second-pass-002-expected.txt": [
+   "2afb2360aaeeeb114f3ff80a810f78ba989d94a5",
+   "support"
+  ],
+  "css/css-grid/alignment/grid-content-alignment-second-pass-002.html": [
+   "22d45abb8d04d0ea2ed351bf718a3f007a84d7e7",
+   "testharness"
+  ],
   "css/css-grid/alignment/grid-content-distribution-001.html": [
    "5622a264eb2dbd6cf621ac97aa4a8ae5db82c6b3",
    "reftest"
@@ -313869,6 +315046,14 @@
    "e30c5d9b04eaf45a511b8df22a2c9719a03ecd92",
    "reftest"
   ],
+  "css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-001.html": [
+   "73d7e603db924d99f1df4ee6761ea6df6f6e8220",
+   "testharness"
+  ],
+  "css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-002.html": [
+   "eea19baeb6b541beddab2a170e477e74b58d8257",
+   "testharness"
+  ],
   "css/css-grid/grid-definition/grid-shorthand-001.html": [
    "31ef1f583e9d09e4d719a0ca5cb5531e8ce08b36",
    "testharness"
@@ -320737,6 +321922,10 @@
    "33aa880de7eb7c4128022871dfd5e2895be30dcc",
    "reftest"
   ],
+  "css/css-sizing/orthogonal-writing-mode-float-in-inline.html": [
+   "83facdff94ac089afc2edfbbb9254e4a81bb28dc",
+   "reftest"
+  ],
   "css/css-sizing/whitespace-and-break.html": [
    "54107f6567df03437aebb1fe8aa5c6403cb1ecf1",
    "reftest"
@@ -342010,7 +343199,7 @@
    "support"
   ],
   "css/css-writing-modes/support/pattern-gg-gr-100x100.png": [
-   "46841065a05226c1c38ce5b5eb0ea71f9fbf4299",
+   "0516dde5ea228b58d6c1cccf8c704fee9f5c9552",
    "support"
   ],
   "css/css-writing-modes/support/pattern-gg-rg-100x100.png": [
@@ -379258,7 +380447,7 @@
    "support"
   ],
   "interfaces/FileAPI.idl": [
-   "ac9d05f31ad82befd9da8e6023b3ab5c3823d370",
+   "dc94962ef147935e5be598ed0609845e479e72d4",
    "support"
   ],
   "interfaces/IndexedDB.idl": [
@@ -379273,6 +380462,10 @@
    "991f7ff8f305a82ca70ba254cdbb019bbf1d00ce",
    "support"
   ],
+  "interfaces/README.md": [
+   "3a89df17f43f5a5e0cd172bae31de9548e35325e",
+   "support"
+  ],
   "interfaces/ResizeObserver.idl": [
    "2835174993c1648c5f8e2a4639727118d62e2d77",
    "support"
@@ -379302,7 +380495,7 @@
    "support"
   ],
   "interfaces/animation-worklet.idl": [
-   "df2684b08687cd7cbc9f1a3754595041e0fa4dd8",
+   "65d8422a170fa4aa16cf1f7634cd017eeb54572a",
    "support"
   ],
   "interfaces/appmanifest.idl": [
@@ -379318,7 +380511,7 @@
    "support"
   ],
   "interfaces/battery-status.idl": [
-   "0afe8bca88113d4a8116663a308079c439b5530d",
+   "f3fcf5a8abf201760e2e8cc8499f66cc7e2e436c",
    "support"
   ],
   "interfaces/beacon.idl": [
@@ -379506,7 +380699,7 @@
    "support"
   ],
   "interfaces/keyboard-map.idl": [
-   "1e9e311a4d347d9f036702d29ef0bc82fca04162",
+   "1d1ddad1d290e39b93545bcf34f8d99e55932bf4",
    "support"
   ],
   "interfaces/longtasks.idl": [
@@ -379522,7 +380715,7 @@
    "support"
   ],
   "interfaces/media-source.idl": [
-   "a3c8e49db54b906ae99e2aa2cc385c0e4d949a80",
+   "825a1e1c8acdbad1d51e0b8e8863ff36bed8585d",
    "support"
   ],
   "interfaces/mediacapture-depth.idl": [
@@ -379534,7 +380727,7 @@
    "support"
   ],
   "interfaces/mediacapture-streams.idl": [
-   "af34b0336b91f5806f6a4d662495f05713b60abd",
+   "695f317656f7b21211a6642714128d05cd018173",
    "support"
   ],
   "interfaces/mediasession.idl": [
@@ -379550,7 +380743,7 @@
    "support"
   ],
   "interfaces/netinfo.idl": [
-   "c40e777040b92c90591f40a02a66440ecc228c5a",
+   "d382fed17bd67ec1cc41287a711ffc5b024280a0",
    "support"
   ],
   "interfaces/notifications.idl": [
@@ -379586,7 +380779,7 @@
    "support"
   ],
   "interfaces/performance-timeline.idl": [
-   "67516402261de8f219f0374d38d42fa17b0a2096",
+   "479fa0ee515e172551e66d9a71f37598cf9dc095",
    "support"
   ],
   "interfaces/permissions.idl": [
@@ -379637,6 +380830,10 @@
    "d500e42e860b94614c0efeeb0b46d2ad7e8d79f9",
    "support"
   ],
+  "interfaces/screen-capture.idl": [
+   "0c53f3ae7b33d94d7d910f3b5b1d05a28239e157",
+   "support"
+  ],
   "interfaces/screen-orientation.idl": [
    "c3d267a479600e83e4782e4a80126e3c4467920f",
    "support"
@@ -379665,6 +380862,10 @@
    "e348a282e353caac1d0bb93e453e06031b1aca75",
    "support"
   ],
+  "interfaces/speech-api.idl": [
+   "38653faaf267c76378c5210f1ab854da5ada5765",
+   "support"
+  ],
   "interfaces/storage.idl": [
    "a1ad440d60e04902f494ecaced1fceb8560adc5c",
    "support"
@@ -379734,7 +380935,7 @@
    "support"
   ],
   "interfaces/webmidi.idl": [
-   "47930880a20607801676fa37a915138e5837e5a1",
+   "883c99386d721db291df7919d149c908721b43f6",
    "support"
   ],
   "interfaces/webrtc-stats.idl": [
@@ -379742,7 +380943,7 @@
    "support"
   ],
   "interfaces/webrtc.idl": [
-   "d7cd98169078292592ff7443f5754d5496ca2f75",
+   "134da863b52d01d87a47981a536df9a9e143e32b",
    "support"
   ],
   "interfaces/webusb.idl": [
@@ -389661,6 +390862,22 @@
    "250d6009213e72069acd56e847fc9509c52c1d90",
    "support"
   ],
+  "origin-policy/origin-policy-single-report.https.tentative.html": [
+   "f059114884dcdce34af13bf368bafa0e8a54c725",
+   "testharness"
+  ],
+  "origin-policy/origin-policy-single-report.https.tentative.html.headers": [
+   "55aacfed81aa035e9811b198a367f7ee225866cb",
+   "support"
+  ],
+  "origin-policy/origin-policy.https.tentative.html": [
+   "d716683b29cc10b518a1e711bf6e24d7fdd96843",
+   "testharness"
+  ],
+  "origin-policy/sec-origin-policy-header.html.py": [
+   "72ec999c555db89a81ef758a3e693dc958f593c0",
+   "support"
+  ],
   "page-visibility/META.yml": [
    "b59824c30c1241ea505cd76974b477f2e7980e53",
    "support"
@@ -391314,7 +392531,7 @@
    "support"
   ],
   "priority-hints/META.yml": [
-   "44692282447605bf39a90316e4cc40b2e9c54143",
+   "ea54865690eddddbdc19ea50771be57223ebed05",
    "support"
   ],
   "priority-hints/fetch-api-request.tentative.any.js": [
@@ -391322,7 +392539,7 @@
    "testharness"
   ],
   "priority-hints/img-attr-named-constructor.tentative.html": [
-   "7c30cb250fb854916a8bf87a4fd5c049ee1dcf5b",
+   "5bed40467a329674f4e03761708e5e1370c941cd",
    "testharness"
   ],
   "priority-hints/link-attr.tentative.html": [
@@ -399793,6 +401010,14 @@
    "a68dca4f542588b705f126df73dfad8c88c69506",
    "support"
   ],
+  "screen-capture/META.yml": [
+   "2148044e4034fd793687f1b54c8ad5963c5977fe",
+   "support"
+  ],
+  "screen-capture/idlharness.window.js": [
+   "73c374fc70909fed944ef904a1a0a8312680d387",
+   "testharness"
+  ],
   "screen-orientation/META.yml": [
    "33d7f9f9207dc190350f9f764b8766269aff87af",
    "support"
@@ -404109,6 +405334,30 @@
    "68bf73d9ac6cd140065dfb17a11e18e83055704f",
    "support"
   ],
+  "speech-api/SpeechRecognition-abort-manual.https.html": [
+   "db0b9b6577ae91eca28d739ee45398b7ed43dcef",
+   "manual"
+  ],
+  "speech-api/SpeechRecognition-basics.https-expected.txt": [
+   "564aa8c26fa7155402409e6fd552fff20aa2ec53",
+   "support"
+  ],
+  "speech-api/SpeechRecognition-basics.https.html": [
+   "b9146fa405b31fc370d24a2655fb0a91993de4c3",
+   "testharness"
+  ],
+  "speech-api/SpeechRecognition-onerror-manual.https.html": [
+   "238a87d55edd0e540592d59295f1dd2959153edb",
+   "manual"
+  ],
+  "speech-api/SpeechRecognition-onresult-manual.https.html": [
+   "54ae3e872b5ce0785bb146cf2a5ce5e028e36823",
+   "manual"
+  ],
+  "speech-api/SpeechRecognition-stop-manual.https.html": [
+   "11f329ac1a29409fa715ff951f8e146bce4f4bb2",
+   "manual"
+  ],
   "speech-api/SpeechSynthesis-speak-ownership-expected.txt": [
    "d0f7cd2adefa9222ee2b81fa31e5f007e904ddd2",
    "support"
@@ -404121,14 +405370,34 @@
    "60eaf93103abe422222307b3c4172f2a0fabee57",
    "testharness"
   ],
+  "speech-api/SpeechSynthesisUtterance-basics.https-expected.txt": [
+   "e345bd541b67f582c4220f61e93481b76c022782",
+   "support"
+  ],
+  "speech-api/SpeechSynthesisUtterance-basics.https.html": [
+   "b2d12479fddd006905a90789aaf88c2ed7fccf1c",
+   "testharness"
+  ],
   "speech-api/historical-expected.txt": [
-   "0ea0408ab857b42d5359deebec1ebf11f776046a",
+   "9d8733285d54d65c010e0010b1a7549e43b363e3",
    "support"
   ],
   "speech-api/historical.html": [
-   "45bfdcce349e2cb28611520b006c060347fdf58d",
+   "9405eb4f26b5f004144896cfc2d4f174a98577e0",
    "testharness"
   ],
+  "speech-api/idlharness.window-expected.txt": [
+   "b8009d0a88e6a7cdaeaa8f69e54cea39e8d15b95",
+   "support"
+  ],
+  "speech-api/idlharness.window.js": [
+   "5403401d79d8bf7f6ce8146a26aa65fa41224fd2",
+   "testharness"
+  ],
+  "speech-api/webspeech.js": [
+   "a9c5181e5c1f522ff1523b700c8f37a0ac04ff84",
+   "support"
+  ],
   "staticrange/idlharness-expected.txt": [
    "638d1ae46157f1d00cb2134ecb75ce38f8352028",
    "support"
@@ -405033,14 +406302,6 @@
    "6f3911baf77e26af2d7e7d7472caae4df6d5a27e",
    "testharness"
   ],
-  "streams/transform-streams/constructor-expected.txt": [
-   "17c8be315ddda64c37afa4c53a1bbad971a05bd6",
-   "support"
-  ],
-  "streams/transform-streams/constructor.dedicatedworker-expected.txt": [
-   "17c8be315ddda64c37afa4c53a1bbad971a05bd6",
-   "support"
-  ],
   "streams/transform-streams/constructor.dedicatedworker.html": [
    "6c954f0d265d21fe1dae9d85afbcc79e8d875797",
    "testharness"
@@ -405053,18 +406314,10 @@
    "93845386cad513a39d8536f82fc536f61ecc1dc3",
    "support"
   ],
-  "streams/transform-streams/constructor.serviceworker.https-expected.txt": [
-   "f0348726ed06bfcc14309b18ac3d41fdee6a252e",
-   "support"
-  ],
   "streams/transform-streams/constructor.serviceworker.https.html": [
    "025f934a714ce8c52df953ba570a527cbcb88399",
    "testharness"
   ],
-  "streams/transform-streams/constructor.sharedworker-expected.txt": [
-   "17c8be315ddda64c37afa4c53a1bbad971a05bd6",
-   "support"
-  ],
   "streams/transform-streams/constructor.sharedworker.html": [
    "f6ce1491f86ee048da0f6135440b7aa5359caa22",
    "testharness"
@@ -405169,14 +406422,6 @@
    "477cc1ed4cc94ff6ee29dcd6f96c16768a2c7567",
    "testharness"
   ],
-  "streams/transform-streams/properties-expected.txt": [
-   "7e7c5d6ef953f585985eb10eddf94b3b71fe2dee",
-   "support"
-  ],
-  "streams/transform-streams/properties.dedicatedworker-expected.txt": [
-   "7e7c5d6ef953f585985eb10eddf94b3b71fe2dee",
-   "support"
-  ],
   "streams/transform-streams/properties.dedicatedworker.html": [
    "0d766237560b16ddb1bfcd02e701089132f1b3ec",
    "testharness"
@@ -405189,18 +406434,10 @@
    "04ed8ef8fdaf1906c8a3cf0fe8e52943abe6084c",
    "support"
   ],
-  "streams/transform-streams/properties.serviceworker.https-expected.txt": [
-   "0de908d9840a89d42b20d09ecc1069e1c9c995fe",
-   "support"
-  ],
   "streams/transform-streams/properties.serviceworker.https.html": [
    "2ef8fc878249c429a89e0748e6a98fac47c1a99a",
    "testharness"
   ],
-  "streams/transform-streams/properties.sharedworker-expected.txt": [
-   "7e7c5d6ef953f585985eb10eddf94b3b71fe2dee",
-   "support"
-  ],
   "streams/transform-streams/properties.sharedworker.html": [
    "5c855e897d1143092ecc10b58268e6a576882184",
    "testharness"
@@ -405385,14 +406622,6 @@
    "b2aeb127d5ae7087b42e3fc08faaa113c84e6fd8",
    "testharness"
   ],
-  "streams/writable-streams/constructor-expected.txt": [
-   "deb8410400986ef8d5b246730041ddd6319c5f43",
-   "support"
-  ],
-  "streams/writable-streams/constructor.dedicatedworker-expected.txt": [
-   "deb8410400986ef8d5b246730041ddd6319c5f43",
-   "support"
-  ],
   "streams/writable-streams/constructor.dedicatedworker.html": [
    "6c954f0d265d21fe1dae9d85afbcc79e8d875797",
    "testharness"
@@ -405405,18 +406634,10 @@
    "a116d92d0e20f463de6073ee6392e30c1d6927dc",
    "support"
   ],
-  "streams/writable-streams/constructor.serviceworker.https-expected.txt": [
-   "97d0aaedae7e65ea968c6a09260bcb48ae347fd8",
-   "support"
-  ],
   "streams/writable-streams/constructor.serviceworker.https.html": [
    "025f934a714ce8c52df953ba570a527cbcb88399",
    "testharness"
   ],
-  "streams/writable-streams/constructor.sharedworker-expected.txt": [
-   "deb8410400986ef8d5b246730041ddd6319c5f43",
-   "support"
-  ],
   "streams/writable-streams/constructor.sharedworker.html": [
    "f6ce1491f86ee048da0f6135440b7aa5359caa22",
    "testharness"
@@ -407950,7 +409171,7 @@
    "support"
   ],
   "wasm/resources/service-worker.js": [
-   "240ed8ea51a45a84978a20240854ae70e1d460af",
+   "d1b8ad09830985a5ce9ac0fe0f88b6d68eb7f012",
    "support"
   ],
   "wasm/wasm_idb_worker.js": [
@@ -407982,7 +409203,7 @@
    "support"
   ],
   "wasm/wasm_service_worker_test.https.html": [
-   "254d9b7074c89c57e15613e6efe9674eba95b74d",
+   "6933cb7a5c73359f7d7748c0d0e784cf6b88e4d8",
    "testharness"
   ],
   "web-animations/META.yml": [
@@ -410870,11 +412091,11 @@
    "testharness"
   ],
   "webrtc/RTCRtpParameters-transactionId-expected.txt": [
-   "a870299433debbcbad921bf9ae29f0115ccc14fa",
+   "4db0275eedd571fd2b1b69473002768fd4111819",
    "support"
   ],
   "webrtc/RTCRtpParameters-transactionId.html": [
-   "a48817af4be42460a1f44f39e63f292662228db8",
+   "ad24fdbfb2e53906c11353f4cf1fb71325c5065d",
    "testharness"
   ],
   "webrtc/RTCRtpReceiver-getCapabilities.html": [
@@ -415565,8 +416786,8 @@
    "c67d281e78f9672e5f25fdde6b978e0fb7bd806e",
    "testharness"
   ],
-  "workers/WorkerGlobalScope_requestAnimationFrame.htm": [
-   "bee219d9a0cabcf7732ba9c3beb16514e3930970",
+  "workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js": [
+   "4d6e01b9d9f736609756af518855d5790827a71e",
    "testharness"
   ],
   "workers/WorkerGlobalScope_setInterval.htm": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/META.yml b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/META.yml
index 99c5a782..ee8f1ea 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/META.yml
@@ -1,3 +1,4 @@
 spec: https://w3c.github.io/webappsec-csp/
 suggested_reviewers:
+  - andypaicu
   - hillbrad
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/support/testharness-helper.sub.js b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/support/testharness-helper.sub.js
index 6d2e64f..c1b2e67 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/support/testharness-helper.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/support/testharness-helper.sub.js
@@ -119,11 +119,11 @@
 
   if (shouldBlock) {
     // Assert iframe does not load and is inaccessible.
-    window.onmessage = function (e) {
+    window.onmessage = t.step_func(function(e) {
       if (e.source != i.contentWindow)
           return;
-      t.assert_unreached('No message should be sent from the frame.');
-    }
+      assert_unreached('No message should be sent from the frame.');
+    });
     i.onload = t.step_func(function () {
       // Delay the check until after the postMessage has a chance to execute.
       setTimeout(t.step_func_done(function () {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html
index 4398387f..fadb3c4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-breaks-002.html
@@ -1,34 +1,54 @@
-<!doctype html>
-<html lang=en>
-  <meta charset=utf-8>
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
   <title>CSS-contain test: layout containment and forced breaks</title>
-  <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
-  <meta name=flags content="">
-  <meta name=assert content="forced breaks within layout containment do not propagate to the parent.">
-  <link rel="match" href="reference/contain-layout-breaks-002-ref.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-layout">
-  <link rel=help href="https://drafts.csswg.org/css-break-3/#forced-break">
 
-<style>
-article {
-  columns: 2 20px;
-  float: left;
-  height: 50px;
-  column-fill: auto;
-}
-div > div {
-  border-top: 20px solid orange;
-  break-before: column;
-}
-article > div {
-  border-top: 20px solid orange;
-  contain: layout;
-}
-</style>
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <meta content="" name="flags">
+  <meta content="forced breaks within layout containment do not propagate to the parent." name="assert">
 
-<p>Test passes if there are two orange boxes below.
-<article>
-  <div>
-    <div></div>
-  </div>
-</article>
+  <link href="reference/contain-layout-breaks-002-ref.html" rel="match">
+
+  <link href="https://drafts.csswg.org/css-contain-1/#containment-layout" rel="help">
+  <link href="https://drafts.csswg.org/css-break-3/#forced-break" rel="help">
+
+  <style>
+  article
+    {
+      column-fill: auto; /* columns are filled sequentially */
+      column-gap: 0em;
+      columns: 2 100px; /* 2 columns each 100px wide */
+      float: left; /* to make multi-column element shrink-wrap */
+      height: 400px; /* give more than enough to go wrong */
+    }
+
+  div#yellow-normal
+    {
+      border-top: yellow solid 100px;
+    }
+
+  div#blue-parent
+    {
+      border-top: blue solid 100px;
+      contain: layout;
+    }
+
+  div#orange-child
+    {
+      border-top: orange solid 100px;
+      break-before: column;
+    }
+  </style>
+
+  <p>Test passes if there is a) a blue square below a yellow square and b) an orange square on the righthand side of the yellow square.
+
+  <article>
+
+    <div id="yellow-normal"></div>
+
+    <div id="blue-parent">
+      <div id="orange-child"></div>
+    </div>
+
+  </article>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-cell-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-cell-001.html
new file mode 100644
index 0000000..d0a2f28
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-cell-001.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' applies to 'table-cell' elements</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-cell-001-ref.html">
+
+  <meta content="In this test, the div#contain should act as the containing block for div#abs-pos ." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#table
+    {
+      background-color: blue;
+      border-spacing: 2px;
+      display: table;
+      height: 206px;
+      table-layout: fixed;
+      width: 206px;
+    }
+
+  div.row
+    {
+      display: table-row;
+    }
+
+  div.cell
+    {
+      background-color: white;
+      display: table-cell;
+    }
+
+  div#contain
+    {
+      contain: layout;
+    }
+
+  span
+    {
+      background-color: red;
+      color: yellow;
+      font-family: monospace;
+    }
+
+  div#abs-pos
+    {
+      background-color: green;
+      color: white;
+      font-family: monospace;
+      left: 0px;
+      position: absolute;
+      top: 0px;
+    }
+  </style>
+
+  <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+  <div id="table">
+
+    <div class="row"><div class="cell">&nbsp;</div><div class="cell">&nbsp;</div></div>
+
+    <div class="row"><div class="cell">&nbsp;</div><div class="cell" id="contain"><span>FAIL</span><div id="abs-pos">PASS</div></div></div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-cell-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-cell-002.html
new file mode 100644
index 0000000..5d4eff0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-cell-002.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' applies to 'table-cell' elements</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-cell-001-ref.html">
+
+  <meta content="In this test, the td#contain should act as the containing block for div#abs-pos ." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  table
+    {
+      background-color: blue;
+      border-spacing: 2px;
+      height: 206px;
+      table-layout: fixed;
+      width: 206px;
+    }
+
+  td
+    {
+      background-color: white;
+      padding: 0px;
+      vertical-align: baseline;
+    }
+
+  td#contain
+    {
+      contain: layout;
+    }
+
+  span
+    {
+      background-color: red;
+      color: yellow;
+      font-family: monospace;
+    }
+
+  div#abs-pos
+    {
+      background-color: green;
+      color: white;
+      font-family: monospace;
+      left: 0px;
+      position: absolute;
+      top: 0px;
+    }
+  </style>
+
+  <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+  <table>
+
+    <tr><td>&nbsp;<td>&nbsp;
+
+    <tr><td>&nbsp;<td id="contain"><span>FAIL</span><div id="abs-pos">PASS</div>
+
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ifc-022.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ifc-022.html
new file mode 100644
index 0000000..3e4f3daf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ifc-022.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and creation of an independent formating context: text no longer flowing around a float</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ifc-022-ref.html">
+
+  <meta content="This test checks that an element with 'contain: layout' will make such element create its own formatting context. In this test, the element with 'contain: layout' acts as if it has its own formatting context independent from div#floated-left element. In other words, the div#with-contain-layout is no longer required to flow its content around the div#floated-left element and current line boxes next to the float are no longer shortened to make room for the margin box of the float." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      color: transparent;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#floated-left
+    {
+      background-color: blue;
+      float: left;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#with-contain-layout
+    {
+      background-color: orange;
+      contain: layout;
+      width: 12em;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <!--
+
+  or
+
+  <p>Test passes if the orange rectangle and blue rectangle are side by side.
+
+  or
+
+  <p>Test passes if the orange rectangle and blue rectangle are apart from each other.
+
+  -->
+
+  <div id="floated-left">Some text in a blue rectangle.</div>
+
+  <div id="with-contain-layout">Some text in an orange rectangle. Some text in an orange rectangle. Some text in an orange rectangle.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html
new file mode 100644
index 0000000..d143173
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-013-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+  <style>
+  div#outer
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      line-height: 1.5; /* computes to 150px */
+      width: 4ch;
+
+      overflow: scroll;
+    }
+
+  div#inner
+    {
+      color: red;
+      contain: layout;
+      width: 0;
+    }
+  </style>
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000;">
+
+  <p>Test passes if there is no red.
+
+  <div id="outer">
+    <div id="inner">&nbsp;&nbsp;&nbsp;&nbsp;FAIL</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html
new file mode 100644
index 0000000..ad1c94e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-013-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+  <style>
+  div#outer
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      line-height: 1.5; /* computes to 150px */
+      width: 4ch;
+
+      overflow: scroll;
+    }
+
+  div#inner
+    {
+      color: red;
+      contain: layout;
+      height: 0;
+    }
+  </style>
+
+  <!--
+
+  150px : height of 1 line box
+
+  -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 250; document.getElementById('outer').scrollTop = 150;">
+
+  <p>Test passes if there is no red.
+
+  <div id="outer">
+    <div id="inner">&nbsp;<br>FAIL</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-015.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-015.html
new file mode 100644
index 0000000..0eaaf9a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-015.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-015-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+  <style>
+  div#outer
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      line-height: 1.5; /* computes to 150px */
+      width: 4ch;
+
+      overflow: auto;
+    }
+
+  div#inner
+    {
+      color: red;
+      contain: layout;
+      width: 0;
+    }
+  </style>
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000;">
+
+  <p>Test passes if there is no red.
+
+  <div id="outer">
+    <div id="inner">&nbsp;&nbsp;&nbsp;&nbsp;FAIL</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-016.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-016.html
new file mode 100644
index 0000000..e4ade9d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-016.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-015-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+  <style>
+  div#outer
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      line-height: 1.5; /* computes to 150px */
+      width: 4ch;
+
+      overflow: auto;
+    }
+
+  div#inner
+    {
+      color: red;
+      contain: layout;
+      height: 0;
+    }
+  </style>
+
+  <!--
+
+  150px : height of 1 line box
+
+  -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 250; document.getElementById('outer').scrollTop = 150;">
+
+  <p>Test passes if there is no red.
+
+  <div id="outer">
+    <div id="inner">&nbsp;<br>FAIL</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html
new file mode 100644
index 0000000..ebdcd04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-013-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+  <style>
+  div#outer
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      line-height: 1.5; /* computes to 150px */
+      width: 4ch;
+
+      overflow: scroll;
+    }
+
+  div#inner
+    {
+      color: red;
+      contain: layout;
+      height: 0;
+      width: 0;
+    }
+  </style>
+
+  <!--
+
+  150px : height of 1 line box
+
+  -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000; document.getElementById('outer').scrollTop = 150;">
+
+  <p>Test passes if there is no red.
+
+  <div id="outer">
+    <div id="inner"><br>FAIL</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-018.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-018.html
new file mode 100644
index 0000000..bf00128b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-018.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: layout' and ink overflow</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-015-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
+
+  <style>
+  div#outer
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      line-height: 1.5; /* computes to 150px */
+      width: 4ch;
+
+      overflow: auto;
+    }
+
+  div#inner
+    {
+      color: red;
+      contain: layout;
+      height: 0;
+      width: 0;
+    }
+  </style>
+
+  <!--
+
+  150px : height of 1 line box
+
+  -->
+
+ <body onload="document.getElementById('outer').scrollLeft = 4000; document.getElementById('outer').scrollTop = 150;">
+
+  <p>Test passes if there is no red.
+
+  <div id="outer">
+    <div id="inner"><br>FAIL</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-019.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-019.html
new file mode 100644
index 0000000..d4909aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-019.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Test: 'contain: layout' on element that overflows and its parent has 'overflow: scroll'</title>
+
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-019-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its overflowing content must be treated as ink overflow. Such overflowing content therefore can not be reached and can not be accessed by the scrollbars or by the scrolling mechanism of the parent of such element. In this test, the parent has 'overflow: scroll'." name="assert">
+
+  <style>
+  div
+    {
+      height: 100px;
+      width: 100px;
+    }
+
+    /* this means that each and all 4 div's use the same definite height and width */
+
+  div#parent-with-overflow-scroll
+    {
+      overflow: scroll;
+    }
+
+  div#contain
+    {
+      contain: layout;
+    }
+
+  div#pass
+    {
+      background-color: green;
+    }
+
+  div#fail
+    {
+      background-color: red;
+    }
+  </style>
+
+  <!--
+
+    25px  : height of a very tall horizontal scrollbar
+ +
+   100px  : height of div#fail
+  =======
+   125px
+
+  -->
+
+  <body onload="document.getElementById('parent-with-overflow-scroll').scrollLeft = 100; document.getElementById('parent-with-overflow-scroll').scrollTop = 125;">
+
+  <p>Test passes if there is a filled green square <strong>with 2 scroll bars</strong> and if there is <strong>no red</strong>.
+
+  <div id="parent-with-overflow-scroll">
+
+    <div id="contain">
+
+      <div id="pass"></div>
+
+      <div id="fail"></div>
+
+    </div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-020.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-020.html
new file mode 100644
index 0000000..2ed9062e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-ink-overflow-020.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Test: 'contain: layout' on element that overflows and its parent has 'overflow: auto'</title>
+
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-layout-ink-overflow-020-ref.html">
+
+  <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its overflowing content must be treated as ink overflow. Such overflowing content therefore can not be reached and can not be accessed by the scrollbars or by the scrolling mechanism of the parent of such element. In this test, the parent has 'overflow: auto' and therefore will not create scrollbars or a scrolling mechanism because the ink overflow is not a scrollable region for the parent." name="assert">
+
+  <style>
+  div
+    {
+      height: 100px;
+      width: 100px;
+    }
+
+    /* this means that each and all 4 div's use the same definite height and width */
+
+  div#parent-with-overflow-auto
+    {
+      overflow: auto;
+    }
+
+  div#contain
+    {
+      contain: layout;
+    }
+
+  div#pass
+    {
+      background-color: green;
+    }
+
+  div#fail
+    {
+      background-color: red;
+    }
+  </style>
+
+  <!--
+
+    25px  : height of a very tall horizontal scrollbar
+ +
+   100px  : height of div#fail
+  =======
+   125px
+
+  -->
+
+  <body onload="document.getElementById('parent-with-overflow-auto').scrollLeft = 100; document.getElementById('parent-with-overflow-auto').scrollTop = 125;">
+
+  <p>Test passes if there is a filled green square, <strong>no scrollbar around it</strong> and <strong>no red</strong>.
+
+  <div id="parent-with-overflow-auto">
+
+    <div id="contain">
+
+      <div id="pass"></div>
+
+      <div id="fail"></div>
+
+    </div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-size-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-size-003.html
new file mode 100644
index 0000000..1abbe267
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-size-003.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: a block with 'contain: layout size' alongside a float</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-layout-size-003-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      color: transparent;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#floated-left
+    {
+      background-color: blue;
+      float: left;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#with-contain-layout-size
+    {
+      background-color: orange;
+      width: 12em;
+
+      contain: layout size;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <div id="floated-left">Some text in a blue rectangle.</div>
+
+  <div id="with-contain-layout-size">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html
deleted file mode 100644
index ae9238d..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-003.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!doctype html>
-<html lang=en>
-  <meta charset=utf-8>
-  <title>CSS-contain test: paint containment applies to the principal box for tables</title>
-  <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
-  <meta name=flags content="">
-  <meta name=assert content="paint containment applies to the principal box, which is the table wrapper box for tables">
-  <link rel="match" href="../reference/pass_if_pass_below.html">
-  <link rel=help href="https://drafts.csswg.org/css-contain-1/#containment-paint">
-
-<style>
-table { contain: paint; }
-</style>
-
-<p>Test passes if there is the word "PASS" below.</p>
-<table>
-  <caption>PASS</caption>
-</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-022.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-022.html
new file mode 100644
index 0000000..6f7fecd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-022.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and absolutely positioned descendants</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-022-ref.html">
+
+  <meta content="This test checks that paint containment applies to atomic inline elements and then they act as containing block for absolutely positioned descendants." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#incorrect-containing-block
+    {
+      color: transparent;
+      font-family: Ahem;
+      font-size: 100px;
+      height: 2em;
+      line-height: 1;
+      position: relative;
+      width: 2em;
+    }
+
+  div#correct-containing-block
+    {
+      background-color: red;
+      contain: paint;
+      display: inline-block;
+      height: 1em;
+      width: 1em;
+    }
+
+  div#abspos
+    {
+      background-color: green;
+      height: 1em;
+      left: 0;
+      position: absolute;
+      top: 0;
+      width: 1em;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="incorrect-containing-block">
+
+  AB C<div id="correct-containing-block">
+
+      <div id="abspos"></div>
+
+    </div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-023.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-023.html
new file mode 100644
index 0000000..368f75f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-023.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and absolutely positioned descendants</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+  <meta content="This test checks that paint containment applies to atomic inline elements so that they can act as containing block for absolutely positioned descendants." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#rel-pos-red
+    {
+      background-image: url("support/pattern-gg-gr-100x100.png");
+      color: green;
+      font-family: Ahem;
+      font-size: 50px;
+      height: 2em;
+      line-height: 1;
+      position: relative;
+      width: 2em;
+    }
+
+  div#containing-block
+    {
+      contain: paint;
+      display: inline-block;
+      height: 50%;
+      vertical-align: top;
+      width: 50%;
+    }
+
+  div#abspos
+    {
+      background-color: green;
+      height: 50px;
+      position: absolute;
+      left: 0px;
+      width: 50px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="rel-pos-red">
+
+    AB C<div id="containing-block">
+
+      <div id="abspos"></div>
+
+    </div>
+
+  </div>
+
+  <!--
+
+    |--------|
+    |  A  B  |
+    |    .---|
+    |  C |c-b|
+    |----|---|
+
+  -->
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-024.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-024.html
new file mode 100644
index 0000000..79ef8a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-024.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and absolutely positioned descendants</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+  <meta content="This test checks that paint containment does not apply to non-atomic inline elements so they do not act as containing block for absolutely positioned descendants." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#correct-containing-block
+    {
+      background-color: red;
+      height: 100px;
+      position: relative;
+      width: 100px;
+    }
+
+  div#incorrect-containing-block
+    {
+      contain: paint;
+      display: inline;
+    }
+
+  div#abspos
+    {
+      background-color: green;
+      bottom: 0;
+      height: 100%;
+      position: absolute;
+      right: 0;
+      width: 100%;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="correct-containing-block">
+
+    <div id="incorrect-containing-block">
+
+      <div id="abspos"></div>
+
+    </div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-047.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-047.html
new file mode 100644
index 0000000..e4a0b284
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-047.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-047-ref.html">
+
+  <meta content="This test checks that an element with 'contain: paint' that has its content overflowing will clip at padding edge." name="assert">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      color: green;
+      contain: paint;
+      font-family: monospace;
+      font-size: 100px;
+      width: 4ch;
+    }
+
+  span
+    {
+      background-color: red;
+      color: yellow;
+    }
+  </style>
+
+  <p>Test passes if there is <strong>no red</strong>.
+
+  <div>PASS<span>FAIL</span></div>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-048.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-048.html
new file mode 100644
index 0000000..e48fcb6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-048.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/ref-if-there-is-no-red.xht">
+
+  <meta content="This test checks that an element with 'contain: paint' that has its content overflowing will clip at padding edge." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      color: red;
+      contain: paint;
+      font-size: 100px;
+      width: 0;
+    }
+
+  </style>
+
+  <p>Test passes if there is <strong>no red</strong>.
+
+  <div>FAIL</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-cell-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-cell-001.html
new file mode 100644
index 0000000..964f33a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-cell-001.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' applies to 'table-cell' elements</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout">
+  <link rel="match" href="reference/contain-paint-047-ref.html">
+
+  <meta content="This test checks that the paint containment applies to table-cell elements. Therefore the content of the table-cell element should be clipped to the padding edge of its principal box." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#table
+    {
+      display: table;
+      font-family: monospace;
+      font-size: 100px;
+      table-layout: fixed;
+      width: 4ch;
+    }
+
+  div.column
+    {
+      display: table-column;
+    }
+
+  div#middle-column
+    {
+      width: 4ch;
+    }
+
+  div.row
+    {
+      display: table-row;
+    }
+
+  div.cell
+    {
+      background-color: white;
+      display: table-cell;
+    }
+
+  div#contain
+    {
+      color: green;
+      contain: paint;
+    }
+
+  span
+    {
+      background-color: red;
+      color: yellow;
+    }
+  </style>
+
+  <p>Test passes if there is <strong>no red</strong>.
+
+  <div id="table">
+
+    <div class="column"></div><div class="column" id="middle-column"></div><div class="column"></div>
+
+    <div class="row"><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
+
+    <div class="row"><div class="cell"></div><div class="cell" id="contain">PASS<span>FAIL</span></div><div class="cell"></div></div>
+
+    <div class="row"><div class="cell"></div><div class="cell"></div><div class="cell"></div></div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-cell-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-cell-002.html
new file mode 100644
index 0000000..e486aa2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-cell-002.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and table-cell elements</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-047-ref.html">
+
+  <meta content="This test checks that the paint containment applies to table-cell elements. Therefore the content of the table-cell element should be clipped to the padding edge of its principal box." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  table
+    {
+      border-spacing: 0px;
+      /* to help reuse an already created reference file */
+      font-family: monospace;
+      font-size: 100px;
+      table-layout: fixed;
+      width: 4ch;
+    }
+
+  td
+    {
+      padding: 0px;
+      /* to help reuse an already created reference file */
+    }
+
+  col#middle-column
+    {
+      width: 4ch;
+    }
+
+  td#test
+    {
+      color: green;
+      contain: paint;
+  }
+
+  span
+    {
+      background-color: red;
+      color: yellow;
+    }
+  </style>
+
+  <p>Test passes if there is <strong>no red</strong>.
+
+  <table>
+
+    <col><col id="middle-column"><col>
+
+    <tr><td><td><td>
+
+    <tr><td><td id="test">PASS<span>FAIL</span><td>
+
+    <tr><td><td><td>
+
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-011.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-011.html
new file mode 100644
index 0000000..643133a4f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-011.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+  <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      width: 100px;
+    }
+
+  div#red-overlapped-test
+    {
+      background-color: red;
+      contain: paint;
+    }
+
+  img
+    {
+      vertical-align: bottom;
+    }
+
+  div#green-overlapping-reference
+    {
+      background-color: green;
+      bottom: 100px;
+      height: 100px;
+      position: relative;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="red-overlapped-test"><img src="support/swatch-red.png" width="200" height="100" alt="Image download support must be enabled"></div>
+
+  <div id="green-overlapping-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-012.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-012.html
new file mode 100644
index 0000000..7040d64
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-012.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+  <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      height: 100px;
+      width: 100px;
+    }
+
+  div#red-overlapped-test
+    {
+      background-color: red;
+      contain: paint;
+    }
+
+  img
+    {
+      vertical-align: bottom;
+    }
+
+  div#green-overlapping-reference
+    {
+      background-color: green;
+      bottom: 100px;
+      position: relative;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="red-overlapped-test"><img src="support/swatch-red.png" width="100" height="200" alt="Image download support must be enabled"></div>
+
+  <div id="green-overlapping-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-013.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-013.html
new file mode 100644
index 0000000..e631130
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-013.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+  <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta name="flags" content="">
+
+  <style>
+  div#red-overlapped-test
+    {
+      background-color: red;
+      contain: paint;
+      padding: 0px 25px;
+      width: 50px;
+    }
+
+  img
+    {
+      vertical-align: bottom;
+    }
+
+  div#green-overlapping-reference
+    {
+      background-color: green;
+      bottom: 100px;
+      height: 100px;
+      position: relative;
+      width: 100px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="red-overlapped-test"><img src="support/swatch-red.png" width="175" height="100" alt="Image download support must be enabled"></div>
+
+  <div id="green-overlapping-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-014.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-014.html
new file mode 100644
index 0000000..8fe10717
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-014.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+  <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta name="flags" content="">
+
+  <style>
+  div#red-overlapped-test
+    {
+      background-color: red;
+      contain: paint;
+      height: 50px;
+      padding: 25px 0px;
+      width: 100px;
+    }
+
+  img
+    {
+      vertical-align: bottom;
+    }
+
+  div#green-overlapping-reference
+    {
+      background-color: green;
+      bottom: 100px;
+      height: 100px;
+      position: relative;
+      width: 100px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div id="red-overlapped-test"><img src="support/swatch-red.png" width="100" height="175" alt="Image download support must be enabled"></div>
+
+  <div id="green-overlapping-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-015.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-015.html
new file mode 100644
index 0000000..b78f0d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-015.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+  <!--
+  This test fails in Chromium 66.0.3359.117
+  -->
+
+  <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box, taking corner clipping into account." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      border-radius: 50%;
+      height: 50px;
+      width: 50px;
+    }
+
+  div#red-container-circle
+    {
+      background-color: red;
+      contain: paint;
+      padding: 25px;
+    }
+
+  img
+    {
+      vertical-align: bottom;
+    }
+
+  div#green-overlapping-reference
+    {
+      background-color: green;
+      bottom: 100px;
+      height: 100px;
+      position: relative;
+      width: 100px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+  <div id="red-container-circle"><img src="support/swatch-red.png" width="175" height="100" alt="Image download support must be enabled"></div>
+
+  <div id="green-overlapping-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-016.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-016.html
new file mode 100644
index 0000000..8203eea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-016.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping descendants at padding edge</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+  <!--
+  This test fails in Chromium 66.0.3359.117
+  -->
+
+  <meta content="This test checks that the paint of the descendant (a red square image) and its geometry is clipped to the padding edge of the element's principal box, taking corner clipping into account." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta name="flags" content="">
+
+  <style>
+  div#red-container-circle
+    {
+      background-color: red;
+      border-radius: 50%;
+      contain: paint;
+      height: 50px;
+      padding: 25px 0px;
+      width: 100px;
+    }
+
+  img
+    {
+      vertical-align: bottom;
+    }
+
+  div#green-overlapping-reference
+    {
+      background-color: green;
+      border-radius: 50%;
+      bottom: 100px;
+      height: 100px;
+      position: relative;
+      width: 100px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+  <div id="red-container-circle"><img src="support/swatch-red.png" width="100" height="175" alt="Image download support must be enabled"></div>
+
+  <div id="green-overlapping-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-017.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-017.html
new file mode 100644
index 0000000..d8213a5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-017.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping at padding edge (generated ::before content)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+
+  <meta content="This test checks that the paint containment of an element clips at its padding edge. In this test, the generated element (a red square image) is located outside the content edge, into what would have been the padding belt of the element." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta content="" name="flags">
+
+  <style>
+  div
+    {
+      background-color: green;
+      border-radius: 100px;
+      contain: paint;
+      height: 50px;
+      padding: 25px;
+      width: 50px;
+    }
+
+  div::before
+    {
+      background-color: red;
+      content: "";
+      display: block;
+      height: 18px;
+      margin-left: 61px;
+      margin-top: -28px;
+      width: 18px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-018.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-018.html
new file mode 100644
index 0000000..17bcccd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-clip-018.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and clipping at padding edge (generated ::after content)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-clip-015-ref.html">
+
+  <meta content="This test checks that the paint containment of an element clips at its padding edge. In this test, the generated element (a red square image) is located outside the content edge, into what would have been the padding belt of the element." name="assert">
+
+  <!--
+
+  contain-paint-clip-011: content overflows horizontally, principal box has no padding
+
+  contain-paint-clip-012: content overflows vertically, principal box has no padding
+
+  contain-paint-clip-013: content overflows horizontally, principal box has horizontal padding
+
+  contain-paint-clip-014: content overflows vertically, principal box has vertical padding
+
+  contain-paint-clip-015: content overflow horizontally, principal box has horizontal padding and corner clipping is involved
+
+  contain-paint-clip-016: content overflow vertically, principal box has vertical padding and corner clipping is involved
+
+  contain-paint-clip-017: principal box has horizontal and vertical padding, generated ::before content is inside top-right corner
+
+  contain-paint-clip-018: principal box has horizontal and vertical padding, generated ::after content is inside top-left corner
+
+  -->
+
+  <meta content="" name="flags">
+
+  <style>
+  div
+    {
+      background-color: green;
+      border-radius: 100px;
+      contain: paint;
+      height: 50px;
+      padding: 25px;
+      width: 50px;
+    }
+
+  div::after
+    {
+      background-color: red;
+      content: "";
+      display: block;
+      height: 18px;
+      margin-left: -29px;
+      margin-top: -28px;
+      width: 18px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-ifc-011.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-ifc-011.html
new file mode 100644
index 0000000..b8a0393
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-ifc-011.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint' and margin collapsing</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-paint">
+  <link rel="match" href="reference/contain-paint-ifc-011-ref.html">
+
+  <meta content="This test checks that a block element with 'contain: paint' establishes a new block formatting context which is independent and separate from others. This causes margin collapsing to be ineffective among vertically-adjacent boxes. In this test, the top margin of parent boxes and top margin of their respective first in-flow child do not collapse. Also, in this test, the bottom margin of the last in-flow child of boxes and bottom margin of their respective parent boxes do not collapse." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      contain: paint;
+      margin: 30px 0px;
+    }
+
+  div#grand-grand-parent-orange
+    {
+      background-color: orange;
+    }
+
+  div#grand-parent-blue
+    {
+      background-color: blue;
+    }
+
+  div#parent-lime
+    {
+      background-color: lime;
+    }
+
+  div#collapse-through-child  /* margin collapsing through element */
+    {
+      contain: none;
+    }
+  </style>
+
+  <p>Test passes if there are 5 horizontal stripes across the page in this order (from top to bottom): an orange stripe, a blue stripe, a bright green stripe, a blue stripe and then an orange stripe.
+
+  <div id="grand-grand-parent-orange">
+
+    <div id="grand-parent-blue">
+
+      <div id="parent-lime">
+
+        <div id="collapse-through-child"></div>
+
+      </div>
+
+    </div>
+
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-001.html
new file mode 100644
index 0000000..930429b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-001.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint size' and table caption</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  table
+    {
+      table-layout: fixed;
+      width: 206px;
+    }
+
+  caption
+    {
+      background-color: red;
+      border: green solid 1em;
+      color: red;
+      contain: paint size;
+      font-size: 20px;
+    }
+  </style>
+
+  <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+  <table>
+
+  <caption>FAIL FAIL FAIL FAIL FAIL FAIL</caption>
+
+    <tr><td>&nbsp;<td>&nbsp;
+
+    <tr><td>&nbsp;<td>&nbsp;
+
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-002.html
new file mode 100644
index 0000000..5af0d54ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-002.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: paint size' and block box</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      background-color: red;
+      border: green solid 1em;
+      color: red;
+      contain: paint size;
+      font-size: 20px;
+      width: 166px;
+    }
+  </style>
+
+  <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+  <div>FAIL FAIL FAIL FAIL FAIL FAIL</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-003.html
new file mode 100644
index 0000000..51459a5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-size-003.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: a block with 'contain: paint size' alongside a float</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-layout-size-003-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      color: transparent;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#floated-left
+    {
+      background-color: blue;
+      float: left;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#with-contain-paint-size
+    {
+      background-color: orange;
+      width: 12em;
+
+      contain: paint size;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <div id="floated-left">Some text in a blue rectangle.</div>
+
+  <div id="with-contain-paint-size">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-021.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-021.html
new file mode 100644
index 0000000..14bd811
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-021.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to inline-block (basic)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-021-ref.html">
+
+  <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has 1 image and no in-flow block descendant." name="assert">
+  <meta name="flags" content="">
+
+  <!--
+
+  contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+  contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+  contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+  contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+  contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+  contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+  contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+  contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+  -->
+
+  <style>
+  div#inline-block-blue-test
+    {
+      background-color: blue;
+      contain: size;
+      display: inline-block;
+      padding: 50px;
+    }
+
+  div#orange-reference
+    {
+      background-color: orange;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+  <div>
+    <div id="inline-block-blue-test"><img src="support/blue50wBy46h.png" alt="Image download support must be enabled"></div>
+  </div>
+
+  <div id="orange-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-023.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-023.html
new file mode 100644
index 0000000..ce795c6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-023.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to inline-block (basic)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-021-ref.html">
+
+  <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has text and no in-flow block descendant." name="assert">
+  <meta name="flags" content="">
+
+  <!--
+
+  contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+  contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+  contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+  contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+  contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+  contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+  contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+  contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+  -->
+
+  <style>
+  div.inline-block
+    {
+      display: inline-block;
+    }
+
+  div#blue-test
+    {
+      background-color: blue;
+      color: transparent;
+      contain: size;
+      font-size: 100px;
+      padding: 50px;
+    }
+
+  div#orange-reference
+    {
+      background-color: orange;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+  <div>
+    <div id="blue-test" class="inline-block">B</div>
+  </div>
+
+  <div>
+    <div id="orange-reference" class="inline-block"></div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-025.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-025.html
new file mode 100644
index 0000000..700a681
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-025.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to inline-block</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-021-ref.html">
+
+  <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has 2 in-flow block descendants made of images." name="assert">
+  <meta name="flags" content="">
+
+  <!--
+
+  contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+  contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+  contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+  contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+  contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+  contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+  contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+  contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+  -->
+
+  <style>
+  div.inline-block
+    {
+      display: inline-block;
+    }
+
+  div#blue-test
+    {
+      background-color: blue;
+      contain: size;
+      padding: 50px;
+    }
+
+  span.block-descendant
+    {
+      display: block;
+    }
+
+  div#orange-reference
+    {
+      background-color: orange;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+  <div>
+    <div id="blue-test" class="inline-block">
+      <span class="block-descendant"><img src="support/blue50wBy23h.png" alt="Image download support must be enabled"></span>
+      <span id="last-line-box" class="block-descendant"><img src="support/blue50wBy23h.png" alt="Image download support must be enabled"></span>
+    </div>
+  </div>
+
+  <div id="orange-reference" class="inline-block"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-027.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-027.html
new file mode 100644
index 0000000..266402c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-027.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to inline-block</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-021-ref.html">
+
+  <meta content="This test checks that when laying out an inline-block element with 'contain: size', the inline-block element must be treated as if it would have no contents. In this test, the inline-block element has 2 in-flow block descendants made of text." name="assert">
+  <meta name="flags" content="">
+
+  <!--
+
+  contain-size-021: inline-block with 1 image and no in-flow block descendant: width comparison
+
+  contain-size-022: inline-block with 1 image and no in-flow block descendant: height comparison
+
+  contain-size-023: inline-block with text and no in-flow block descendant: width comparison
+
+  contain-size-024: inline-block with text and no in-flow block descendant: height comparison
+
+  contain-size-025: inline-block and 2 in-flow block descendants made of images: width comparison
+
+  contain-size-026: inline-block and 2 in-flow block descendants made of images: height comparison
+
+  contain-size-027: inline-block and 2 in-flow block descendants made of text: width comparison
+
+  contain-size-028: inline-block and 2 in-flow block descendants made of text: height comparison
+
+  -->
+
+  <style>
+  div.inline-block
+    {
+      display: inline-block;
+    }
+
+  div#blue-test
+    {
+      background-color: blue;
+      color: transparent;
+      contain: size;
+      font-size: 50px;
+      line-height: 1;
+      padding: 50px;
+    }
+
+  span.block-descendant
+    {
+      display: block;
+    }
+
+  div#orange-reference
+    {
+      background-color: orange;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+  <div>
+    <div id="blue-test" class="inline-block">
+      <span class="block-descendant">B</span>
+      <span id="last-line-box" class="block-descendant">L</span>
+    </div>
+  </div>
+
+  <div>
+    <div id="orange-reference" class="inline-block"></div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-041.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-041.html
new file mode 100644
index 0000000..44069a0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-041.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to inline replaced element (basic)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-021-ref.html">
+
+  <meta content="This test checks that when laying out an inline replaced element with 'contain: size', the inline replaced element must be treated as having an intrinsic width and height of 0." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  img#blue-test
+    {
+      background-color: blue;
+      contain: size;
+      padding: 50px;
+    }
+
+  div#orange-reference
+    {
+      background-color: orange;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+  <div><img id="blue-test" src="support/blue-100x100.png" alt="Image download support must be enabled"></div>
+
+  <div id="orange-reference"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-042.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-042.html
new file mode 100644
index 0000000..e1d6b3d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-042.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to inline replaced element (basic)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-022-ref.html">
+
+  <meta content="This test checks that when laying out an inline replaced element with 'contain: size', the inline replaced element must be treated as having an intrinsic width and height of 0." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  img#blue-test
+    {
+      background-color: blue;
+      contain: size;
+      padding: 50px;
+    }
+  </style>
+
+  <p>This test passes if the painted blue area is <strong>exactly as tall as</strong> the orange square.
+
+  <div><img id="blue-test" src="support/blue-100x100.png" alt="Image download support must be enabled"> <img id="orange-reference" src="support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-051.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-051.html
new file mode 100644
index 0000000..d529df9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-051.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' does not apply to table-cell element</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-051-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  td
+    {
+      contain: size;
+      font-size: 50px;
+    }
+  </style>
+
+  <p>Test passes if "5678" (without quotes) is readable and if the digits do not overlap each other.
+
+  <table>
+    <tr>
+      <td>5<td>6<td>7<td>8
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-052.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-052.html
new file mode 100644
index 0000000..d32d154
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-052.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' does not apply to table-cell element</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-051-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div#table
+    {
+      border-spacing: 2px;
+      display: table;
+    }
+
+  div#table-row
+    {
+      display: table-row;
+    }
+
+  div.table-cell
+    {
+      contain: size;
+      display: table-cell;
+      font-size: 50px;
+      padding: 1px;
+    }
+  </style>
+
+  <p>Test passes if "5678" (without quotes) is readable and if the digits do not overlap each other.
+
+  <div id="table">
+    <div id="table-row">
+      <div class="table-cell">5</div><div class="table-cell">6</div><div class="table-cell">7</div><div class="table-cell">8</div>
+    </div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-056.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-056.html
new file mode 100644
index 0000000..fa0f98b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-056.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to caption element</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-056-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  table
+    {
+      width: 400px;
+    }
+
+  caption
+    {
+      border: orange solid 3px;
+      color: blue;
+      contain: size;
+      font-size: 32px;
+    }
+  </style>
+
+  <p>Test passes if the words "Table caption" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Table caption" in it.
+
+  <table>
+    <caption>Table caption</caption>
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-061.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-061.html
new file mode 100644
index 0000000..2af24fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-061.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to block box (basic)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-061-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      contain: size;
+      font-size: 100px;
+      overflow: hidden;
+    }
+  </style>
+
+  <p>Test passes if the word FAIL is absent.
+
+  <div>FAIL</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-062.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-062.html
new file mode 100644
index 0000000..60cb194
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-062.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' applies to block box (basic)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-062-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      border: orange solid 3px;
+      color: blue;
+      contain: size;
+      font-size: 32px;
+      width: 400px;
+    }
+  </style>
+
+  <p>Test passes if the words "Text sample" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Text sample" in it.
+
+  <div>Text sample</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-monolithic-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-monolithic-001.html
new file mode 100644
index 0000000..30f19b6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-monolithic-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: size' element is monolithic</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-multicol-1/#column-gaps-and-rules">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+  <link rel="match" href="reference/contain-size-monolithic-001-ref.html">
+
+  <meta content="This test checks that an element with size containment becomes monolithic. In this test, the only way to break the content of such monolithic element is to break (or slice) the content at each pair of characters. Since column rules are only drawn between two columns that both have content and since the test expects only 1 column filled with content, therefore the column rule should not be painted, thus the 'no red' test success condition." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#multi-column
+    {
+      column-count: 2;
+      column-fill: balance; /* balance is the initial column-fill value */
+      column-gap: 4ch;
+      column-rule: red solid 4ch;
+      column-width: 2ch;
+      font-family: monospace;
+      font-size: 20px;
+      width: 8ch;
+    }
+
+  div#size-contain
+    {
+      contain: size;
+    }
+  </style>
+
+  <p>Test passes if "AB", "CD", "EF" and "GH" are vertically aligned into 1 single column and if there is <strong>no red</strong>.
+
+  <div id="multi-column">
+    <div id="size-contain">AB CD EF GH</div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-001.html
new file mode 100644
index 0000000..142730c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-001.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: strict' and table caption</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  table
+    {
+      table-layout: fixed;
+      width: 206px;
+    }
+
+  caption
+    {
+      background-color: red;
+      border: green solid 1em;
+      color: red;
+      contain: strict;
+      font-size: 20px;
+    }
+  </style>
+
+  <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+  <table>
+
+  <caption>FAIL FAIL FAIL FAIL FAIL FAIL</caption>
+
+    <tr><td>&nbsp;<td>&nbsp;
+
+    <tr><td>&nbsp;<td>&nbsp;
+
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-002.html
new file mode 100644
index 0000000..369275e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-002.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: strict' and block box</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-paint-size-001-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      background-color: red;
+      border: green solid 1em;
+      color: red;
+      contain: strict;
+      font-size: 20px;
+      width: 166px;
+    }
+  </style>
+
+  <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+  <div>FAIL FAIL FAIL FAIL FAIL FAIL</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-003.html
new file mode 100644
index 0000000..792710cd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-strict-003.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: a block with 'contain: strict' alongside a float</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#contain-property">
+  <link rel="match" href="reference/contain-layout-size-003-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  div
+    {
+      color: transparent;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#floated-left
+    {
+      background-color: blue;
+      float: left;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#with-contain-strict
+    {
+      background-color: orange;
+      width: 12em;
+
+      contain: strict;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <div id="floated-left">Some text in a blue rectangle.</div>
+
+  <div id="with-contain-strict">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-001.html
new file mode 100644
index 0000000..30a29d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-001.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: style' and counter</title>
+
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+  <link rel="match" href="reference/contain-style-counters-001-ref.html">
+
+  <meta content="This test checks that when an element has 'contain: style', then counters which may be affecting its subtree are reset to 0 for such scope." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#create-counter
+    {
+      counter-reset: counter-of-span 9;
+    }
+
+    /*
+    This creates a new counter identified as "counter-of-span"
+    and initially sets such counter to 9 (an entirely
+    arbitrary number).
+    */
+
+  div#test
+    {
+      contain: style;
+      font-size: 3em;
+    }
+
+  div#test span
+    {
+      counter-increment: counter-of-span 5;
+    }
+
+    /*
+    This increments the counter identified as "counter-of-span"
+    of the step value of 5 (an entirely arbitrary number) each
+    and every time there is a <span> descendant within the subtree
+    of div#test
+    */
+
+  div#test span::after
+    {
+      content: counter(counter-of-span);
+    }
+    /*
+    Now, the generated content after the span is set to the
+    current value of the counter identified as "counter-of-span"
+    */
+
+  </style>
+
+
+  <p>Test passes if there is the digit 5.
+
+  <div id="create-counter"></div>
+
+  <div id="test"><span></span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-002.html
new file mode 100644
index 0000000..eeaac6a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-002.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: style' and counter (with 'display: contents')</title>
+
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+  <link rel="match" href="reference/contain-style-counters-001-ref.html">
+
+  <meta content="This test checks that when an element has 'contain: style', then counters which may be affecting its subtree are reset to 0 for such scope. In this test, the div#test does not generate a principal box because of 'display: contents'. Despite that particular condition, 'contain: style' will have an effect on div#test." name="assert">
+  <meta name="flags" content="">
+
+  <style>
+  div#create-counter
+    {
+      counter-reset: counter-of-span 9;
+    }
+
+    /*
+    This creates a new counter identified as "counter-of-span"
+    and initially sets such counter to 9 (an entirely
+    arbitrary number).
+    */
+
+  div#test
+    {
+      contain: style;
+      display: contents;
+      font-size: 3em;
+    }
+
+    /*
+    Other types of containment (size, layout, paint) have no
+    effect on box that do not generate a principal box which
+    is the case here with div#test because of 'display: contents'.
+    But in this test, 'contain: style' will apply and will
+    have a rendering effect on the counter.
+    */
+
+  div#test span
+    {
+      counter-increment: counter-of-span 5;
+    }
+
+    /*
+    This increments the counter identified as "counter-of-span"
+    of the step value of 5 (an entirely arbitrary number) each
+    and every time there is a <span> descendant within the subtree
+    of div#test
+    */
+
+  div#test span::after
+    {
+      content: counter(counter-of-span);
+    }
+    /*
+    Now, the generated content after the span is set to the
+    current value of the counter identified as "counter-of-span"
+    */
+
+  </style>
+
+
+  <p>Test passes if there is the digit 5.
+
+  <div id="create-counter"></div>
+
+  <div id="test"><span></span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-003.html
new file mode 100644
index 0000000..d99f139
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-003.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: style' for counters (span children of &lt;body&gt;)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+  <link rel="match" href="reference/contain-style-counters-003-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  body
+    {
+      counter-reset: counter-of-span 17;
+    }
+
+    /*
+    This creates a new counter identified as "counter-of-span"
+    and initially sets such counter to 17 (an entirely
+    arbitrary number)
+    */
+
+  body
+    {
+      contain: style;
+    }
+
+    /*
+    This will reset the counter to 0.
+    */
+
+  body span
+    {
+      counter-increment: counter-of-span 4;
+    }
+
+    /*
+    This increments the counter identified as "counter-of-span"
+    of the step value of 4 (an entirely arbitrary number) each
+    and every time there is a <span> descendant within the subtree
+    of div#test
+    */
+
+  div
+    {
+      font-size: 3em;
+    }
+
+  div::after
+    {
+      content: counter(counter-of-span);
+    }
+
+    /*
+    Now, the generated content after the span is set to the
+    current value of the counter identified as "counter-of-span"
+    */
+  </style>
+
+  <body>
+
+  <span></span> <span></span> <span></span> <span></span> <span></span>
+
+  <!-- 5 span above -->
+
+  <p>Test passes if there is the number 20.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-004.html
new file mode 100644
index 0000000..1e751d15
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters-004.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Containment Test: 'contain: style' for counters (span descendants of &lt;body&gt;)</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-style">
+  <link rel="match" href="reference/contain-style-counters-003-ref.html">
+
+  <meta name="flags" content="">
+
+  <style>
+  body
+    {
+      counter-reset: counter-of-span 13;
+    }
+
+    /*
+    This creates a new counter identified as "counter-of-span"
+    and initially sets such counter to 13 (an entirely
+    arbitrary number)
+    */
+
+  body
+    {
+      contain: style;
+    }
+
+    /*
+    This will reset the counter to 0.
+    */
+
+  body span
+    {
+      counter-increment: counter-of-span 5;
+    }
+
+    /*
+    This increments the counter identified as "counter-of-span"
+    of the step value of 5 (an entirely arbitrary number) each
+    and every time there is a <span> descendant within the subtree
+    of div#test
+    */
+
+  div
+    {
+      font-size: 3em;
+    }
+
+  div::after
+    {
+      content: counter(counter-of-span);
+    }
+
+    /*
+    Now, the generated content after the span is set to the
+    current value of the counter identified as "counter-of-span"
+    */
+  </style>
+
+  <body>
+
+  <p> <span></span> <span></span> <span></span> <span></span>
+
+  <!-- 4 span inside the <p> -->
+
+  <p>Test passes if there is the number 20.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html
deleted file mode 100644
index 55bf97f9..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-style-counters.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<title>CSS Containment Test: contain:style for counters</title>
-<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-style">
-<link rel="match" href="contain-style-counters-ref.html">
-<style>
-    #t1 { contain: style }
-    #t1 span::after { content: counter(t1) }
-    .t1-reset { counter-reset: t1 5 }
-    #t1 span { counter-increment: t1 1 }
-
-    #t2 {
-        contain: style;
-        display: contents;
-    }
-    #t2 span::after { content: counter(t2) }
-    .t2-reset { counter-reset: t2 7; }
-    #t2 span { counter-increment: t2 4; }
-</style>
-<div class="t1-reset"></div>
-<div id="t1"><span>You should see the number 1 here: </span></div>
-<div class="t2-reset"></div>
-<div id="t2"><span>You should see the number 4 here: </span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-breaks-002-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-breaks-002-ref.html
index 9ecc3d2..c68bee1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-breaks-002-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-breaks-002-ref.html
@@ -1,25 +1,25 @@
-<!doctype html>
-<html lang=en>
-  <meta charset=utf-8>
-  <title>CSS-contain test reference</title>
-  <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
-  <meta name=flags content="">
+<!DOCTYPE html>
 
-<style>
-article {
-  columns: 2 20px;
-  float: left;
-  height: 50px;
-  column-fill: auto;
-}
-article > div {
-  break-before: column;
-  border-top: 20px solid orange;
-}
-</style>
+  <meta charset="UTF-8">
 
-<p>Test passes if there are two orange boxes below.
-<article>
-    <div></div>
-    <div></div>
-</article>
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      float: left;
+    }
+
+  img
+    {
+      vertical-align: top;
+    }
+  </style>
+
+  <p>Test passes if there is a) a blue square below a yellow square and b) an orange square on the righthand side of the yellow square.
+
+  <div><img src="../support/swatch-yellow.png" width="100" height="100" alt="Image download support must be enabled"><br><img src="../support/swatch-blue.png" width="100" height="100" alt="Image download support must be enabled"></div>
+
+  <div><img src="../support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-cell-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-cell-001-ref.html
new file mode 100644
index 0000000..093dd363
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-cell-001-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  table
+    {
+      background-color: blue;
+      border-spacing: 2px;
+      height: 206px;
+      table-layout: fixed;
+      width: 206px;
+    }
+
+  td
+    {
+      background-color: white;
+      padding: 0px;
+      vertical-align: baseline;
+    }
+
+  span
+    {
+      background-color: green;
+      color: white;
+      font-family: monospace;
+    }
+  </style>
+
+  <p>Test passes if there is the word PASS and if there is <strong>no red</strong>.
+
+  <table>
+
+    <tr><td>&nbsp;<td>&nbsp;
+
+    <tr><td>&nbsp;<td><span>PASS</span>
+
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ifc-022-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ifc-022-ref.html
new file mode 100644
index 0000000..682af7d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ifc-022-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      color: transparent;
+      float: left;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#blue-rectangle
+    {
+      background-color: blue;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#orange-rectangle
+    {
+      background-color: orange;
+      width: 12em;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <div id="blue-rectangle">Some text in a blue rectangle.</div>
+
+  <div id="orange-rectangle">Some text in an orange rectangle. Some text in an orange rectangle. Some text in an orange rectangle.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html
new file mode 100644
index 0000000..a2b75db
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      font-family: monospace;
+      font-size: 100px;
+      height: 2.8ch;
+      overflow: scroll;
+      width: 4ch;
+    }
+  </style>
+
+ <body>
+
+  <p>Test passes if there is no red.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html
new file mode 100644
index 0000000..8dbbbbd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-015-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <body>
+
+  <p>Test passes if there is no red.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html
new file mode 100644
index 0000000..7ec1d1bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-019-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div#parent
+    {
+      height: 100px;
+      width: 100px;
+      overflow: scroll;
+    }
+
+  div#child
+    {
+      background-color: green;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <body onload="document.getElementById('parent').scrollLeft = 100; document.getElementById('parent').scrollTop = 125;">
+
+  <p>Test passes if there is a filled green square <strong>with 2 scroll bars</strong> and if there is <strong>no red</strong>.
+
+  <div id="parent">
+    <div id="child"></div>
+  </div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html
new file mode 100644
index 0000000..57a4e9c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-020-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      background-color: green;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green square, <strong>no scrollbar around it</strong> and <strong>no red</strong>.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-size-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-size-003-ref.html
new file mode 100644
index 0000000..e3932a9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-layout-size-003-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      color: transparent;
+      float: left;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#blue-rectangle
+    {
+      background-color: blue;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#orange-rectangle
+    {
+      background-color: orange;
+      height: 0px;
+      width: 12em;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <div id="blue-rectangle">Some text in a blue rectangle.</div>
+
+  <div id="orange-rectangle">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-022-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-022-ref.html
new file mode 100644
index 0000000..b3bb7576
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-022-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      background-color: green;
+      height: 100px;
+      left: 100px;
+      position: relative;
+      top: 100px;
+      width: 100px;
+    }
+
+  </style>
+
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-047-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-047-ref.html
new file mode 100644
index 0000000..f1364997
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-047-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      color: green;
+      font-family: monospace;
+      font-size: 100px;
+  }
+  </style>
+
+  <p>Test passes if there is <strong>no red</strong>.
+
+  <div>PASS</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-clip-015-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-clip-015-ref.html
new file mode 100644
index 0000000..781a6d2f2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-clip-015-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      background-color: green;
+      border-radius: 50%;
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <p>Test passes if there is a filled green circle and <strong>no red</strong>.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-ifc-011-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-ifc-011-ref.html
new file mode 100644
index 0000000..229c8c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-ifc-011-ref.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  p
+    {
+      margin-bottom: 30px;
+    }
+
+  div
+    {
+      height: 30px;
+    }
+
+  div.orange
+    {
+      background-color: orange;
+    }
+
+  div.blue
+    {
+      background-color: blue;
+    }
+
+  div#lime
+    {
+      background-color: lime;
+    }
+  </style>
+
+  <p>Test passes if there are 5 horizontal stripes across the page in this order (from top to bottom): an orange stripe, a blue stripe, a bright green stripe, a blue stripe and then an orange stripe.
+
+  <div class="orange"></div>
+
+  <div class="blue"></div>
+
+  <div id="lime"></div>
+
+  <div class="blue"></div>
+
+  <div class="orange"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-size-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-size-001-ref.html
new file mode 100644
index 0000000..9aad8a49
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-size-001-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      background-color: green;
+      height: 40px;
+      width: 206px;
+    }
+  </style>
+
+  <p>Test passes if there is a short horizontal green stripe and <strong>no red</strong>.
+
+  <div></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-size-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-size-003-ref.html
new file mode 100644
index 0000000..27820fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-paint-size-003-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      color: transparent;
+      float: left;
+      font-size: 16px;
+      padding: 8px;
+    }
+
+  div#blue-rectangle
+    {
+      background-color: blue;
+      margin: 8px;
+      width: 6em;
+    }
+
+  div#orange-rectangle
+    {
+      background-color: orange;
+      height: 0px;
+      overflow: hidden;
+      width: 12em;
+    }
+  </style>
+
+  <p>Test passes if the orange rectangle and blue rectangle do not overlap.
+
+  <div id="blue-rectangle">Some text in a blue rectangle.</div>
+
+  <div id="orange-rectangle">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore.</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-021-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-021-ref.html
new file mode 100644
index 0000000..de9cea1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-021-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <p>This test passes if the painted blue area is <strong>exactly as wide as</strong> the orange square.
+
+  <div><img src="../support/swatch-blue.png" width="100" height="100" alt="Image download support must be enabled"></div>
+
+  <div><img src="../support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-022-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-022-ref.html
new file mode 100644
index 0000000..3ca9ac9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-022-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <p>This test passes if the painted blue area is <strong>exactly as tall as</strong> the orange square.
+
+  <div><img src="../support/swatch-blue.png" width="100" height="100" alt="Image download support must be enabled"> <img src="../support/swatch-orange.png" width="100" height="100" alt="Image download support must be enabled"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-051-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-051-ref.html
new file mode 100644
index 0000000..07455aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-051-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  td
+    {
+      font-size: 50px;
+    }
+  </style>
+
+  <p>Test passes if "5678" (without quotes) is readable and if the digits do not overlap each other.
+
+  <table>
+    <tr>
+      <td>5<td>6<td>7<td>8
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-056-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-056-ref.html
new file mode 100644
index 0000000..2e73f0e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-056-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  table
+    {
+      width: 400px;
+    }
+
+  caption
+    {
+      border-top: orange solid 6px;
+      color: blue;
+      font-size: 32px;
+    }
+
+  span
+    {
+      bottom: 3px;
+      position: relative;
+    }
+  </style>
+
+  <p>Test passes if the words "Table caption" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Table caption" in it.
+
+  <table>
+    <caption><span>Table caption</span></caption>
+  </table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-061-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-061-ref.html
new file mode 100644
index 0000000..756c20d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-061-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <p>Test passes if the word FAIL is absent.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-062-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-062-ref.html
new file mode 100644
index 0000000..dbfa77f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-062-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      border: orange solid 3px;
+      color: blue;
+      font-size: 32px;
+      height: 0px;
+      width: 400px;
+    }
+  </style>
+
+  <p>Test passes if the words "Text sample" are below a thick orange line. Test fails if, instead of a thick orange line, there is an orange rectangle with the words "Text sample" in it.
+
+  <div>Text sample</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-monolithic-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-monolithic-001-ref.html
new file mode 100644
index 0000000..2e8f1ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-monolithic-001-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      font-family: monospace;
+      font-size: 20px;
+      width: 8ch;
+    }
+  </style>
+
+  <p>Test passes if "AB", "CD", "EF" and "GH" are vertically aligned into 1 single column and if there is <strong>no red</strong>.
+
+
+  <div>AB<br>CD<br>EF<br>GH</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-style-counters-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-style-counters-001-ref.html
new file mode 100644
index 0000000..c0c652b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-style-counters-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      font-size: 3em;
+    }
+  </style>
+
+  <p>Test passes if there is the digit 5.
+
+  <div>5</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-style-counters-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-style-counters-003-ref.html
new file mode 100644
index 0000000..8eb67b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-style-counters-003-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reference Test</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      font-size: 3em;
+    }
+  </style>
+
+  <p>Test passes if there is the digit 20.
+
+  <div>20</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/ref-if-there-is-no-red.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/ref-if-there-is-no-red.xht
new file mode 100644
index 0000000..a5b4e9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/ref-if-there-is-no-red.xht
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+ <head>
+
+  <title>CSS Reftest Reference</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+
+ </head>
+
+ <body>
+
+  <p>Test passes if there is <strong>no red</strong>.</p>
+
+ </body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue-100x100.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue-100x100.png
new file mode 100644
index 0000000..3b72d5c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue-100x100.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue50wBy23h.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue50wBy23h.png
new file mode 100644
index 0000000..d20129c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue50wBy23h.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue50wBy46h.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue50wBy46h.png
new file mode 100644
index 0000000..303d0404
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/blue50wBy46h.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/pattern-gg-gr-100x100.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/pattern-gg-gr-100x100.png
new file mode 100644
index 0000000..fd9b7e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/pattern-gg-gr-100x100.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-blue.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-blue.png
new file mode 100644
index 0000000..bf27596
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-blue.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-orange.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-orange.png
new file mode 100644
index 0000000..d3cd498b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-orange.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-red.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-red.png
new file mode 100644
index 0000000..1caf25c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-red.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-yellow.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-yellow.png
new file mode 100644
index 0000000..1591aa0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/swatch-yellow.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/first-letter-and-sibling-display-change.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/first-letter-and-sibling-display-change.html
new file mode 100644
index 0000000..29bdc5bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-pseudo/first-letter-and-sibling-display-change.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>CSS Test: Changing ::first-letter color while sibling changes display type.</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="match" href="first-letter-block-to-inline-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#first-letter-pseudo">
+<style>
+  div { color: green }
+  div::first-letter { color: red }
+  .green::first-letter { color: green }
+</style>
+<div>This text should be green.<span></span></div>
+<script>
+  document.body.offsetTop;
+  document.querySelector("span").style.display = "block";
+  document.querySelector("div").className = "green";
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/pattern-gg-gr-100x100.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/pattern-gg-gr-100x100.png
index b14c75ea..fd9b7e1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/pattern-gg-gr-100x100.png
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/pattern-gg-gr-100x100.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/inert/inert-does-not-match-disabled-selector.html b/third_party/WebKit/LayoutTests/external/wpt/dom/inert/inert-does-not-match-disabled-selector.html
new file mode 100644
index 0000000..74b8ac3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/inert/inert-does-not-match-disabled-selector.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+button {
+    color: green;
+}
+
+button:disabled {
+    color: red;
+}
+
+</style>
+</head>
+<body style="color: green">
+<button inert>The test passes if this is in green.</button>
+<script>
+test(function() {
+    button = document.querySelector('button');
+    color = document.defaultView.getComputedStyle(button).getPropertyValue('color');
+    assert_false(button.matches(':disabled'));
+}, 'Tests that inert elements do not match the :disabled selector.');
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-does-not-match-disabled-selector.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-does-not-match-disabled-selector.html
new file mode 100644
index 0000000..defc7cd6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-does-not-match-disabled-selector.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>inert does not match :disabled selector</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <style>
+      button {
+        color: green;
+      }
+
+      button:disabled {
+        color: red;
+      }
+    </style>
+  </head>
+  <body>
+    <button inert>The test passes if this is in green.</button>
+    <script>
+      test(function() {
+        button = document.querySelector('button');
+        var color = document.defaultView.getComputedStyle(button).getPropertyValue('color');
+        assert_equals(color, 'rgb(0, 128, 0)');
+      }, 'Tests that inert elements do not match the :disabled selector.');
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-in-shadow-dom.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-in-shadow-dom.html
new file mode 100644
index 0000000..36c962b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-in-shadow-dom.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <title>inert inside ShadowRoot affects slotted content</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+  <div>Button 1 should be inert, and Button 2 should not be inert.</div>
+  <div id="shadow-host">
+    <button slot="slot-1" id="button-1">Button 1 (inert)</button>
+    <button slot="slot-2" id="button-2">Button 2 (not inert)</button>
+  </div>
+  <script>
+    const shadowHost = document.getElementById("shadow-host");
+    const shadowRoot = shadowHost.attachShadow({ mode: "open" });
+    const inertDiv = document.createElement("div");
+    inertDiv.inert = true;
+    shadowRoot.appendChild(inertDiv);
+    const slot1 = document.createElement("slot");
+    slot1.name = "slot-1";
+    inertDiv.appendChild(slot1);
+    const slot2 = document.createElement("slot");
+    slot2.name = "slot-2";
+    shadowRoot.appendChild(slot2);
+
+    function testCanFocus(selector, canFocus) {
+      const element = document.querySelector(selector);
+      let focusedElement = null;
+      element.addEventListener("focus", function() { focusedElement = element; }, false);
+      element.focus();
+      assert_equals((focusedElement === element), canFocus);
+    }
+
+    test(() => {
+      testCanFocus("#button-1", false);
+      testCanFocus("#button-2", true);
+    }, "inert inside ShadowRoot affects slotted content");
+  </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-inlines.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-inlines.html
new file mode 100644
index 0000000..b056c64
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-inlines.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>inert inlines</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/resources/testdriver.js"></script>
+    <script src="/resources/testdriver-vendor.js"></script>
+  </head>
+<body>
+<a inert id="a" href="javascript:void(0)">Click me</a>
+<button inert id="button">Click me</button>
+<div inert id="div" style="background-color: blue; width: 50px; height: 50px">Click me</div>
+<span inert id="span">Click me</span>
+<script>
+function eventFiredOnInertElement(e) {
+    e.target.style.background = 'red';
+    inertElementFiredOn = true;
+}
+
+inertElements = ['a', 'button', 'div', 'span']
+inertElements.forEach(function(id) {
+    element = document.getElementById(id);
+    element.addEventListener('click', eventFiredOnInertElement);
+    element.addEventListener('mousemove', eventFiredOnInertElement);
+});
+
+document.addEventListener('click', function(e) {
+    document.firedOn = true;
+});
+
+promise_test(async () => {
+    for (let id of inertElements) {
+        var element = document.getElementById(id);
+        inertElementFiredOn = false;
+        document.firedOn = false;
+        try {
+          await test_driver.click(element);
+          assert_false(inertElementFiredOn, 'no event should be fired on ' + id);
+          assert_true(document.firedOn, 'event should be fired on document instead of ' + id);
+        } catch (e) {
+          // test driver detects inert elements as unclickable
+          // and throws an error
+          assert_false(inertElementFiredOn, 'no event should be fired on ' + id);
+        }
+    }
+}, 'Tests that inert inlines do not receive mouse events. ' +
+   'To test manually, click on all the "Click me"s. The test ' +
+   'fails if you see red.');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-label-focus.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-label-focus.html
new file mode 100644
index 0000000..8bbe1eca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-label-focus.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>inert with label/for</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/resources/testdriver.js"></script>
+    <script src="/resources/testdriver-vendor.js"></script>
+  </head>
+  <body>
+    <label inert id="for-submit" for="submit">Label for Submit</label>
+    <input id="text" type="text">
+    <input id="submit" type="submit">
+
+    <label id="for-input-in-inert-subtree"
+           for="input-in-inert-subtree">Label for input in inert subtree</label>
+    <div inert>
+      <input id="input-in-inert-subtree"></input>
+    </div>
+
+    <script>
+      test(() => {
+        label = document.querySelector('#for-submit');
+        label.focus();
+        assert_equals(document.activeElement, document.querySelector('#submit'));
+      }, 'Calling focus() on an inert label should still send focus to its target.');
+
+      promise_test(async () => {
+        text = document.querySelector('#text');
+        text.focus();
+        label = document.querySelector('#for-submit');
+        try {
+          await test_driver.click(label);
+          assert_equals(document.activeElement, document.body);
+        } catch (e) {
+          // test driver detects inert elements as unclickable
+          // and throws an error
+        }
+      }, 'Clicking on an inert label should send focus to document.body.');
+
+      test(() => {
+        text = document.querySelector('#text');
+        text.focus();
+
+        label = document.querySelector('#for-input-in-inert-subtree');
+        label.focus();
+        assert_equals(document.activeElement, text);
+      }, 'Calling focus() on a label for a control which is in an inert subtree ' +
+         'should have no effect.');
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-uneditable.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-uneditable.html
new file mode 100644
index 0000000..b18d991
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-uneditable.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>inert nodes are uneditable</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+<body>
+<span inert id="not-editable" contenteditable>I'm not editable.</span>
+<span id="editable" contenteditable>I'm editable.</span>
+<script>
+var notEditable = document.querySelector('#not-editable');
+var editable = document.querySelector('#editable');
+
+promise_test(async () => {
+    notEditable.focus();
+    var oldValue = notEditable.textContent;
+    assert_equals(oldValue, "I'm not editable.");
+    try {
+      test_driver.keyDown('a');
+      assert_equals(notEditable.textContent, oldValue);
+    } catch (e) {
+      // TODO(crbug.com/828858): Remove this check once bug is resolved.
+      assert_true(false, "send_keys not implemented yet");
+    }
+}, "Can't edit inert contenteditable");
+
+test(() => {
+    editable.focus();
+    var oldValue = editable.textContent;
+    assert_equals(oldValue, "I'm editable.");
+    try {
+      test_driver.keyDown('a');
+      assert_not_equals(editable.textContent, oldValue);
+    } catch (e) {
+      // TODO(crbug.com/828858): Remove this check once bug is resolved.
+      assert_true(false, "send_keys not implemented yet");
+    }
+}, "Can edit non-inert contenteditable");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-unfocusable.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-unfocusable.html
new file mode 100644
index 0000000..8b5de37f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-unfocusable.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>inert nodes are unfocusable</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+<body id="body" tabindex="1">
+  <button id="focusable">Outside of inert container</button>
+  <button inert id="inert">Inert button</button>
+  <div inert id="container">
+    <input id="text" type="text">
+    <input id="datetime" type="datetime">
+    <input id="color" type="color">
+    <select id="select">
+        <optgroup id="optgroup">
+            <option id="option">Option</option>
+        </optgroup>
+    </select>
+    <div id="contenteditable-div" contenteditable>I'm editable</div>
+    <span id="tabindex-span" tabindex="0">I'm tabindexed.</div>
+    <embed id="embed" type="application/x-blink-test-plugin" width=100 height=100></embed>
+    <a id="anchor" href="">Link</a>
+  </div>
+<script>
+function testFocus(element, expectFocus) {
+    focusedElement = null;
+    element.addEventListener('focus', function() { focusedElement = element; }, false);
+    element.focus();
+    theElement = element;
+    assert_equals(focusedElement === theElement, expectFocus);
+}
+
+function testTree(element, expectFocus, excludeCurrent) {
+    if (element.nodeType == Node.ELEMENT_NODE && !excludeCurrent)
+        testFocus(element, expectFocus);
+    if (element.tagName === "SELECT")
+        return;
+    var childNodes = element.childNodes;
+    for (var i = 0; i < childNodes.length; i++)
+        testTree(childNodes[i], expectFocus);
+}
+
+
+test(function() {
+    testFocus(document.getElementById('focusable'), true);
+}, "Button outside of inert container is focusable.");
+
+test(function() {
+    testFocus(document.getElementById('inert'), false);
+}, "Button with inert atribute is unfocusable.");
+
+test(function() {
+    testTree(document.getElementById('container'), false);
+}, "All focusable elements inside inert subtree are unfocusable");
+
+test(function() {
+    assert_false(document.getElementById("focusable").inert, "Inert not set explicitly is false")
+    assert_true(document.getElementById("inert").inert, "Inert set explicitly is true");
+    assert_true(document.getElementById("container").inert, "Inert set on container is true");
+}, "Can get inert via property");
+
+test(function() {
+    assert_false(document.getElementById("text").inert, "Elements inside of inert subtrees return false when getting inert");
+}, "Elements inside of inert subtrees return false when getting 'inert'");
+
+test(function() {
+    document.getElementById('focusable').inert = true;
+    testFocus(document.getElementById('focusable'), false);
+    document.getElementById('inert').inert = false;
+    testFocus(document.getElementById('inert'), true);
+    document.getElementById('container').inert = false;
+    testTree(document.getElementById('container'), true, true);
+}, "Setting inert via property correctly modifies inert state");
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-unselectable.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-unselectable.html
new file mode 100644
index 0000000..7d5e908
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/inert/inert-node-is-unselectable.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>inert nodes are unselectable</title>
+    <link rel="author" title="Alice Boxhall" href="aboxhall@chromium.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+<body>
+  <div inert>Here is a text node you can't select.</div>
+  <div>I'm selectable.</div>
+<script>
+test(function() {
+    document.execCommand('SelectAll');
+    assert_equals(window.getSelection().toString(), "I'm selectable.");
+}, "Inert nodes cannot be selected.");
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event-expected.txt
deleted file mode 100644
index 907dafe..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL error event is normal (return true does not cancel; one arg) on Window, with a synthetic Event assert_equals: expected false but got true
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/FileAPI.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/FileAPI.idl
index 690d777..42e51d0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/FileAPI.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/FileAPI.idl
@@ -51,7 +51,7 @@
   // async read methods
   void readAsArrayBuffer(Blob blob);
   void readAsBinaryString(Blob blob);
-  void readAsText(Blob blob, optional DOMString label);
+  void readAsText(Blob blob, optional DOMString encoding);
   void readAsDataURL(Blob blob);
 
   void abort();
@@ -84,7 +84,7 @@
 
   ArrayBuffer readAsArrayBuffer(Blob blob);
   DOMString readAsBinaryString(Blob blob);
-  DOMString readAsText(Blob blob, optional DOMString label);
+  DOMString readAsText(Blob blob, optional DOMString encoding);
   DOMString readAsDataURL(Blob blob);
 };
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/README.md b/third_party/WebKit/LayoutTests/external/wpt/interfaces/README.md
new file mode 100644
index 0000000..024cd088
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/README.md
@@ -0,0 +1,5 @@
+This directory contains [Web IDL](https://heycam.github.io/webidl/) interface definitions for use in idlharness.js tests.
+
+The `.idl` files are extracted from specs by [Reffy](https://github.com/tidoust/reffy) into [reffy-reports](https://github.com/tidoust/reffy-reports), and then copied into this directory.
+
+Automatically importing changes from reffy-reports is tracked by the [Auto-import IDL files](https://github.com/web-platform-tests/wpt/projects/1) project. Currently, it is only semi-automated, and not guaranteed to happen at any particular cadence. If you need to update an IDL file, please copy the file from [whatwg/idl/](https://github.com/tidoust/reffy-reports/tree/master/whatwg/idl) in reffy-reports.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/animation-worklet.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/animation-worklet.idl
index 762c443..e0f5fc2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/animation-worklet.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/animation-worklet.idl
@@ -22,7 +22,6 @@
         readonly attribute DOMString animatorName;
 };
 
-
 interface WorkletGroupEffectReadOnly :  GroupEffectReadOnly {};
 
 interface WorkletGroupEffect :  WorkletGroupEffectReadOnly {};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl
index 1491d642..fca24cd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/battery-status.idl
@@ -6,6 +6,7 @@
 partial interface Navigator {
   Promise<BatteryManager> getBattery();
 };
+
 [Exposed=Window]
 interface BatteryManager : EventTarget {
     readonly        attribute boolean charging;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/keyboard-map.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/keyboard-map.idl
index e2f2c32..3d472361 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/keyboard-map.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/keyboard-map.idl
@@ -1,3 +1,9 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the
+// "Keyboard Map" spec.
+// See: https://wicg.github.io/keyboard-map/
+
+[Exposed=Window]
 partial interface Navigator {
   [SecureContext, SameObject] readonly attribute Keyboard keyboard;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/media-source.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/media-source.idl
index 6476794..5e9663a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/media-source.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/media-source.idl
@@ -8,10 +8,12 @@
     "open",
     "ended"
 };
+
 enum EndOfStreamError {
     "network",
     "decode"
 };
+
 [Constructor]
 interface MediaSource : EventTarget {
     readonly attribute SourceBufferList    sourceBuffers;
@@ -28,10 +30,12 @@
     void         clearLiveSeekableRange();
     static boolean isTypeSupported(DOMString type);
 };
+
 enum AppendMode {
     "segments",
     "sequence"
 };
+
 interface SourceBuffer : EventTarget {
              attribute AppendMode          mode;
     readonly attribute boolean             updating;
@@ -51,22 +55,27 @@
     void abort();
     void remove(double start, unrestricted double end);
 };
+
 interface SourceBufferList : EventTarget {
     readonly attribute unsigned long length;
              attribute EventHandler  onaddsourcebuffer;
              attribute EventHandler  onremovesourcebuffer;
     getter SourceBuffer (unsigned long index);
 };
+
 [Exposed=Window]
 partial interface URL {
     static DOMString createObjectURL(MediaSource mediaSource);
 };
+
 partial interface AudioTrack {
     readonly attribute SourceBuffer? sourceBuffer;
 };
+
 partial interface VideoTrack {
     readonly attribute SourceBuffer? sourceBuffer;
 };
+
 partial interface TextTrack {
     readonly attribute SourceBuffer? sourceBuffer;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/mediacapture-streams.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/mediacapture-streams.idl
index 1d2dd31..1d943ea 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/mediacapture-streams.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/mediacapture-streams.idl
@@ -8,231 +8,263 @@
  Constructor(MediaStream stream),
  Constructor(sequence<MediaStreamTrack> tracks)]
 interface MediaStream : EventTarget {
-    readonly attribute DOMString    id;
+    readonly        attribute DOMString id;
     sequence<MediaStreamTrack> getAudioTracks();
     sequence<MediaStreamTrack> getVideoTracks();
     sequence<MediaStreamTrack> getTracks();
-    MediaStreamTrack?          getTrackById(DOMString trackId);
-    void                       addTrack(MediaStreamTrack track);
-    void                       removeTrack(MediaStreamTrack track);
-    MediaStream                clone();
-    readonly attribute boolean      active;
-             attribute EventHandler onaddtrack;
-             attribute EventHandler onremovetrack;
+    MediaStreamTrack? getTrackById(DOMString trackId);
+    void addTrack(MediaStreamTrack track);
+    void removeTrack(MediaStreamTrack track);
+    MediaStream clone();
+    readonly        attribute boolean active;
+                    attribute EventHandler onaddtrack;
+                    attribute EventHandler onremovetrack;
 };
+
 [Exposed=Window]
 interface MediaStreamTrack : EventTarget {
-    readonly attribute DOMString             kind;
-    readonly attribute DOMString             id;
-    readonly attribute DOMString             label;
-             attribute boolean               enabled;
-    readonly attribute boolean               muted;
-             attribute EventHandler          onmute;
-             attribute EventHandler          onunmute;
-    readonly attribute MediaStreamTrackState readyState;
-             attribute EventHandler          onended;
-    MediaStreamTrack       clone();
-    void                   stop();
+    readonly        attribute DOMString kind;
+    readonly        attribute DOMString id;
+    readonly        attribute DOMString label;
+                    attribute boolean enabled;
+    readonly        attribute boolean muted;
+                    attribute EventHandler onmute;
+                    attribute EventHandler onunmute;
+    readonly        attribute MediaStreamTrackState readyState;
+                    attribute EventHandler onended;
+    MediaStreamTrack clone();
+    void stop();
     MediaTrackCapabilities getCapabilities();
-    MediaTrackConstraints  getConstraints();
-    MediaTrackSettings     getSettings();
-    Promise<void>          applyConstraints(optional MediaTrackConstraints constraints);
-             attribute EventHandler          onoverconstrained;
+    MediaTrackConstraints getConstraints();
+    MediaTrackSettings getSettings();
+    Promise<void> applyConstraints(optional MediaTrackConstraints constraints);
+                    attribute EventHandler onoverconstrained;
 };
+
 enum MediaStreamTrackState {
     "live",
     "ended"
 };
+
 dictionary MediaTrackSupportedConstraints {
-    boolean width = true;
-    boolean height = true;
-    boolean aspectRatio = true;
-    boolean frameRate = true;
-    boolean facingMode = true;
-    boolean resizeMode = true;
-    boolean volume = true;
-    boolean sampleRate = true;
-    boolean sampleSize = true;
-    boolean echoCancellation = true;
-    boolean autoGainControl = true;
-    boolean noiseSuppression = true;
-    boolean latency = true;
-    boolean channelCount = true;
-    boolean deviceId = true;
-    boolean groupId = true;
+             boolean width = true;
+             boolean height = true;
+             boolean aspectRatio = true;
+             boolean frameRate = true;
+             boolean facingMode = true;
+             boolean resizeMode = true;
+             boolean volume = true;
+             boolean sampleRate = true;
+             boolean sampleSize = true;
+             boolean echoCancellation = true;
+             boolean autoGainControl = true;
+             boolean noiseSuppression = true;
+             boolean latency = true;
+             boolean channelCount = true;
+             boolean deviceId = true;
+             boolean groupId = true;
 };
+
 dictionary MediaTrackCapabilities {
-    ULongRange          width;
-    ULongRange          height;
-    DoubleRange         aspectRatio;
-    DoubleRange         frameRate;
-    sequence<DOMString> facingMode;
-    sequence<DOMString> resizeMode;
-    DoubleRange         volume;
-    ULongRange          sampleRate;
-    ULongRange          sampleSize;
-    sequence<boolean>   echoCancellation;
-    sequence<boolean>   autoGainControl;
-    sequence<boolean>   noiseSuppression;
-    DoubleRange         latency;
-    ULongRange          channelCount;
-    DOMString           deviceId;
-    DOMString           groupId;
+             ULongRange width;
+             ULongRange height;
+             DoubleRange aspectRatio;
+             DoubleRange frameRate;
+             sequence<DOMString> facingMode;
+             sequence<DOMString> resizeMode;
+             DoubleRange volume;
+             ULongRange sampleRate;
+             ULongRange sampleSize;
+             sequence<boolean> echoCancellation;
+             sequence<boolean> autoGainControl;
+             sequence<boolean> noiseSuppression;
+             DoubleRange latency;
+             ULongRange channelCount;
+             DOMString deviceId;
+             DOMString groupId;
 };
+
 dictionary MediaTrackConstraints : MediaTrackConstraintSet {
-    sequence<MediaTrackConstraintSet> advanced;
+             sequence<MediaTrackConstraintSet> advanced;
 };
+
 dictionary MediaTrackConstraintSet {
-    ConstrainULong     width;
-    ConstrainULong     height;
-    ConstrainDouble    aspectRatio;
-    ConstrainDouble    frameRate;
-    ConstrainDOMString facingMode;
-    ConstrainDOMString resizeMode;
-    ConstrainDouble    volume;
-    ConstrainULong     sampleRate;
-    ConstrainULong     sampleSize;
-    ConstrainBoolean   echoCancellation;
-    ConstrainBoolean   autoGainControl;
-    ConstrainBoolean   noiseSuppression;
-    ConstrainDouble    latency;
-    ConstrainULong     channelCount;
-    ConstrainDOMString deviceId;
-    ConstrainDOMString groupId;
+             ConstrainULong width;
+             ConstrainULong height;
+             ConstrainDouble aspectRatio;
+             ConstrainDouble frameRate;
+             ConstrainDOMString facingMode;
+             ConstrainDOMString resizeMode;
+             ConstrainDouble volume;
+             ConstrainULong sampleRate;
+             ConstrainULong sampleSize;
+             ConstrainBoolean echoCancellation;
+             ConstrainBoolean autoGainControl;
+             ConstrainBoolean noiseSuppression;
+             ConstrainDouble latency;
+             ConstrainULong channelCount;
+             ConstrainDOMString deviceId;
+             ConstrainDOMString groupId;
 };
+
 dictionary MediaTrackSettings {
-    long      width;
-    long      height;
-    double    aspectRatio;
-    double    frameRate;
-    DOMString facingMode;
-    DOMString resizeMode;
-    double    volume;
-    long      sampleRate;
-    long      sampleSize;
-    boolean   echoCancellation;
-    boolean   autoGainControl;
-    boolean   noiseSuppression;
-    double    latency;
-    long      channelCount;
-    DOMString deviceId;
-    DOMString groupId;
+             long width;
+             long height;
+             double aspectRatio;
+             double frameRate;
+             DOMString facingMode;
+             DOMString resizeMode;
+             double volume;
+             long sampleRate;
+             long sampleSize;
+             boolean echoCancellation;
+             boolean autoGainControl;
+             boolean noiseSuppression;
+             double latency;
+             long channelCount;
+             DOMString deviceId;
+             DOMString groupId;
 };
+
 enum VideoFacingModeEnum {
     "user",
     "environment",
     "left",
     "right"
 };
+
 enum VideoResizeModeEnum {
     "none",
     "crop-and-scale"
 };
+
 [Exposed=Window,
  Constructor(DOMString type, MediaStreamTrackEventInit eventInitDict)]
 interface MediaStreamTrackEvent : Event {
     [SameObject]
-    readonly attribute MediaStreamTrack track;
+    readonly        attribute MediaStreamTrack track;
 };
+
 dictionary MediaStreamTrackEventInit : EventInit {
     required MediaStreamTrack track;
 };
+
 [Exposed=Window,
  Constructor(DOMString type, OverconstrainedErrorEventInit eventInitDict)]
 interface OverconstrainedErrorEvent : Event {
-    readonly attribute OverconstrainedError? error;
+    readonly        attribute OverconstrainedError? error;
 };
+
 dictionary OverconstrainedErrorEventInit : EventInit {
-    OverconstrainedError? error = null;
+             OverconstrainedError? error = null;
 };
+
 partial interface Navigator {
     [SameObject]
-    readonly attribute MediaDevices mediaDevices;
+    readonly        attribute MediaDevices mediaDevices;
 };
+
 [Exposed=Window]
 interface MediaDevices : EventTarget {
-    attribute EventHandler ondevicechange;
+                    attribute EventHandler ondevicechange;
     Promise<sequence<MediaDeviceInfo>> enumerateDevices();
 };
+
 [Exposed=Window]
 interface MediaDeviceInfo {
-    readonly attribute DOMString       deviceId;
-    readonly attribute MediaDeviceKind kind;
-    readonly attribute DOMString       label;
-    readonly attribute DOMString       groupId;
+    readonly        attribute DOMString deviceId;
+    readonly        attribute MediaDeviceKind kind;
+    readonly        attribute DOMString label;
+    readonly        attribute DOMString groupId;
     [Default] object toJSON();
 };
+
 enum MediaDeviceKind {
     "audioinput",
     "audiooutput",
     "videoinput"
 };
-[Exposed=Window]
-interface InputDeviceInfo : MediaDeviceInfo {
+
+[Exposed=Window] interface InputDeviceInfo : MediaDeviceInfo {
     MediaTrackCapabilities getCapabilities();
 };
+
 partial interface Navigator {
-    void getUserMedia(MediaStreamConstraints constraints,
-                      NavigatorUserMediaSuccessCallback successCallback,
-                      NavigatorUserMediaErrorCallback errorCallback);
+    void getUserMedia(MediaStreamConstraints constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback);
 };
+
 partial interface MediaDevices {
     MediaTrackSupportedConstraints getSupportedConstraints();
-    Promise<MediaStream>           getUserMedia(optional MediaStreamConstraints constraints);
+    Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints);
 };
+
 dictionary MediaStreamConstraints {
-    (boolean or MediaTrackConstraints) video = false;
-    (boolean or MediaTrackConstraints) audio = false;
+             (boolean or MediaTrackConstraints) video = false;
+             (boolean or MediaTrackConstraints) audio = false;
 };
+
 callback NavigatorUserMediaSuccessCallback = void (MediaStream stream);
+
 callback NavigatorUserMediaErrorCallback = void (MediaStreamError error);
+
 typedef object MediaStreamError;
+
 [NoInterfaceObject]
 interface ConstrainablePattern {
-    Capabilities  getCapabilities();
-    Constraints   getConstraints();
-    Settings      getSettings();
+    Capabilities getCapabilities();
+    Constraints getConstraints();
+    Settings getSettings();
     Promise<void> applyConstraints(optional Constraints constraints);
-    attribute EventHandler onoverconstrained;
+                    attribute EventHandler onoverconstrained;
 };
+
 dictionary DoubleRange {
-    double max;
-    double min;
+             double max;
+             double min;
 };
+
 dictionary ConstrainDoubleRange : DoubleRange {
-    double exact;
-    double ideal;
+             double exact;
+             double ideal;
 };
+
 dictionary ULongRange {
-    [Clamp]
-    unsigned long max;
-    [Clamp]
-    unsigned long min;
+             [Clamp] unsigned long max;
+             [Clamp] unsigned long min;
 };
+
 dictionary ConstrainULongRange : ULongRange {
-    [Clamp]
-    unsigned long exact;
-    [Clamp]
-    unsigned long ideal;
+             [Clamp] unsigned long exact;
+             [Clamp] unsigned long ideal;
 };
+
 dictionary ConstrainBooleanParameters {
-    boolean exact;
-    boolean ideal;
+             boolean exact;
+             boolean ideal;
 };
+
 dictionary ConstrainDOMStringParameters {
-    (DOMString or sequence<DOMString>) exact;
-    (DOMString or sequence<DOMString>) ideal;
+             (DOMString or sequence<DOMString>) exact;
+             (DOMString or sequence<DOMString>) ideal;
 };
+
 typedef ([Clamp] unsigned long or ConstrainULongRange) ConstrainULong;
+
 typedef (double or ConstrainDoubleRange) ConstrainDouble;
+
 typedef (boolean or ConstrainBooleanParameters) ConstrainBoolean;
+
 typedef (DOMString or sequence<DOMString> or ConstrainDOMStringParameters) ConstrainDOMString;
+
 dictionary Capabilities {
 };
+
 dictionary Settings {
 };
+
 dictionary ConstraintSet {
 };
+
 dictionary Constraints : ConstraintSet {
-    sequence<ConstraintSet> advanced;
+             sequence<ConstraintSet> advanced;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/netinfo.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/netinfo.idl
index 3e6212c..8fd0bba 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/netinfo.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/netinfo.idl
@@ -39,4 +39,7 @@
   readonly attribute Millisecond rtt;
   readonly attribute boolean saveData;
   attribute EventHandler onchange;
-};typedef unrestricted double Megabit;typedef unsigned long long Millisecond;
+};
+
+typedef unrestricted double Megabit;
+typedef unsigned long long Millisecond;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl
index 0eda1be..0ff9cdc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl
@@ -7,7 +7,8 @@
   PerformanceEntryList getEntries();
   PerformanceEntryList getEntriesByType(DOMString type);
   PerformanceEntryList getEntriesByName(DOMString name, optional DOMString type);
-};typedef sequence<PerformanceEntry> PerformanceEntryList;
+};
+typedef sequence<PerformanceEntry> PerformanceEntryList;
 
 [Exposed=(Window,Worker)]
 interface PerformanceEntry {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl
new file mode 100644
index 0000000..ae96a3c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/screen-capture.idl
@@ -0,0 +1,27 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the
+// "Screen Capture" spec.
+// See: https://w3c.github.io/mediacapture-screen-share/
+
+partial interface Navigator {
+    Promise<MediaStream> getDisplayMedia(optional MediaStreamConstraints constraints);
+};
+
+partial dictionary MediaTrackConstraintSet {
+             ConstrainDOMString displaySurface;
+             ConstrainBoolean logicalSurface;
+             ConstrainDOMString cursor;
+};
+
+enum DisplayCaptureSurfaceType {
+    "monitor",
+    "window",
+    "application",
+    "browser"
+};
+
+enum CursorCaptureConstraint {
+    "never",
+    "always",
+    "motion"
+};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl
new file mode 100644
index 0000000..5ffa04fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/speech-api.idl
@@ -0,0 +1,174 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the
+// "Web Speech API" spec.
+// See: https://w3c.github.io/speech-api/
+
+[Exposed=Window, Constructor]
+interface SpeechRecognition : EventTarget {
+    // recognition parameters
+    attribute SpeechGrammarList grammars;
+    attribute DOMString lang;
+    attribute boolean continuous;
+    attribute boolean interimResults;
+    attribute unsigned long maxAlternatives;
+    attribute DOMString serviceURI;
+
+    // methods to drive the speech interaction
+    void start();
+    void stop();
+    void abort();
+
+    // event methods
+    attribute EventHandler onaudiostart;
+    attribute EventHandler onsoundstart;
+    attribute EventHandler onspeechstart;
+    attribute EventHandler onspeechend;
+    attribute EventHandler onsoundend;
+    attribute EventHandler onaudioend;
+    attribute EventHandler onresult;
+    attribute EventHandler onnomatch;
+    attribute EventHandler onerror;
+    attribute EventHandler onstart;
+    attribute EventHandler onend;
+};
+
+enum SpeechRecognitionErrorCode {
+    "no-speech",
+    "aborted",
+    "audio-capture",
+    "network",
+    "not-allowed",
+    "service-not-allowed",
+    "bad-grammar",
+    "language-not-supported"
+};
+
+[Exposed=Window]
+interface SpeechRecognitionErrorEvent : Event {
+    readonly attribute SpeechRecognitionErrorCode error;
+    readonly attribute DOMString message;
+};
+
+// Item in N-best list
+[Exposed=Window]
+interface SpeechRecognitionAlternative {
+    readonly attribute DOMString transcript;
+    readonly attribute float confidence;
+};
+
+// A complete one-shot simple response
+[Exposed=Window]
+interface SpeechRecognitionResult {
+    readonly attribute unsigned long length;
+    getter SpeechRecognitionAlternative item(unsigned long index);
+    readonly attribute boolean isFinal;
+};
+
+// A collection of responses (used in continuous mode)
+[Exposed=Window]
+interface SpeechRecognitionResultList {
+    readonly attribute unsigned long length;
+    getter SpeechRecognitionResult item(unsigned long index);
+};
+
+// A full response, which could be interim or final, part of a continuous response or not
+[Exposed=Window]
+interface SpeechRecognitionEvent : Event {
+    readonly attribute unsigned long resultIndex;
+    readonly attribute SpeechRecognitionResultList results;
+    readonly attribute any interpretation;
+    readonly attribute Document? emma;
+};
+
+// The object representing a speech grammar
+[Exposed=Window, Constructor]
+interface SpeechGrammar {
+    attribute DOMString src;
+    attribute float weight;
+};
+
+// The object representing a speech grammar collection
+[Exposed=Window, Constructor]
+interface SpeechGrammarList {
+    readonly attribute unsigned long length;
+    getter SpeechGrammar item(unsigned long index);
+    void addFromURI(DOMString src,
+                    optional float weight);
+    void addFromString(DOMString string,
+                    optional float weight);
+};
+
+[Exposed=Window]
+interface SpeechSynthesis : EventTarget {
+    readonly attribute boolean pending;
+    readonly attribute boolean speaking;
+    readonly attribute boolean paused;
+
+    attribute EventHandler onvoiceschanged;
+
+    void speak(SpeechSynthesisUtterance utterance);
+    void cancel();
+    void pause();
+    void resume();
+    sequence<SpeechSynthesisVoice> getVoices();
+};
+
+partial interface Window {
+    [SameObject] readonly attribute SpeechSynthesis speechSynthesis;
+};
+
+[Exposed=Window,
+  Constructor,
+  Constructor(DOMString text)]
+interface SpeechSynthesisUtterance : EventTarget {
+    attribute DOMString text;
+    attribute DOMString lang;
+    attribute SpeechSynthesisVoice? voice;
+    attribute float volume;
+    attribute float rate;
+    attribute float pitch;
+
+    attribute EventHandler onstart;
+    attribute EventHandler onend;
+    attribute EventHandler onerror;
+    attribute EventHandler onpause;
+    attribute EventHandler onresume;
+    attribute EventHandler onmark;
+    attribute EventHandler onboundary;
+};
+
+[Exposed=Window]
+interface SpeechSynthesisEvent : Event {
+    readonly attribute SpeechSynthesisUtterance utterance;
+    readonly attribute unsigned long charIndex;
+    readonly attribute float elapsedTime;
+    readonly attribute DOMString name;
+};
+
+enum SpeechSynthesisErrorCode {
+    "canceled",
+    "interrupted",
+    "audio-busy",
+    "audio-hardware",
+    "network",
+    "synthesis-unavailable",
+    "synthesis-failed",
+    "language-unavailable",
+    "voice-unavailable",
+    "text-too-long",
+    "invalid-argument",
+};
+
+[Exposed=Window]
+interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent {
+    readonly attribute SpeechSynthesisErrorCode error;
+};
+
+[Exposed=Window]
+interface SpeechSynthesisVoice {
+    readonly attribute DOMString voiceURI;
+    readonly attribute DOMString name;
+    readonly attribute DOMString lang;
+    readonly attribute boolean localService;
+    readonly attribute boolean default;
+};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/webmidi.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/webmidi.idl
index eb7ed6bef..bc5c3b79 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/webmidi.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/webmidi.idl
@@ -4,67 +4,81 @@
 // See: http://webaudio.github.io/web-midi-api/
 
 partial interface Navigator {
-    Promise<MIDIAccess> requestMIDIAccess(optional MIDIOptions options);
+  Promise<MIDIAccess> requestMIDIAccess(optional MIDIOptions options);
 };
+
 dictionary MIDIOptions {
-    boolean sysex;
-    boolean software;
+  boolean sysex;
+  boolean software;
 };
+
 interface MIDIInputMap {
-    readonly maplike<DOMString, MIDIInput>;
+  readonly maplike<DOMString, MIDIInput>;
 };
+
 interface MIDIOutputMap {
-    readonly maplike<DOMString, MIDIOutput>;
+  readonly maplike<DOMString, MIDIOutput>;
 };
+
 interface MIDIAccess : EventTarget {
-    readonly attribute MIDIInputMap  inputs;
-    readonly attribute MIDIOutputMap outputs;
-             attribute EventHandler  onstatechange;
-    readonly attribute boolean       sysexEnabled;
+  readonly attribute MIDIInputMap inputs;
+  readonly attribute MIDIOutputMap outputs;
+  attribute EventHandler onstatechange;
+  readonly attribute boolean sysexEnabled;
 };
+
 interface MIDIPort : EventTarget {
-    readonly attribute DOMString               id;
-    readonly attribute DOMString?              manufacturer;
-    readonly attribute DOMString?              name;
-    readonly attribute MIDIPortType            type;
-    readonly attribute DOMString?              version;
-    readonly attribute MIDIPortDeviceState     state;
-    readonly attribute MIDIPortConnectionState connection;
-             attribute EventHandler            onstatechange;
-    Promise<MIDIPort> open();
-    Promise<MIDIPort> close();
+  readonly attribute DOMString id;
+  readonly attribute DOMString? manufacturer;
+  readonly attribute DOMString? name;
+  readonly attribute MIDIPortType type;
+  readonly attribute DOMString? version;
+  readonly attribute MIDIPortDeviceState state;
+  readonly attribute MIDIPortConnectionState connection;
+  attribute EventHandler onstatechange;
+  Promise<MIDIPort> open();
+  Promise<MIDIPort> close();
 };
+
 interface MIDIInput : MIDIPort {
-    attribute EventHandler onmidimessage;
+  attribute EventHandler onmidimessage;
 };
+
 interface MIDIOutput : MIDIPort {
-    void send(sequence<octet> data, optional DOMHighResTimeStamp timestamp = 0);
-    void clear();
+  void send(sequence<octet> data, optional DOMHighResTimeStamp timestamp = 0);
+  void clear();
 };
+
 enum MIDIPortType {
-    "input",
-    "output",
+  "input",
+  "output",
 };
+
 enum MIDIPortDeviceState {
-    "disconnected",
-    "connected",
+  "disconnected",
+  "connected",
 };
+
 enum MIDIPortConnectionState {
-    "open",
-    "closed",
-    "pending",
+  "open",
+  "closed",
+  "pending",
 };
+
 [Constructor(DOMString type, optional MIDIMessageEventInit eventInitDict)]
 interface MIDIMessageEvent : Event {
-    readonly attribute Uint8Array data;
+  readonly attribute Uint8Array data;
 };
+
 dictionary MIDIMessageEventInit : EventInit {
-    Uint8Array data;
+  Uint8Array data;
 };
+
 [Constructor(DOMString type, optional MIDIConnectionEventInit eventInitDict)]
 interface MIDIConnectionEvent : Event {
-    readonly attribute MIDIPort port;
+  readonly attribute MIDIPort port;
 };
+
 dictionary MIDIConnectionEventInit : EventInit {
-    MIDIPort port;
+  MIDIPort port;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/webrtc.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/webrtc.idl
index 8d949cabb..2849a7d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/webrtc.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/webrtc.idl
@@ -587,7 +587,6 @@
           };
 
 [Exposed=Window] interface RTCStatsReport {
-
     readonly maplike<DOMString, object>;
 };
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/inline-client-rect.html b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/inline-client-rect.html
new file mode 100644
index 0000000..0bdfc8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/intersection-observer/inline-client-rect.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./resources/intersection-observer-test-utils.js"></script>
+
+<style>
+pre, #log {
+  position: absolute;
+  top: 120px;
+  left: 0;
+}
+#scroller {
+  width: 250px;
+  overflow: auto;
+}
+#overflow {
+  width: 1000px;
+}
+.content {
+  width: 100px;
+  height: 20px;
+  padding: 40px 0;
+  text-align: center;
+  background-color: grey;
+  display: inline-block;
+}
+</style>
+
+<div id="scroller">
+  <div id="overflow">
+    <span><div class="content">1</div></span>
+    <span><div class="content">2</div></span>
+    <span><div class="content">3</div></span>
+    <span id="target"><div class="content">4</div></span>
+    <span><div class="content">5</div></span>
+  </div>
+</div>
+
+<script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+
+var entries = [];
+var scroller, target, spaceWidth, targetOffsetLeft, targetOffsetTop;
+
+runTestCycle(function() {
+  scroller = document.getElementById("scroller");
+  assert_true(!!scroller, "scroller exists");
+  target = document.getElementById("target");
+  assert_true(!!target, "target exists");
+  var observer = new IntersectionObserver(function(changes) {
+    entries = entries.concat(changes)
+  });
+  observer.observe(target);
+  entries = entries.concat(observer.takeRecords());
+  assert_equals(entries.length, 0, "No initial notifications.");
+  runTestCycle(step0, "First rAF");
+}, "Inline target");
+
+function step0() {
+  // Measure space width between two adjacent inlines.
+  let nextEl = target.nextElementSibling;
+  spaceWidth = nextEl.offsetLeft - target.offsetLeft - target.offsetWidth;
+  // 8px body margin + 3 preceding siblings @ (100px width + spaceWidth) each
+  targetOffsetLeft = 8 + 300 + (spaceWidth * 3);
+  // 8px body margin + 40px top padding
+  targetOffsetTop = 48;
+  let left = targetOffsetLeft;
+  let right = left + 100;
+  let top = targetOffsetTop;
+  let bottom = top + target.offsetHeight;
+
+  scroller.scrollLeft = 90;
+  runTestCycle(step1, "scroller.scrollLeft = 90");
+
+  checkLastEntry(entries, 0, [left, right, top, bottom,
+                              0, 0, 0, 0, 0, vw, 0, vh, false]);
+}
+
+function step1() {
+  // -90px for scroll offset
+  let left = targetOffsetLeft - 90;
+  let right = left + 100;
+  let top = targetOffsetTop;
+  let bottom = top + target.offsetHeight;
+  // 8px body margin + 250px client width of scroller
+  let scrollerRight = 258;
+  checkLastEntry(entries, 1, [left, right, top, bottom,
+                              left, scrollerRight, top, bottom,
+                              0, vw, 0, vh, true]);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-changetype-util.js b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-changetype-util.js
index f6976d2..4e24223 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-changetype-util.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-changetype-util.js
@@ -19,12 +19,12 @@
             url: 'mp4/test-v-128k-320x240-24fps-8kfr.mp4'
         },
         {
-            type: 'video/webm; codecs="vorbis"',
+            type: 'audio/webm; codecs="vorbis"',
             is_video: false,
             url: 'webm/test-a-128k-44100Hz-1ch.webm'
         },
         {
-            type: 'video/mp4; codecs="mp4a.40.2"',
+            type: 'audio/mp4; codecs="mp4a.40.2"',
             is_video: false,
             url: 'mp4/test-a-128k-44100Hz-1ch.mp4'
         },
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-util.js b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-util.js
index 15a56e8..bb701e7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-util.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-source/mediasource-util.js
@@ -222,7 +222,10 @@
         return null;
     }
 
+    // To support mediasource-changetype tests, do not use any types that
+    // indicate automatic timestamp generation in this audioOnlyTypes list.
     var audioOnlyTypes = ['audio/mp4;codecs="mp4a.40.2"', 'audio/webm;codecs="vorbis"'];
+
     var videoOnlyTypes = ['video/mp4;codecs="avc1.4D4001"', 'video/webm;codecs="vp8"'];
     var audioVideoTypes = ['video/mp4;codecs="avc1.4D4001,mp4a.40.2"', 'video/webm;codecs="vp8,vorbis"'];
     MediaSourceUtil.AUDIO_ONLY_TYPE = getFirstSupportedType(audioOnlyTypes);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/priority-hints/META.yml b/third_party/WebKit/LayoutTests/external/wpt/priority-hints/META.yml
index 22a350d7..487b401 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/priority-hints/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/priority-hints/META.yml
@@ -1,3 +1,5 @@
 spec: https://wicg.github.io/priority-hints/
 suggested_reviewers:
+  - addyosmani
   - domfarolino
+  - yoavweiss
diff --git a/third_party/WebKit/LayoutTests/external/wpt/priority-hints/img-attr-named-constructor.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/priority-hints/img-attr-named-constructor.tentative.html
index d9dd22a9..ce677cc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/priority-hints/img-attr-named-constructor.tentative.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/priority-hints/img-attr-named-constructor.tentative.html
@@ -19,6 +19,8 @@
     assert_equals(img5.importance, "auto", "missing importance reflects as 'auto' IDL attribute on the image element");
   }, "importance attribute on <img> elements should reflect valid IDL values");
 
-  const img = new Image();
-  assert_equals(img.importance, "auto");
+  test(() => {
+    const img = new Image();
+    assert_equals(img.importance, "auto");
+  }, "importance of new Image() is 'auto'");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/screen-capture/META.yml b/third_party/WebKit/LayoutTests/external/wpt/screen-capture/META.yml
new file mode 100644
index 0000000..6e5b23c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/screen-capture/META.yml
@@ -0,0 +1,5 @@
+spec: https://w3c.github.io/mediacapture-screen-share/
+suggested_reviewers:
+  - alvestrand
+  - martinthomson
+  - uysalere
diff --git a/third_party/WebKit/LayoutTests/external/wpt/screen-capture/idlharness.window.js b/third_party/WebKit/LayoutTests/external/wpt/screen-capture/idlharness.window.js
new file mode 100644
index 0000000..076e89f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/screen-capture/idlharness.window.js
@@ -0,0 +1,16 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://w3c.github.io/mediacapture-screen-share/
+
+idl_test(
+  ['screen-capture'],
+  ['mediacapture-streams', 'html'],
+  idl_array => {
+    idl_array.add_objects({
+      Navigator: ['navigator'],
+    });
+  }
+);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-abort-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-abort-manual.https.html
new file mode 100644
index 0000000..3c9e1ab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-abort-manual.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SpeechRecognition.abort</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="webspeech.js"></script>
+  </head>
+  <body>
+    <p><b>Instructions:</b> Do NOT speak. Run test in silence.
+      This test may fail if too much noise.</p>
+    <div id="log"></div>
+    <div id="notes"></div>
+    <script>
+var audioTest = new CycleTest('onaudio');
+reco.onaudiostart = audioTest.startEvent();
+reco.onaudioend = audioTest.endEvent();
+
+reco.onsoundstart = neverFireEvent('onsoundstart');
+reco.onsoundend = neverFireEvent('onsoundend');
+reco.onspeechstart = neverFireEvent('onspeechstart');
+reco.onspeechend = neverFireEvent('onsspeechend');
+reco.onresult = neverFireEvent('onresult');
+reco.onnomatch = neverFireEvent('onnomatch');
+
+var errorTest = new CountTest('onerror aborted', 1, 1);
+reco.onerror = errorTest.test().step_func(function(event) {
+  errorTest.count(1);
+  assert_equals(typeof(event.message), 'string', 'typeof(event.message)');
+  notes.innerHTML += 'onerror message is "' + event.message + '"' + '<br>';
+  assert_equals(event.error, 'aborted', 'onerror event.error');
+});
+
+reco.start();
+
+function beginTest() {
+  audioTest.test.step_timeout(function() { reco.abort(); }, DELAY);
+}
+    </script>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-basics.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-basics.https-expected.txt
new file mode 100644
index 0000000..2c7efa3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-basics.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL SpeechRecognition basics SpeechRecognition is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-basics.https.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-basics.https.html
new file mode 100644
index 0000000..dc5d3f5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-basics.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>SpeechRecognition basics</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  const reco = new SpeechRecognition();
+  assert_equals(reco.grammars.length, 0, 'SpeechRecognition.grammars.length');
+  assert_equals(reco.lang, '', 'SpeechRecognition.lang');
+  assert_false(reco.continuous, 'SpeechRecognition.continuous');
+  assert_false(reco.interimResults, 'SpeechRecognition.interimResults');
+  assert_equals(reco.maxAlternatives, 1, 'SpeechRecognition.maxAlternatives');
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-onerror-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-onerror-manual.https.html
new file mode 100644
index 0000000..b0d5d5e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-onerror-manual.https.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SpeechRecognition.onerror no-speech</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script>
+      var TIMEOUT_OVERRIDE = 10000;  // In milliseconds.
+    </script>
+    <script src='webspeech.js'></script>
+  </head>
+  <body>
+    <p><b>Instructions:</b> Do NOT speak. Run test in silence.
+      This test may fail if too much noise.</p>
+    <div id="log"></div>
+    <div id="notes"></div>
+    <script>
+var audioTest = new CycleTest('onaudio');
+reco.onaudiostart = audioTest.startEvent();
+reco.onaudioend = audioTest.endEvent();
+
+reco.onsoundstart = neverFireEvent('onsoundstart');
+reco.onsoundend = neverFireEvent('onsoundend');
+reco.onspeechstart = neverFireEvent('onspeechstart');
+reco.onspeechend = neverFireEvent('onsspeechend');
+reco.onresult = neverFireEvent('onresult');
+reco.onnomatch = neverFireEvent('onnomatch');
+
+var errorTest = new CountTest('onerror no-speech', 1, 1);
+reco.onerror = errorTest.test().step_func(function(event) {
+  errorTest.count(1);
+  assert_equals(typeof(event.message), 'string', 'typeof(event.message)');
+  notes.innerHTML += 'onerror message is "' + event.message + '"' + '<br>';
+  assert_equals(event.error, 'no-speech', 'onerror event.error');
+});
+
+reco.start();
+    </script>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-onresult-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-onresult-manual.https.html
new file mode 100644
index 0000000..6a0877b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-onresult-manual.https.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta name="timeout" content="long">
+    <title>SpeechRecognition.onresult</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script>
+      var TIMEOUT_OVERRIDE = 60000;  // In milliseconds.
+    </script>
+    <script src="webspeech.js"></script>
+  </head>
+  <body>
+    <b>Instructions:</b>
+    <p>Reload and re-run this test at least 4 times to cover all 4 combinations
+      of these checkboxes:
+    <input type="checkbox" id="continuous">continuous
+    <input type="checkbox" id="interim">interimResults
+    <button id="button" onclick="startButton()">Click and Speak</button>
+    <br>
+    You may also wish to test with various combinations of these:
+    maxAlternatives:
+    <input type="text" value="3" size="2" id="maxAlternatives">,
+    language:
+    <input type="text" value="en-us" size="7" id="language">
+    </p>
+    <div id="results"></div>
+    <div id="log"></div>
+    <div id="notes"></div>
+    <script>
+var audioTest = new CycleTest('onaudio');
+reco.onaudiostart = audioTest.startEvent();
+reco.onaudioend = audioTest.endEvent();
+
+var soundTest = new CycleTest('onsound');
+reco.onsoundstart = soundTest.startEvent();
+reco.onsoundend = soundTest.endEvent();
+
+var speechTest = new CycleTest('onspeech');
+reco.onspeechstart = speechTest.startEvent();
+reco.onspeechend = speechTest.endEvent();
+
+reco.onerror = neverFireEvent('onerror');
+reco.onnomatch = neverFireEvent('onnomatch');
+
+var lastIsFinal = -1;  // Highest results index that has been marked isFinal.
+var lastInterimCount = 0;  // Number of results that are not marked isFinal.
+var resultTest = new CountTest('onresult', 1, 9999);
+
+resultTest.whenDone = function() {
+  assert_equals(lastInterimCount, 0, 'Number of interim results pending');
+};
+
+function appendAlternatives(array, results) {
+  for (var i = 0; i < reco.maxAlternatives; i++) {
+    if (i < results.length) {
+      array[i] += results[i].transcript;
+    } else {
+      array[i] += '<no alternative>';
+      assert_true(i > 0, 'Must return at least one alternative.');
+    }
+  }
+}
+
+reco.onresult = resultTest.test().step_func(function(event) {
+  resultTest.count(1);
+  var final = new Array();
+  var interim = new Array();
+  for (var i = 0; i < reco.maxAlternatives; i++) {
+    final[i] = '';
+    interim[i] = '';
+  }
+  assert_true(event.resultIndex > lastIsFinal, 'resultIndex must not ' +
+      'indicate a change in a result that was previously marked isFinal.');
+  assert_true(event.resultIndex <= event.results.length,
+      'resultIndex must not be greater than results.length.');
+  for (var i = 0; i < event.results.length; ++i) {
+    assert_true(event.results[i].length <= reco.maxAlternatives,
+        'Number of alternatives must not exceed maxAlternatives.');
+    if (event.results[i].isFinal) {
+      appendAlternatives(final, event.results[i]);
+      assert_true(reco.continuous || i < 1,
+          'When SpeechRecognition.continuous is false, no more than one ' +
+          'SpeechRecognitionResult.isFinal true should be returned.');
+      if (i > lastIsFinal) {
+        lastIsFinal = i;
+      }
+    } else {
+      appendAlternatives(interim, event.results[i]);
+      assert_true(i > lastIsFinal, 'A SpeechRecognitionResult was previously ' +
+          'marked isFinal, but now is not marked isFinal.');
+    }
+  lastInterimCount = event.results.length - lastIsFinal - 1;
+  assert_true(reco.interimResults || lastInterimCount == 0,
+      'Should not return interim results when reco.interimResults is false.');
+  }
+  for (var i = 0; i < reco.maxAlternatives; i++) {
+    document.getElementById('final_span_' + i).innerHTML = final[i];
+    document.getElementById('interim_span_' + i).innerHTML = interim[i];
+  }
+});
+
+function configureRecognition() {
+  var continuousBox = document.getElementById('continuous');
+  var interimBox = document.getElementById('interim');
+  var maxAlternativesInput = document.getElementById('maxAlternatives');
+  var langInput = document.getElementById('language');
+  reco.continuous = continuousBox.checked;
+  reco.interimResults = interimBox.checked;
+  reco.maxAlternatives = maxAlternativesInput.value;
+  reco.lang = langInput.value;
+  continuousBox.disabled = true;
+  interimBox.disabled = true;
+  maxAlternativesInput.disabled = true;
+  langInput.disabled = true;
+  test(function() {
+    assert_equals(reco.continuous, continuousBox.checked,
+                  'SpeechRecognition.continuous');
+    assert_equals(reco.interimResults, interim.checked,
+                  'SpeechRecognition.interimResults');
+    assert_equals(reco.maxAlternatives, parseInt(maxAlternativesInput.value),
+                  'SpeechRecognition.maxAlternatives');
+    assert_equals(reco.lang, langInput.value,
+                  'SpeechRecognition.lang');
+  }, 'SpeechRecognition settings');
+}
+
+var clicks = 0;
+function startButton() {
+  var button = document.getElementById('button');
+  if (++clicks == 1) {
+    configureRecognition();
+    if (reco.continuous) {
+      button.innerHTML = 'Click when done speaking';
+    } else {
+      button.hidden = true;
+    }
+    var results_html = '';
+    for (var i = 0; i < reco.maxAlternatives; i++) {
+      results_html += '<div style="border:1px dotted gray; padding:10px; ' +
+          'font-weight:bold">' +
+          '<span id="final_span_' + i + '"></span>' +
+          '<span id="interim_span_' + i + '" style="color:blue"></span>' +
+          '</div>';
+    }
+    results.innerHTML = results_html;
+    reco.start();
+  } else {
+    button.hidden = true;
+    reco.stop();
+  }
+}
+    </script>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-stop-manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-stop-manual.https.html
new file mode 100644
index 0000000..e4741b7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechRecognition-stop-manual.https.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SpeechRecognition.stop</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="webspeech.js"></script>
+  </head>
+  <body>
+    <p><b>Instructions:</b> Do NOT speak. Run test in silence.
+      This test may fail if too much noise.</p>
+    <div id="log"></div>
+    <div id="notes"></div>
+    <script>
+var audioTest = new CycleTest('onaudio');
+reco.onaudiostart = audioTest.startEvent();
+reco.onaudioend = audioTest.endEvent();
+
+reco.onsoundstart = neverFireEvent('onsoundstart');
+reco.onsoundend = neverFireEvent('onsoundend');
+reco.onspeechstart = neverFireEvent('onspeechstart');
+reco.onspeechend = neverFireEvent('onsspeechend');
+reco.onresult = neverFireEvent('onresult');
+reco.onerror = neverFireEvent('onerror');
+
+var nomatchTest = new CountTest('onnomatch', 0, 1);
+reco.onnomatch = nomatchTest.test().step_func(function(event) {
+  nomatchTest.count(1);
+});
+
+reco.start();
+
+function beginTest() {
+  setTimeout(function() { reco.stop(); }, DELAY);
+}
+    </script>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisUtterance-basics.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisUtterance-basics.https-expected.txt
new file mode 100644
index 0000000..17b83eb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisUtterance-basics.https-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+PASS new SpeechSynthesisUtterance() default text
+PASS new SpeechSynthesisUtterance() default lang
+PASS new SpeechSynthesisUtterance() default voice
+FAIL new SpeechSynthesisUtterance() default volume assert_equals: volume expected 1 but got -1
+FAIL new SpeechSynthesisUtterance() default rate assert_equals: rate expected 1 but got -1
+FAIL new SpeechSynthesisUtterance() default pitch assert_equals: pitch expected 1 but got -1
+FAIL new SpeechSynthesisUtterance("hello") text and defaults assert_equals: volume expected 1 but got -1
+PASS SpeechSynthesisUtterance text setter
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisUtterance-basics.https.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisUtterance-basics.https.html
new file mode 100644
index 0000000..9a90f086a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/SpeechSynthesisUtterance-basics.https.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>SpeechSynthesisUtterance basics</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const DEFAULTS = {
+  text: '',
+  lang: '',
+  voice: null,
+  volume: 1,
+  rate: 1,
+  pitch: 1,
+};
+
+for (const prop in DEFAULTS) {
+  test(function() {
+    const utt = new SpeechSynthesisUtterance();
+    assert_equals(utt[prop], DEFAULTS[prop], prop);
+  }, `new SpeechSynthesisUtterance() default ${prop}`);
+}
+
+test(function() {
+  const utt = new SpeechSynthesisUtterance("hello");
+  assert_equals(utt.text, 'hello', 'text');
+  // check that the other properties retain their defaults
+  for (const prop in DEFAULTS) {
+    if (prop != 'text') {
+      assert_equals(utt[prop], DEFAULTS[prop], prop);
+    }
+  }
+}, 'new SpeechSynthesisUtterance("hello") text and defaults');
+
+test(function() {
+  const utt = new SpeechSynthesisUtterance();
+  utt.text = 'word';
+  assert_equals(utt.text, 'word');
+}, 'SpeechSynthesisUtterance text setter');
+
+// TODO: setters https://github.com/w3c/speech-api/issues/29
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical-expected.txt
index 42510d6..ebdbc55 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+PASS SpeechRecognitionError interface should not exist
 FAIL webkitSpeechGrammar interface should not exist assert_false: expected false got true
 FAIL webkitSpeechGrammarList interface should not exist assert_false: expected false got true
 FAIL webkitSpeechRecognition interface should not exist assert_false: expected false got true
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical.html b/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical.html
index 4ca574b171..2fb0ccd4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/historical.html
@@ -5,6 +5,7 @@
 <div id="log"></div>
 <script>
 [
+  "SpeechRecognitionError",
   "webkitSpeechGrammar",
   "webkitSpeechGrammarList",
   "webkitSpeechRecognition",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
new file mode 100644
index 0000000..12eedaf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window-expected.txt
@@ -0,0 +1,220 @@
+This is a testharness.js-based test.
+Found 216 tests; 60 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS idl_test setup
+PASS Partial interface Window: original interface defined
+FAIL SpeechRecognition interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface object length assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface object name assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute grammars assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute lang assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute continuous assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute interimResults assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute maxAlternatives assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute serviceURI assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: operation start() assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: operation stop() assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: operation abort() assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onaudiostart assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onsoundstart assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onspeechstart assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onspeechend assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onsoundend assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onaudioend assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onresult assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onnomatch assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onerror assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onstart assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition interface: attribute onend assert_own_property: self does not have own property "SpeechRecognition" expected property "SpeechRecognition" missing
+FAIL SpeechRecognition must be primary interface of new SpeechRecognition() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL Stringification of new SpeechRecognition() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "grammars" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "lang" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "continuous" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "interimResults" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "maxAlternatives" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "serviceURI" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "start()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "stop()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "abort()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onaudiostart" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onsoundstart" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onspeechstart" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onspeechend" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onsoundend" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onaudioend" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onresult" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onnomatch" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onerror" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onstart" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognition interface: new SpeechRecognition() must inherit property "onend" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechRecognition is not defined"
+FAIL SpeechRecognitionErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface object length assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface object name assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface: attribute error assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionErrorEvent interface: attribute message assert_own_property: self does not have own property "SpeechRecognitionErrorEvent" expected property "SpeechRecognitionErrorEvent" missing
+FAIL SpeechRecognitionAlternative interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface object length assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface object name assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface: attribute transcript assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionAlternative interface: attribute confidence assert_own_property: self does not have own property "SpeechRecognitionAlternative" expected property "SpeechRecognitionAlternative" missing
+FAIL SpeechRecognitionResult interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface object length assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface object name assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface: attribute length assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface: operation item(unsigned long) assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResult interface: attribute isFinal assert_own_property: self does not have own property "SpeechRecognitionResult" expected property "SpeechRecognitionResult" missing
+FAIL SpeechRecognitionResultList interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface object length assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface object name assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface: attribute length assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionResultList interface: operation item(unsigned long) assert_own_property: self does not have own property "SpeechRecognitionResultList" expected property "SpeechRecognitionResultList" missing
+FAIL SpeechRecognitionEvent interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface object length assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface object name assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: attribute resultIndex assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: attribute results assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: attribute interpretation assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechRecognitionEvent interface: attribute emma assert_own_property: self does not have own property "SpeechRecognitionEvent" expected property "SpeechRecognitionEvent" missing
+FAIL SpeechGrammar interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface object length assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface object name assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface: attribute src assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar interface: attribute weight assert_own_property: self does not have own property "SpeechGrammar" expected property "SpeechGrammar" missing
+FAIL SpeechGrammar must be primary interface of new SpeechGrammar() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammar is not defined"
+FAIL Stringification of new SpeechGrammar() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammar is not defined"
+FAIL SpeechGrammar interface: new SpeechGrammar() must inherit property "src" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammar is not defined"
+FAIL SpeechGrammar interface: new SpeechGrammar() must inherit property "weight" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammar is not defined"
+FAIL SpeechGrammarList interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface object length assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface object name assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: attribute length assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: operation item(unsigned long) assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: operation addFromURI(DOMString, float) assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList interface: operation addFromString(DOMString, float) assert_own_property: self does not have own property "SpeechGrammarList" expected property "SpeechGrammarList" missing
+FAIL SpeechGrammarList must be primary interface of new SpeechGrammarList() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL Stringification of new SpeechGrammarList() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: new SpeechGrammarList() must inherit property "length" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: new SpeechGrammarList() must inherit property "item(unsigned long)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: calling item(unsigned long) on new SpeechGrammarList() with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: new SpeechGrammarList() must inherit property "addFromURI(DOMString, float)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: calling addFromURI(DOMString, float) on new SpeechGrammarList() with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: new SpeechGrammarList() must inherit property "addFromString(DOMString, float)" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechGrammarList interface: calling addFromString(DOMString, float) on new SpeechGrammarList() with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: SpeechGrammarList is not defined"
+FAIL SpeechSynthesis interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface object length assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface object name assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: attribute pending assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: attribute speaking assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: attribute paused assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: attribute onvoiceschanged assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: operation speak(SpeechSynthesisUtterance) assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: operation cancel() assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: operation pause() assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: operation resume() assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis interface: operation getVoices() assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+FAIL SpeechSynthesis must be primary interface of speechSynthesis assert_own_property: self does not have own property "SpeechSynthesis" expected property "SpeechSynthesis" missing
+PASS Stringification of speechSynthesis
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "pending" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "speaking" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "paused" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "onvoiceschanged" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "speak(SpeechSynthesisUtterance)" with the proper type
+PASS SpeechSynthesis interface: calling speak(SpeechSynthesisUtterance) on speechSynthesis with too few arguments must throw TypeError
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "cancel()" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "pause()" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "resume()" with the proper type
+PASS SpeechSynthesis interface: speechSynthesis must inherit property "getVoices()" with the proper type
+PASS SpeechSynthesisUtterance interface: existence and properties of interface object
+PASS SpeechSynthesisUtterance interface object length
+PASS SpeechSynthesisUtterance interface object name
+PASS SpeechSynthesisUtterance interface: existence and properties of interface prototype object
+PASS SpeechSynthesisUtterance interface: existence and properties of interface prototype object's "constructor" property
+PASS SpeechSynthesisUtterance interface: existence and properties of interface prototype object's @@unscopables property
+PASS SpeechSynthesisUtterance interface: attribute text
+PASS SpeechSynthesisUtterance interface: attribute lang
+PASS SpeechSynthesisUtterance interface: attribute voice
+PASS SpeechSynthesisUtterance interface: attribute volume
+PASS SpeechSynthesisUtterance interface: attribute rate
+PASS SpeechSynthesisUtterance interface: attribute pitch
+PASS SpeechSynthesisUtterance interface: attribute onstart
+PASS SpeechSynthesisUtterance interface: attribute onend
+PASS SpeechSynthesisUtterance interface: attribute onerror
+PASS SpeechSynthesisUtterance interface: attribute onpause
+PASS SpeechSynthesisUtterance interface: attribute onresume
+PASS SpeechSynthesisUtterance interface: attribute onmark
+PASS SpeechSynthesisUtterance interface: attribute onboundary
+PASS SpeechSynthesisUtterance must be primary interface of new SpeechSynthesisUtterance()
+PASS Stringification of new SpeechSynthesisUtterance()
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "text" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "lang" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "voice" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "volume" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "rate" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "pitch" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onstart" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onend" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onerror" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onpause" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onresume" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onmark" with the proper type
+PASS SpeechSynthesisUtterance interface: new SpeechSynthesisUtterance() must inherit property "onboundary" with the proper type
+PASS SpeechSynthesisEvent interface: existence and properties of interface object
+PASS SpeechSynthesisEvent interface object length
+PASS SpeechSynthesisEvent interface object name
+PASS SpeechSynthesisEvent interface: existence and properties of interface prototype object
+PASS SpeechSynthesisEvent interface: existence and properties of interface prototype object's "constructor" property
+PASS SpeechSynthesisEvent interface: existence and properties of interface prototype object's @@unscopables property
+PASS SpeechSynthesisEvent interface: attribute utterance
+PASS SpeechSynthesisEvent interface: attribute charIndex
+PASS SpeechSynthesisEvent interface: attribute elapsedTime
+PASS SpeechSynthesisEvent interface: attribute name
+FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisErrorEvent interface object length assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisErrorEvent interface object name assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisErrorEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisErrorEvent interface: attribute error assert_own_property: self does not have own property "SpeechSynthesisErrorEvent" expected property "SpeechSynthesisErrorEvent" missing
+FAIL SpeechSynthesisVoice interface: existence and properties of interface object assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface object length assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface object name assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: existence and properties of interface prototype object assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: attribute voiceURI assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: attribute name assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: attribute lang assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: attribute localService assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+FAIL SpeechSynthesisVoice interface: attribute default assert_own_property: self does not have own property "SpeechSynthesisVoice" expected property "SpeechSynthesisVoice" missing
+PASS Window interface: attribute speechSynthesis
+PASS Window interface: self must inherit property "speechSynthesis" with the proper type
+PASS WorkerGlobalScope interface: existence and properties of interface object
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window.js b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window.js
new file mode 100644
index 0000000..2f97028
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/idlharness.window.js
@@ -0,0 +1,34 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+idl_test(
+  ['speech-api'],
+  ['dom', 'html'],
+  idl_array => {
+    idl_array.add_objects({
+      SpeechGrammar: ['new SpeechGrammar()'],
+      SpeechGrammarList: ['new SpeechGrammarList()'],
+      SpeechRecognition: ['new SpeechRecognition()'],
+      // TODO: SpeechRecognitionAlternative
+      // TODO: SpeechRecognitionErrorEvent
+      // TODO: SpeechRecognitionEvent
+      // TODO: SpeechRecognitionResult
+      // TODO: SpeechRecognitionResultList
+      SpeechSynthesis: ['speechSynthesis'],
+      // TODO: SpeechSynthesisErrorEvent
+      // TODO: SpeechSynthesisEvent
+      SpeechSynthesisUtterance: ['new SpeechSynthesisUtterance()'],
+      Window: ['self'],
+    });
+
+    // https://w3c.github.io/speech-api/#dom-speechsynthesis-getvoices can
+    // return an empty list, so add SpeechSynthesisVoice conditionally.
+    const voices = speechSynthesis.getVoices();
+    if (voices.length) {
+      self.voice = voices[0];
+      idl_array.add_objects({ SpeechSynthesisVoice: ['voice'] });
+    }
+  }
+);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/speech-api/webspeech.js b/third_party/WebKit/LayoutTests/external/wpt/speech-api/webspeech.js
new file mode 100644
index 0000000..93830e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/speech-api/webspeech.js
@@ -0,0 +1,112 @@
+var DELAY = 500;  // In milliseconds.
+var TIMEOUT = 2000;  // In milliseconds.  Used for most tests.
+if (typeof(TIMEOUT_OVERRIDE) != 'undefined') {
+  TIMEOUT = TIMEOUT_OVERRIDE;
+}
+GLOBAL_TIMEOUT = TIMEOUT + 2000;  // In milliseconds.
+setup({timeout: GLOBAL_TIMEOUT});
+var onstarted = false;
+var neverFireTest = async_test('Events that should not fire',
+                               {timeout: TIMEOUT});
+var onstartTest = async_test('onstart', {timeout: TIMEOUT});
+var reco = new SpeechRecognition();
+
+reco.onstart = onstartTest.step_func(function(event) {
+  assert_false(onstarted, 'onstart should only fire once.');
+  onstarted = true;
+  onstartTest.done();
+  beginTest();
+});
+
+reco.onend = function() {
+  neverFireTest.done();
+  for (var i = 0; i < doneOnEndTestList.length; i++) {
+    doneOnEndTestList[i].done();
+  }
+};
+
+function neverFireEvent(name) {
+  return neverFireTest.step_func(function(event) {
+    assert_unreached(name + ' should not fire.');
+  });
+}
+
+var doneOnEndTestList = [];  // List of all test objects to call done at onend.
+
+// Tally calls to count() and test against min/max when test ends.
+// A max value of 0 indicates no maximum.
+function CountTest(name, min, max) {
+  doneOnEndTestList.push(this);
+  this.name = name;
+  this.min = min;
+  this.max = max;
+  this.sum = 0;
+  this.asyncTest = async_test(name, {timeout: TIMEOUT});
+
+  this.count = function(increment) { this.sum += increment; };
+
+  this.test = function() { return this.asyncTest; };
+
+  this.done = function() {
+    var cTest = this;
+    this.asyncTest.step(function() {
+      notes.innerHTML += cTest.name + ' occurred ' + cTest.sum + ' times.<br>';
+      if (cTest.min == cTest.max) {
+        assert_true(cTest.sum == cTest.min, cTest.name + ' occurred ' +
+          cTest.sum + ' times and should have occurred ' +
+          cTest.min + ' times.');
+      } else {
+        assert_true(cTest.sum >= cTest.min, cTest.name + ' occurred ' +
+            cTest.sum + ' times and should have occurred at least ' +
+            cTest.min + ' times.');
+        assert_true(cTest.max == 0 || cTest.sum <= cTest.max, cTest.name +
+            ' occurred ' + cTest.sum +
+            ' times and should have occurred at most ' + cTest.max + ' times.');
+      }
+      if (cTest.whenDone) {
+        cTest.whenDone();
+      }
+    });
+    this.asyncTest.done();
+  };
+}
+
+// Test for proper cycling of startEvent followed by endEvent.
+function CycleTest(name) {
+  doneOnEndTestList.push(this);
+  this.name = name;
+  this.count = 0;  // Counts number of start / end cycles.
+  this.started = false; // Tracks whether last event was a start or end event.
+  this.test = async_test(name + ' start/stop', {timeout: TIMEOUT});
+
+  this.startEvent = function() {
+    var cycle = this;
+    return this.test.step_func(function(event) {
+      assert_true(onstarted, cycle.name + 'start fired before onstart.');
+      assert_false(cycle.started, cycle.name + 'start fired twice without ' +
+                   cycle.name + 'stop.');
+      cycle.started = true;
+    });
+  };
+
+  this.endEvent = function() {
+    var cycle = this;
+    return this.test.step_func(function(event) {
+      assert_true(cycle.started, cycle.name + 'end fired before ' +
+                  cycle.name + 'start.');
+      cycle.started = false;
+      cycle.count += 1;
+    });
+  };
+
+  this.done = function() {
+    var cycle = this;
+    this.test.step(function() {
+      assert_false(cycle.started, cycle.name + 'start fired but not ' +
+                   cycle.name + 'end.');
+      assert_true(cycle.count > 0, cycle.name + 'start never fired.');
+      notes.innerHTML += cycle.name + ' cycled ' + cycle.count + ' times.<br>';
+    });
+    this.test.done();
+  };
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/WorkerGlobalScope_requestAnimationFrame.htm b/third_party/WebKit/LayoutTests/external/wpt/workers/WorkerGlobalScope_requestAnimationFrame.htm
deleted file mode 100644
index c5efd53..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/workers/WorkerGlobalScope_requestAnimationFrame.htm
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<title> WorkerGlobalScope API: requestAnimationFrame()</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
-<script id="worker" type="text/worker">
-const res = [];
-requestAnimationFrame((dt) => {
-  res.push(dt);
-  requestAnimationFrame((dt) => {
-    res.push(dt);
-    requestAnimationFrame((dt) => {
-      res.push(dt);
-      postMessage(res);
-    });
-  });
-});
-</script>
-<script>
-async_test(function(t) {
-  var blob = new Blob([document.getElementById('worker').textContent]);
-  var worker = new Worker(URL.createObjectURL(blob));
-  worker.addEventListener("error", t.unreached_func("No error should be reported"));
-  worker.addEventListener("message", t.step_func((ev) => {
-    const ret = ev.data;
-    assert_equals(ret.length, 3);
-    assert_true(ret[0] < ret[1]);
-    assert_true(ret[1] < ret[2]);
-    t.done();
-  }));
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js b/third_party/WebKit/LayoutTests/external/wpt/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js
new file mode 100644
index 0000000..e1b0b9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/WorkerGlobalScope_requestAnimationFrame.tentative.worker.js
@@ -0,0 +1,19 @@
+importScripts("/resources/testharness.js");
+
+async_test(t => {
+  const res = [];
+  requestAnimationFrame(t.step_func(dt => {
+    res.push(dt);
+    requestAnimationFrame(t.step_func(dt => {
+      res.push(dt);
+      requestAnimationFrame(t.step_func_done(dt => {
+        res.push(dt);
+        assert_equals(res.length, 3);
+        assert_less_than(res[0], res[1]);
+        assert_less_than(res[1], res[2]);
+      }));
+    }));
+  }));
+});
+
+done();
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-scroll-position.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-scroll-position.html
new file mode 100644
index 0000000..abacb5b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-scroll-position.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<style>
+#grid {
+  display: grid;
+  height: 300px;
+}
+#item {
+  overflow: scroll;
+  overflow-anchor: none;
+}
+#content {
+  height: 800px;
+}
+</style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
+<div id="log"></div>
+
+<div id="grid">
+  <div id="item">
+    <div id="content">AAA</div>
+  </div>
+</div>
+
+<script>
+onload = () => {
+  var item = document.querySelector("#item");
+  item.scrollTo(0, 200);
+  document.querySelector("#content").innerHTML = "BBB";
+  test(() => {
+    assert_equals(item.scrollTop, 200);
+  }, "Checks that scroll position is kept when grid item content is modified.");
+};
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements-expected.txt b/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements-expected.txt
index 4a4ba3c..83af5fb 100644
--- a/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements-expected.txt
@@ -13,7 +13,7 @@
 PASS internals.updateStyleAndReturnAffectedElementCount() is 9
 PASS getComputedStyle(r3, '::first-line').backgroundColor is green
 PASS getComputedStyle(r4, '::first-letter').backgroundColor is transparent
-PASS internals.updateStyleAndReturnAffectedElementCount() is 10
+PASS internals.updateStyleAndReturnAffectedElementCount() is 9
 PASS getComputedStyle(r4, '::first-letter').backgroundColor is green
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements.html b/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements.html
index 22fc85c5..694cfb2 100644
--- a/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements.html
+++ b/third_party/WebKit/LayoutTests/fast/css/dynamic-class-pseudo-elements.html
@@ -81,8 +81,7 @@
 t4.className = "a4";
 
 if (window.internals)
-    shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "10");
+    shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "9");
 
-document.body.offsetLeft; // workaround for issue 351308
 shouldBe("getComputedStyle(r4, '::first-letter').backgroundColor", "green");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/harness/results.html b/third_party/WebKit/LayoutTests/fast/harness/results.html
index 365c9c6..576f28cd 100644
--- a/third_party/WebKit/LayoutTests/fast/harness/results.html
+++ b/third_party/WebKit/LayoutTests/fast/harness/results.html
@@ -391,7 +391,6 @@
   "SKIP":       { index: 9, text: "Skip", isFailure: false, isSuccess: false },
   "MISSING":    { index: 10, text: "Missing", isFailure: false, isSuccess: false },
   "WONTFIX":    { index: 11, text: "WontFix", isFailure: false, isSuccess: false },
-  "NEEDSMANUALREBASELINE": { index: 12, text: "NeedsManualRebaseline", isFailure: false, isSuccess: false },
   "PASS":       { index: 13, text: "Pass", isFailure: false, isSuccess: true },
   "NOTRUN":     { index: 14, text: "NOTRUN", isFailure: false, isSuccess: true }
 };
@@ -962,7 +961,6 @@
   },
   containsNoPass: function(map) {
     return map.has("FAIL")
-        || map.has("NEEDSMANUALREBASELINE")
         || map.has("WONTFIX")
         || map.has("SKIP")
         || map.has("CRASH");
@@ -971,8 +969,7 @@
     return !Filters.containsPass(test.expectedMap) && Filters.containsPass(test.actualMap);
   },
   regressionFromExpectedMap: (finalResult, expectedMap) => {
-    if (expectedMap.has("NEEDSMANUALREBASELINE")
-        || expectedMap.has("NEEDSREBASELINE")
+    if (expectedMap.has("NEEDSREBASELINE")
         || expectedMap.has("WONTFIX"))
       return false;
     switch (finalResult) {
@@ -1016,8 +1013,7 @@
   flagFailure: test => { // Tests that are failing, but expected to pass in base.
     if (Filters.containsPass(test.actualMap))
       return false;
-    if (test.expectedMap.has("NEEDSMANUALREBASELINE")
-        || test.expectedMap.has("NEEDSREBASELINE")
+    if (test.expectedMap.has("NEEDSREBASELINE")
         || test.expectedMap.has("WONTFIX"))
       return false;
     let baseMap = test.flagMap ? test.baseMap : test.expectedMap;
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js
index bc2e35d..2656768e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --expose-wasm
-
 function bytes() {
   var buffer = new ArrayBuffer(arguments.length);
   var view = new Uint8Array(buffer);
@@ -28,6 +26,7 @@
 
 var kHeaderSize = 8;
 var kPageSize = 65536;
+var kSpecMaxPages = 65535;
 
 function bytesWithHeader() {
   var buffer = new ArrayBuffer(kHeaderSize + arguments.length);
@@ -52,23 +51,29 @@
 
 // Section declaration constants
 let kUnknownSectionCode = 0;
-let kTypeSectionCode = 1;      // Function signature declarations
-let kImportSectionCode = 2;    // Import declarations
-let kFunctionSectionCode = 3;  // Function declarations
-let kTableSectionCode = 4;     // Indirect function table and other tables
-let kMemorySectionCode = 5;    // Memory attributes
-let kGlobalSectionCode = 6;    // Global declarations
-let kExportSectionCode = 7;    // Exports
-let kStartSectionCode = 8;     // Start function declaration
-let kElementSectionCode = 9;  // Elements section
-let kCodeSectionCode = 10;      // Function code
-let kDataSectionCode = 11;     // Data segments
-let kNameSectionCode = 12;     // Name section (encoded as string)
+let kTypeSectionCode = 1;        // Function signature declarations
+let kImportSectionCode = 2;      // Import declarations
+let kFunctionSectionCode = 3;    // Function declarations
+let kTableSectionCode = 4;       // Indirect function table and other tables
+let kMemorySectionCode = 5;      // Memory attributes
+let kGlobalSectionCode = 6;      // Global declarations
+let kExportSectionCode = 7;      // Exports
+let kStartSectionCode = 8;       // Start function declaration
+let kElementSectionCode = 9;     // Elements section
+let kCodeSectionCode = 10;       // Function code
+let kDataSectionCode = 11;       // Data segments
+let kNameSectionCode = 12;       // Name section (encoded as string)
+let kExceptionSectionCode = 13;  // Exception section (must appear before code section)
+
+// Name section types
+let kModuleNameCode = 0;
+let kFunctionNamesCode = 1;
+let kLocalNamesCode = 2;
 
 let kWasmFunctionTypeForm = 0x60;
 let kWasmAnyFunctionTypeForm = 0x70;
 
-let kResizableMaximumFlag = 1;
+let kHasMaximumFlag = 1;
 
 // Function declaration flags
 let kDeclFunctionName   = 0x01;
@@ -82,7 +87,8 @@
 let kWasmI64 = 0x7e;
 let kWasmF32 = 0x7d;
 let kWasmF64 = 0x7c;
-let kWasmS128 = 0x7b;
+let kWasmS128  = 0x7b;
+let kWasmAnyRef = 0x6f;
 
 let kExternalFunction = 0;
 let kExternalTable = 1;
@@ -104,7 +110,7 @@
 let kSig_v_v = makeSig([], []);
 let kSig_i_v = makeSig([], [kWasmI32]);
 let kSig_l_v = makeSig([], [kWasmI64]);
-let kSig_f_v = makeSig([], [kWasmF64]);
+let kSig_f_v = makeSig([], [kWasmF32]);
 let kSig_d_v = makeSig([], [kWasmF64]);
 let kSig_v_i = makeSig([kWasmI32], []);
 let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []);
@@ -113,7 +119,20 @@
 let kSig_v_d = makeSig([kWasmF64], []);
 let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []);
 let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
-let kSig_s_v = makeSig([], [kWasmS128]);
+let kSig_ii_v = makeSig([], [kWasmI32, kWasmI32]);
+let kSig_iii_v = makeSig([], [kWasmI32, kWasmI32, kWasmI32]);
+let kSig_ii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32]);
+let kSig_iii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32, kWasmI32]);
+let kSig_ii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32]);
+let kSig_iii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32, kWasmI32]);
+
+let kSig_v_f = makeSig([kWasmF32], []);
+let kSig_f_f = makeSig([kWasmF32], [kWasmF32]);
+let kSig_d_d = makeSig([kWasmF64], [kWasmF64]);
+let kSig_r_r = makeSig([kWasmAnyRef], [kWasmAnyRef]);
+let kSig_i_r = makeSig([kWasmAnyRef], [kWasmI32]);
+let kSig_v_r = makeSig([kWasmAnyRef], []);
+let kSig_r_v = makeSig([], [kWasmAnyRef]);
 
 function makeSig(params, results) {
   return {params: params, results: results};
@@ -167,6 +186,7 @@
 let kExprI64Const = 0x42;
 let kExprF32Const = 0x43;
 let kExprF64Const = 0x44;
+let kExprRefNull = 0xd0;
 let kExprI32LoadMem = 0x28;
 let kExprI64LoadMem = 0x29;
 let kExprF32LoadMem = 0x2a;
@@ -226,6 +246,7 @@
 let kExprF64Gt = 0x64;
 let kExprF64Le = 0x65;
 let kExprF64Ge = 0x66;
+let kExprRefIsNull = 0xd1;
 let kExprI32Clz = 0x67;
 let kExprI32Ctz = 0x68;
 let kExprI32Popcnt = 0x69;
@@ -316,6 +337,37 @@
 let kExprF32ReinterpretI32 = 0xbe;
 let kExprF64ReinterpretI64 = 0xbf;
 
+// Prefix opcodes
+let kAtomicPrefix = 0xfe;
+
+let kExprI32AtomicLoad = 0x10;
+let kExprI32AtomicLoad8U = 0x12;
+let kExprI32AtomicLoad16U = 0x13;
+let kExprI32AtomicStore = 0x17;
+let kExprI32AtomicStore8U = 0x19;
+let kExprI32AtomicStore16U = 0x1a;
+let kExprI32AtomicAdd = 0x1e;
+let kExprI32AtomicAdd8U = 0x20;
+let kExprI32AtomicAdd16U = 0x21;
+let kExprI32AtomicSub = 0x25;
+let kExprI32AtomicSub8U = 0x27;
+let kExprI32AtomicSub16U = 0x28;
+let kExprI32AtomicAnd = 0x2c;
+let kExprI32AtomicAnd8U = 0x2e;
+let kExprI32AtomicAnd16U = 0x2f;
+let kExprI32AtomicOr = 0x33;
+let kExprI32AtomicOr8U = 0x35;
+let kExprI32AtomicOr16U = 0x36;
+let kExprI32AtomicXor = 0x3a;
+let kExprI32AtomicXor8U = 0x3c;
+let kExprI32AtomicXor16U = 0x3d;
+let kExprI32AtomicExchange = 0x41;
+let kExprI32AtomicExchange8U = 0x43;
+let kExprI32AtomicExchange16U = 0x44;
+let kExprI32AtomicCompareExchange = 0x48
+let kExprI32AtomicCompareExchange8U = 0x4a
+let kExprI32AtomicCompareExchange16U = 0x4b
+
 let kTrapUnreachable          = 0;
 let kTrapMemOutOfBounds       = 1;
 let kTrapDivByZero            = 2;
@@ -324,7 +376,7 @@
 let kTrapFloatUnrepresentable = 5;
 let kTrapFuncInvalid          = 6;
 let kTrapFuncSigMismatch      = 7;
-let kTrapInvalidIndex         = 8;
+let kTrapTypeError            = 8;
 
 let kTrapMsgs = [
   "unreachable",
@@ -332,33 +384,29 @@
   "divide by zero",
   "divide result unrepresentable",
   "remainder by zero",
-  "integer result unrepresentable",
-  "invalid function",
+  "float unrepresentable in integer range",
+  "invalid index into function table",
   "function signature mismatch",
-  "invalid index into function table"
+  "wasm function signature contains illegal type"
 ];
 
 function assertTraps(trap, code) {
-  var threwException = true;
   try {
     if (typeof code === 'function') {
       code();
     } else {
       eval(code);
     }
-    threwException = false;
   } catch (e) {
-    assertEquals("object", typeof e);
+    assertEquals('object', typeof e);
     assertEquals(kTrapMsgs[trap], e.message);
     // Success.
     return;
   }
-  throw new MjsUnitAssertionError("Did not trap, expected: "
-                                  + kTrapMsgs[trap]);
+  throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
 }
 
-function assertWasmThrows(value, code) {
-  assertEquals("number", typeof(value));
+function assertWasmThrows(runtime_id, values, code) {
   try {
     if (typeof code === 'function') {
       code();
@@ -366,11 +414,34 @@
       eval(code);
     }
   } catch (e) {
-    assertEquals("number", typeof e);
-    assertEquals(value, e);
+    assertTrue(e instanceof WebAssembly.RuntimeError);
+    var e_runtime_id = e['WasmExceptionRuntimeId'];
+    assertEquals(e_runtime_id, runtime_id);
+    assertTrue(Number.isInteger(e_runtime_id));
+    var e_values = e['WasmExceptionValues'];
+    assertEquals(values.length, e_values.length);
+    for (i = 0; i < values.length; ++i) {
+      assertEquals(values[i], e_values[i]);
+    }
     // Success.
     return;
   }
-  throw new MjsUnitAssertionError("Did not throw at all, expected: "
-                                  + value);
+  throw new MjsUnitAssertionError('Did not throw expected: ' + runtime_id + values);
+}
+
+function wasmI32Const(val) {
+  let bytes = [kExprI32Const];
+  for (let i = 0; i < 4; ++i) {
+    bytes.push(0x80 | ((val >> (7 * i)) & 0x7f));
+  }
+  bytes.push((val >> (7 * 4)) & 0x7f);
+  return bytes;
+}
+
+function wasmF32Const(f) {
+  return [kExprF32Const].concat(Array.from(new Uint8Array((new Float32Array([f])).buffer)));
+}
+
+function wasmF64Const(f) {
+  return [kExprF64Const].concat(Array.from(new Uint8Array((new Float64Array([f])).buffer)));
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js
index 0d8c698..c787c280 100644
--- a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js
@@ -74,7 +74,7 @@
     // Emit section length.
     this.emit_u32v(section.length);
     // Copy the temporary buffer.
-    this.push(...section);
+    for (var i = 0; i < section.length; i++) this.push(section[i]);
   }
 }
 
@@ -86,6 +86,15 @@
     this.body = [];
   }
 
+  numLocalNames() {
+    if (this.local_names === undefined) return 0;
+    let num_local_names = 0;
+    for (let loc_name of this.local_names) {
+      if (loc_name !== undefined) ++num_local_names;
+    }
+    return num_local_names;
+  }
+
   exportAs(name) {
     this.module.addExport(name, this.index);
     return this;
@@ -98,11 +107,12 @@
 
   addBody(body) {
     for (let b of body) {
-      if (typeof b != 'number') throw new Error("invalid body");
+      if (typeof b !== 'number' || (b & (~0xFF)) !== 0 )
+        throw new Error('invalid body (entries must be 8 bit numbers): ' + body);
     }
-    this.body = body;
+    this.body = body.slice();
     // Automatically add the end for the function block to the body.
-    body.push(kExprEnd);
+    this.body.push(kExprEnd);
     return this;
   }
 
@@ -111,8 +121,25 @@
     return this;
   }
 
-  addLocals(locals) {
-    this.locals = locals;
+  getNumLocals() {
+    let total_locals = 0;
+    for (let l of this.locals || []) {
+      for (let type of ["i32", "i64", "f32", "f64", "s128"]) {
+        total_locals += l[type + "_count"] || 0;
+      }
+    }
+    return total_locals;
+  }
+
+  addLocals(locals, names) {
+    const old_num_locals = this.getNumLocals();
+    if (!this.locals) this.locals = []
+    this.locals.push(locals);
+    if (names) {
+      if (!this.local_names) this.local_names = [];
+      const missing_names = old_num_locals - this.local_names.length;
+      this.local_names.push(...new Array(missing_names), ...names);
+    }
     return this;
   }
 
@@ -142,9 +169,11 @@
     this.imports = [];
     this.exports = [];
     this.globals = [];
+    this.exceptions = [];
     this.functions = [];
     this.function_table = [];
-    this.function_table_length = 0;
+    this.function_table_length_min = 0;
+    this.function_table_length_max = 0;
     this.function_table_inits = [];
     this.segments = [];
     this.explicit = [];
@@ -158,8 +187,8 @@
     return this;
   }
 
-  addMemory(min, max, exp) {
-    this.memory = {min: min, max: max, exp: exp};
+  addMemory(min, max, exp, shared) {
+    this.memory = {min: min, max: max, exp: exp, shared: shared};
     return this;
   }
 
@@ -185,8 +214,9 @@
   }
 
   addType(type) {
-    // TODO: canonicalize types?
     this.types.push(type);
+    var pl = type.params.length;  // should have params
+    var rl = type.results.length; // should have results
     return this.types.length - 1;
   }
 
@@ -197,6 +227,13 @@
     return glob;
   }
 
+  addException(type) {
+    if (type.results.length != 0)
+      throw new Error('Invalid exception signature: ' + type);
+    this.exceptions.push(type);
+    return this.exceptions.length - 1;
+  }
+
   addFunction(name, type) {
     let type_index = (typeof type) == "number" ? type : this.addType(type);
     let func = new WasmFunctionBuilder(this, name, type_index);
@@ -212,16 +249,16 @@
     return this.num_imported_funcs++;
   }
 
-  addImportedGlobal(module = "", name, type) {
+  addImportedGlobal(module = "", name, type, mutable = false) {
     let o = {module: module, name: name, kind: kExternalGlobal, type: type,
-             mutable: false}
+             mutable: mutable};
     this.imports.push(o);
     return this.num_imported_globals++;
   }
 
-  addImportedMemory(module = "", name, initial = 0, maximum) {
+  addImportedMemory(module = "", name, initial = 0, maximum, shared) {
     let o = {module: module, name: name, kind: kExternalMemory,
-             initial: initial, maximum: maximum};
+             initial: initial, maximum: maximum, shared: shared};
     this.imports.push(o);
     return this;
   }
@@ -256,19 +293,32 @@
                                     array: array});
     if (!is_global) {
       var length = base + array.length;
-      if (length > this.function_table_length && !is_import) {
-        this.function_table_length = length;
+      if (length > this.function_table_length_min && !is_import) {
+        this.function_table_length_min = length;
+      }
+      if (length > this.function_table_length_max && !is_import) {
+         this.function_table_length_max = length;
       }
     }
     return this;
   }
 
   appendToTable(array) {
+    for (let n of array) {
+      if (typeof n != 'number')
+        throw new Error('invalid table (entries have to be numbers): ' + array);
+    }
     return this.addFunctionTableInit(this.function_table.length, false, array);
   }
 
-  setFunctionTableLength(length) {
-    this.function_table_length = length;
+  setFunctionTableBounds(min, max) {
+    this.function_table_length_min = min;
+    this.function_table_length_max = max;
+    return this;
+  }
+
+  setName(name) {
+    this.name = name;
     return this;
   }
 
@@ -314,7 +364,12 @@
             section.emit_u8(imp.mutable);
           } else if (imp.kind == kExternalMemory) {
             var has_max = (typeof imp.maximum) != "undefined";
-            section.emit_u8(has_max ? 1 : 0); // flags
+            var is_shared = (typeof imp.shared) != "undefined";
+            if (is_shared) {
+              section.emit_u8(has_max ? 3 : 2); // flags
+            } else {
+              section.emit_u8(has_max ? 1 : 0); // flags
+            }
             section.emit_u32v(imp.initial); // initial
             if (has_max) section.emit_u32v(imp.maximum); // maximum
           } else if (imp.kind == kExternalTable) {
@@ -331,40 +386,45 @@
     }
 
     // Add functions declarations
-    let has_names = false;
-    let names = false;
     if (wasm.functions.length > 0) {
       if (debug) print("emitting function decls @ " + binary.length);
       binary.emit_section(kFunctionSectionCode, section => {
         section.emit_u32v(wasm.functions.length);
         for (let func of wasm.functions) {
-          has_names = has_names || (func.name != undefined &&
-                                   func.name.length > 0);
           section.emit_u32v(func.type_index);
         }
       });
     }
 
     // Add function_table.
-    if (wasm.function_table_length > 0) {
+    if (wasm.function_table_length_min > 0) {
       if (debug) print("emitting table @ " + binary.length);
       binary.emit_section(kTableSectionCode, section => {
         section.emit_u8(1);  // one table entry
         section.emit_u8(kWasmAnyFunctionTypeForm);
-        section.emit_u8(1);
-        section.emit_u32v(wasm.function_table_length);
-        section.emit_u32v(wasm.function_table_length);
+        // TODO(gdeepti): Cleanup to use optional max flag,
+        // fix up tests to set correct initial/maximum values
+        section.emit_u32v(1);
+        section.emit_u32v(wasm.function_table_length_min);
+        section.emit_u32v(wasm.function_table_length_max);
       });
     }
 
     // Add memory section
-    if (wasm.memory != undefined) {
+    if (wasm.memory !== undefined) {
       if (debug) print("emitting memory @ " + binary.length);
       binary.emit_section(kMemorySectionCode, section => {
         section.emit_u8(1);  // one memory entry
-        section.emit_u32v(kResizableMaximumFlag);
+        const has_max = wasm.memory.max !== undefined;
+        const is_shared = wasm.memory.shared !== undefined;
+        // Emit flags (bit 0: reszeable max, bit 1: shared memory)
+        if (is_shared) {
+          section.emit_u8(has_max ? 3 : 2);
+        } else {
+          section.emit_u8(has_max ? 1 : 0);
+        }
         section.emit_u32v(wasm.memory.min);
-        section.emit_u32v(wasm.memory.max);
+        if (has_max) section.emit_u32v(wasm.memory.max);
       });
     }
 
@@ -419,7 +479,7 @@
     }
 
     // Add export table.
-    var mem_export = (wasm.memory != undefined && wasm.memory.exp);
+    var mem_export = (wasm.memory !== undefined && wasm.memory.exp);
     var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
     if (exports_count > 0) {
       if (debug) print("emitting exports @ " + binary.length);
@@ -439,7 +499,7 @@
     }
 
     // Add start function section.
-    if (wasm.start_index != undefined) {
+    if (wasm.start_index !== undefined) {
       if (debug) print("emitting start function @ " + binary.length);
       binary.emit_section(kStartSectionCode, section => {
         section.emit_u32v(wasm.start_index);
@@ -452,9 +512,9 @@
       binary.emit_section(kElementSectionCode, section => {
         var inits = wasm.function_table_inits;
         section.emit_u32v(inits.length);
-        section.emit_u8(0); // table index
 
         for (let init of inits) {
+          section.emit_u8(0); // table index
           if (init.is_global) {
             section.emit_u8(kExprGetGlobal);
           } else {
@@ -470,6 +530,20 @@
       });
     }
 
+    // Add exceptions.
+    if (wasm.exceptions.length > 0) {
+      if (debug) print("emitting exceptions @ " + binary.length);
+      binary.emit_section(kExceptionSectionCode, section => {
+        section.emit_u32v(wasm.exceptions.length);
+        for (let type of wasm.exceptions) {
+          section.emit_u32v(type.params.length);
+          for (let param of type.params) {
+            section.emit_u8(param);
+          }
+        }
+      });
+    }
+
     // Add function bodies.
     if (wasm.functions.length > 0) {
       // emit function bodies
@@ -479,9 +553,7 @@
         for (let func of wasm.functions) {
           // Function body length will be patched later.
           let local_decls = [];
-          let l = func.locals;
-          if (l != undefined) {
-            let local_decls_count = 0;
+          for (let l of func.locals || []) {
             if (l.i32_count > 0) {
               local_decls.push({count: l.i32_count, type: kWasmI32});
             }
@@ -494,6 +566,9 @@
             if (l.f64_count > 0) {
               local_decls.push({count: l.f64_count, type: kWasmF64});
             }
+            if (l.s128_count > 0) {
+              local_decls.push({count: l.s128_count, type: kWasmS128});
+            }
           }
 
           let header = new Binary;
@@ -539,21 +614,50 @@
       binary.emit_bytes(exp);
     }
 
-    // Add function names.
-    if (has_names) {
-      if (debug) print("emitting names @ " + binary.length);
+    // Add names.
+    let num_function_names = 0;
+    let num_functions_with_local_names = 0;
+    for (let func of wasm.functions) {
+      if (func.name !== undefined) ++num_function_names;
+      if (func.numLocalNames() > 0) ++num_functions_with_local_names;
+    }
+    if (num_function_names > 0 || num_functions_with_local_names > 0 ||
+        wasm.name !== undefined) {
+      if (debug) print('emitting names @ ' + binary.length);
       binary.emit_section(kUnknownSectionCode, section => {
-        section.emit_string("name");
-        var count = wasm.functions.length + wasm.num_imported_funcs;
-        section.emit_u32v(count);
-        for (var i = 0; i < wasm.num_imported_funcs; i++) {
-          section.emit_u8(0); // empty string
-          section.emit_u8(0); // local names count == 0
+        section.emit_string('name');
+        // Emit module name.
+        if (wasm.name !== undefined) {
+          section.emit_section(kModuleNameCode, name_section => {
+            name_section.emit_string(wasm.name);
+          });
         }
-        for (let func of wasm.functions) {
-          var name = func.name == undefined ? "" : func.name;
-          section.emit_string(name);
-          section.emit_u8(0);  // local names count == 0
+        // Emit function names.
+        if (num_function_names > 0) {
+          section.emit_section(kFunctionNamesCode, name_section => {
+            name_section.emit_u32v(num_function_names);
+            for (let func of wasm.functions) {
+              if (func.name === undefined) continue;
+              name_section.emit_u32v(func.index);
+              name_section.emit_string(func.name);
+            }
+          });
+        }
+        // Emit local names.
+        if (num_functions_with_local_names > 0) {
+          section.emit_section(kLocalNamesCode, name_section => {
+            name_section.emit_u32v(num_functions_with_local_names);
+            for (let func of wasm.functions) {
+              if (func.numLocalNames() == 0) continue;
+              name_section.emit_u32v(func.index);
+              name_section.emit_u32v(func.numLocalNames());
+              for (let i = 0; i < func.local_names.length; ++i) {
+                if (func.local_names[i] === undefined) continue;
+                name_section.emit_u32v(i);
+                name_section.emit_string(func.local_names[i]);
+              }
+            }
+          });
         }
       });
     }
@@ -578,4 +682,13 @@
     let instance = new WebAssembly.Instance(module, ffi);
     return instance;
   }
+
+  asyncInstantiate(ffi) {
+    return WebAssembly.instantiate(this.toBuffer(), ffi)
+        .then(({module, instance}) => instance);
+  }
+
+  toModule(debug = false) {
+    return new WebAssembly.Module(this.toBuffer(debug));
+  }
 }
diff --git a/third_party/WebKit/LayoutTests/lifecycle/background-change-lifecycle-count.html b/third_party/WebKit/LayoutTests/lifecycle/background-change-lifecycle-count.html
new file mode 100644
index 0000000..ccdba3b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/lifecycle/background-change-lifecycle-count.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<div id="box" style="width: 100px; height: 100px; background: blue;"></div>
+
+<script>
+  var t = async_test('Integration test for background style change updates');
+
+  t.step(function() {
+    assert_true(!!window.internals, 'Test requires window.internals');
+  });
+
+  // Loading is non-deterministic so record the initial count after onload
+  // plus a paint.
+  onload = function() {
+    requestAnimationFrame(function() {
+      // Windows flakily sends mouse events on the first frame so wait an
+      // additional frame before starting the test.
+      requestAnimationFrame(function() {
+        var initialLifecycleCount = internals.LifecycleUpdateCount();
+
+        box.style.background = 'green';
+
+        requestAnimationFrame(function() {
+          var postChangeCount = internals.LifecycleUpdateCount();
+          t.step(function() {
+            // A background style change should have only resulted in a single
+            // lifecycle update. If this ever fails, something is causing an
+            // unnecessary lifecycle update.
+            assert_equals(postChangeCount, initialLifecycleCount + 1,
+                'a style change should cause one lifecycle update');
+          });
+
+          // A timeout is used so we can capture unnecessary updates. 250ms was
+          // chosen because it is the lowest value that would reliably fail for
+          // https://crbug.com/866981 and https://crbug.com/868983 on bots; lower
+          // values would just become flaky.
+          setTimeout(function() {
+            t.step(function() {
+              // The timeout should cause a single additional update. If this ever
+              // fails, something is causing an unnecessary lifecycle update.
+              assert_equals(internals.LifecycleUpdateCount(), postChangeCount + 1,
+                  'a timeout should cause one lifecycle update');
+            });
+            t.done();
+          }, 250);
+        });
+      });
+    });
+  }
+</script>
diff --git a/third_party/WebKit/LayoutTests/media/track/track-cue-rendering-font-with-zoom.html b/third_party/WebKit/LayoutTests/media/track/track-cue-rendering-font-with-zoom.html
new file mode 100644
index 0000000..abcf2e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/track/track-cue-rendering-font-with-zoom.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<title>Test that default positioned TextTrack's cues are rendered correctly.</title>
+<script src="../media-controls.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<video>
+    <track src="captions-webvtt/captions.vtt" kind="captions" default>
+</video>
+<script>
+async_test(function(t) {
+    zoom_factor = 2.5;
+    eventSender.setPageZoomFactor(zoom_factor);
+    var video = document.querySelector("video");
+    var testTrack = document.querySelector("track");
+    video.src = "../content/test.ogv";
+
+    video.onseeked = t.step_func(function() {
+        assert_equals(window.devicePixelRatio, zoom_factor)
+        testFontSize([[2560, 1440], [1000, 300], [600, 450], [300, 150]]);
+    });
+
+    function testFontSize(subjects) {
+        var dimensions = subjects.shift();
+        video.width = dimensions[0];
+        video.height = dimensions[1];
+        runAfterLayoutAndPaint(t.step_func(function() {
+            assert_equals(getComputedStyle(textTrackContainerElement(video)).fontSize, video.height * 0.05 + "px");
+            if (subjects.length) {
+                testFontSize(subjects);
+            } else {
+                t.done();
+            }
+        }));
+    }
+
+    video.currentTime = 0.5;
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png
index 57d418a..54b9b8a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png
index 3eb7fb6..73eb539e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png
index c493fd01..d6e73b5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt
index 6094517..762b36e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt
@@ -15,10 +15,22 @@
   LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180
 layer at (57,85) size 240x180
   LayoutFlexibleBox {DIV} at (0,0) size 240x180
-layer at (57,85) size 240x228 backgroundClip at (57,85) size 240x180 clip at (59,87) size 237x178
-  LayoutButton (relative positioned) {INPUT} at (0,0) size 240x228 [border: (1.50px solid #D8D8D8) (1.50px solid #D1D1D1) (1.50px solid #BABABA) (1.50px solid #D1D1D1)]
-    LayoutFlexibleBox (anonymous) at (12,77.25) size 216x72
+layer at (57,85) size 240x156 clip at (59,87) size 237x153
+  LayoutButton (relative positioned) {INPUT} at (0,0) size 240x156 [border: (1.50px solid #D8D8D8) (1.50px solid #D1D1D1) (1.50px solid #BABABA) (1.50px solid #D1D1D1)]
+    LayoutFlexibleBox (anonymous) at (12,41.25) size 216x72
       LayoutBlockFlow {DIV} at (72,0) size 72x72 [bgcolor=#FFFFFFE6]
+layer at (57,169) size 240x72 scrollWidth 267
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,84) size 240x72
+    LayoutBlockFlow {DIV} at (24,0) size 46.72x72 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x28
+        text run at (0,22) width 47: "0:00"
+    LayoutBlockFlow {DIV} at (76.72,-72) size 46.72x144 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x100
+        text run at (0,22) width 7: "/"
+        text run at (0,94) width 47: "0:06"
+    LayoutBlockFlow {DIV} at (123.44,72) size 0x0
+    LayoutButton {INPUT} at (123.44,0) size 72x72
+    LayoutButton {INPUT} at (195.44,0) size 72x72
 layer at (57,241) size 240x24
   LayoutSlider {INPUT} at (0,156) size 240x24 [color=#909090]
     LayoutFlexibleBox {DIV} at (24,0) size 192x6
@@ -41,10 +53,22 @@
   LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180
 layer at (57,310) size 240x180
   LayoutFlexibleBox {DIV} at (0,0) size 240x180
-layer at (57,310) size 240x228 backgroundClip at (43,291) size 268x218 clip at (59,312) size 237x197
-  LayoutButton (relative positioned) {INPUT} at (0,0) size 240x228 [border: (1.50px solid #D8D8D8) (1.50px solid #D1D1D1) (1.50px solid #BABABA) (1.50px solid #D1D1D1)]
-    LayoutFlexibleBox (anonymous) at (12,77.25) size 216x72
+layer at (57,310) size 240x156 clip at (59,312) size 237x153
+  LayoutButton (relative positioned) {INPUT} at (0,0) size 240x156 [border: (1.50px solid #D8D8D8) (1.50px solid #D1D1D1) (1.50px solid #BABABA) (1.50px solid #D1D1D1)]
+    LayoutFlexibleBox (anonymous) at (12,41.25) size 216x72
       LayoutBlockFlow {DIV} at (72,0) size 72x72 [bgcolor=#FFFFFFE6]
+layer at (57,394) size 240x72 backgroundClip at (47,373) size 249x113 clip at (57,394) size 239x72 scrollWidth 267
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,84) size 240x72
+    LayoutBlockFlow {DIV} at (24,0) size 46.72x72 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x28
+        text run at (0,22) width 47: "0:00"
+    LayoutBlockFlow {DIV} at (76.72,-72) size 46.72x144 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x100
+        text run at (0,22) width 7: "/"
+        text run at (0,94) width 47: "0:06"
+    LayoutBlockFlow {DIV} at (123.44,72) size 0x0
+    LayoutButton {INPUT} at (123.44,0) size 72x72
+    LayoutButton {INPUT} at (195.44,0) size 72x72
 layer at (57,466) size 240x24
   LayoutSlider {INPUT} at (0,156) size 240x24 [color=#909090]
     LayoutFlexibleBox {DIV} at (24,0) size 192x6
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png
index 4592021..b4a57b2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.txt
new file mode 100644
index 0000000..d40ff8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/video-surface-layer/media/video-zoom-controls-expected.txt
@@ -0,0 +1,86 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 800x600
+    LayoutBlockFlow {BODY} at (12,12) size 776x543
+      LayoutBlockFlow {P} at (0,0) size 776x28
+        LayoutText {#text} at (0,0) size 278x28
+          text run at (0,0) width 278: "Zoomed video with controls."
+layer at (57,85) size 240x180
+  LayoutVideo {VIDEO} at (45,73) size 240x180
+layer at (57,85) size 240x180
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180
+    LayoutFlexibleBox {DIV} at (0,0) size 240x180
+layer at (57,85) size 240x180
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180
+layer at (57,85) size 240x180
+  LayoutFlexibleBox {DIV} at (0,0) size 240x180
+layer at (57,85) size 240x156 clip at (59,87) size 237x153
+  LayoutButton (relative positioned) {INPUT} at (0,0) size 240x156 [border: (1.50px solid #D8D8D8) (1.50px solid #D1D1D1) (1.50px solid #BABABA) (1.50px solid #D1D1D1)]
+    LayoutFlexibleBox (anonymous) at (12,41.25) size 216x72
+      LayoutBlockFlow {DIV} at (72,0) size 72x72 [bgcolor=#FFFFFFE6]
+layer at (57,169) size 240x72 scrollWidth 339
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,84) size 240x72
+    LayoutBlockFlow {DIV} at (24,0) size 46.72x72 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x28
+        text run at (0,22) width 47: "0:00"
+    LayoutBlockFlow {DIV} at (76.72,-72) size 46.72x144 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x100
+        text run at (0,22) width 7: "/"
+        text run at (0,94) width 47: "0:06"
+    LayoutBlockFlow {DIV} at (123.44,72) size 0x0
+    LayoutButton {INPUT} at (123.44,0) size 72x72
+    LayoutButton {INPUT} at (195.44,0) size 72x72
+    LayoutButton {INPUT} at (267.44,0) size 72x72
+layer at (57,241) size 240x24
+  LayoutSlider {INPUT} at (0,156) size 240x24 [color=#909090]
+    LayoutFlexibleBox {DIV} at (24,0) size 192x6
+layer at (81,241) size 192x6
+  LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 192x6 [bgcolor=#FFFFFF4D]
+layer at (81,235) size 18x18
+  LayoutBlockFlow (relative positioned) {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF]
+layer at (81,241) size 192x6 scrollWidth 288
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 192x6
+layer at (81,241) size 0x6
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF]
+layer at (81,241) size 288x6 backgroundClip at (81,241) size 192x6 clip at (81,241) size 192x6
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 288x6 [bgcolor=#FFFFFF8A]
+layer at (57,310) size 240x180
+  LayoutVideo {VIDEO} at (45,298) size 240x180
+layer at (57,310) size 240x180
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180
+    LayoutFlexibleBox {DIV} at (0,0) size 240x180
+layer at (57,310) size 240x180
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 240x180
+layer at (57,310) size 240x180
+  LayoutFlexibleBox {DIV} at (0,0) size 240x180
+layer at (57,310) size 240x156 clip at (59,312) size 237x153
+  LayoutButton (relative positioned) {INPUT} at (0,0) size 240x156 [border: (1.50px solid #D8D8D8) (1.50px solid #D1D1D1) (1.50px solid #BABABA) (1.50px solid #D1D1D1)]
+    LayoutFlexibleBox (anonymous) at (12,41.25) size 216x72
+      LayoutBlockFlow {DIV} at (72,0) size 72x72 [bgcolor=#FFFFFFE6]
+layer at (57,394) size 240x72 backgroundClip at (47,373) size 249x113 clip at (57,394) size 239x72 scrollWidth 339
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,84) size 240x72
+    LayoutBlockFlow {DIV} at (24,0) size 46.72x72 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x28
+        text run at (0,22) width 47: "0:00"
+    LayoutBlockFlow {DIV} at (76.72,-72) size 46.72x144 [color=#FFFFFF]
+      LayoutText {#text} at (0,22) size 47x100
+        text run at (0,22) width 7: "/"
+        text run at (0,94) width 47: "0:06"
+    LayoutBlockFlow {DIV} at (123.44,72) size 0x0
+    LayoutButton {INPUT} at (123.44,0) size 72x72
+    LayoutButton {INPUT} at (195.44,0) size 72x72
+    LayoutButton {INPUT} at (267.44,0) size 72x72
+layer at (57,466) size 240x24
+  LayoutSlider {INPUT} at (0,156) size 240x24 [color=#909090]
+    LayoutFlexibleBox {DIV} at (24,0) size 192x6
+layer at (81,466) size 192x6
+  LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 192x6 [bgcolor=#FFFFFF4D]
+layer at (81,460) size 18x18
+  LayoutBlockFlow (relative positioned) {DIV} at (0,-6) size 18x18 [bgcolor=#FFFFFF]
+layer at (81,466) size 192x6 backgroundClip at (70,448) size 190x40 clip at (81,466) size 179x6 scrollWidth 288
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 192x6
+layer at (81,466) size 0x6
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 0x6 [bgcolor=#FFFFFF]
+layer at (81,466) size 288x6 backgroundClip at (70,448) size 190x40 clip at (70,448) size 190x40
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 288x6 [bgcolor=#FFFFFF8A]
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 60bda5e..3fa1ede9 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -4,6 +4,10 @@
     getter signal
     method abort
     method constructor
+interface AbortPaymentEvent : ExtendableEvent
+    attribute @@toStringTag
+    method constructor
+    method respondWith
 interface AbortSignal : EventTarget
     attribute @@toStringTag
     getter aborted
@@ -51,6 +55,14 @@
     method keys
     method match
     method open
+interface CanMakePaymentEvent : ExtendableEvent
+    attribute @@toStringTag
+    getter methodData
+    getter modifiers
+    getter paymentRequestOrigin
+    getter topOrigin
+    method constructor
+    method respondWith
 interface CanvasGradient
     attribute @@toStringTag
     method addColorStop
@@ -790,6 +802,27 @@
     method moveTo
     method quadraticCurveTo
     method rect
+interface PaymentInstruments
+    attribute @@toStringTag
+    method clear
+    method constructor
+    method delete
+    method get
+    method has
+    method keys
+    method set
+interface PaymentRequestEvent : ExtendableEvent
+    attribute @@toStringTag
+    getter instrumentKey
+    getter methodData
+    getter modifiers
+    getter paymentRequestId
+    getter paymentRequestOrigin
+    getter topOrigin
+    getter total
+    method constructor
+    method openWindow
+    method respondWith
 interface Performance : EventTarget
     attribute @@toStringTag
     getter onresourcetimingbufferfull
@@ -964,6 +997,7 @@
     getter installing
     getter navigationPreload
     getter onupdatefound
+    getter paymentManager
     getter pushManager
     getter scope
     getter sync
@@ -2440,24 +2474,30 @@
     attribute console
     attribute internals
     getter clients
+    getter onabortpayment
     getter onactivate
+    getter oncanmakepayment
     getter onfetch
     getter oninstall
     getter onmessage
     getter onnotificationclick
     getter onnotificationclose
+    getter onpaymentrequest
     getter onpush
     getter onsync
     getter registration
     method fetch
     method gc
     method skipWaiting
+    setter onabortpayment
     setter onactivate
+    setter oncanmakepayment
     setter onfetch
     setter oninstall
     setter onmessage
     setter onnotificationclick
     setter onnotificationclose
+    setter onpaymentrequest
     setter onpush
     setter onsync
 PASS Verify the interface of ServiceWorkerGlobalScope
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 2ae7d7b..cfc04e05 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -765,6 +765,15 @@
 [Worker]     method moveTo
 [Worker]     method quadraticCurveTo
 [Worker]     method rect
+[Worker] interface PaymentInstruments
+[Worker]     attribute @@toStringTag
+[Worker]     method clear
+[Worker]     method constructor
+[Worker]     method delete
+[Worker]     method get
+[Worker]     method has
+[Worker]     method keys
+[Worker]     method set
 [Worker] interface Performance : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onresourcetimingbufferfull
@@ -931,6 +940,7 @@
 [Worker]     getter installing
 [Worker]     getter navigationPreload
 [Worker]     getter onupdatefound
+[Worker]     getter paymentManager
 [Worker]     getter pushManager
 [Worker]     getter scope
 [Worker]     getter sync
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 503ee3594..570198f97 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -4403,6 +4403,21 @@
     getter sortingCode
     method constructor
     method toJSON
+interface PaymentInstruments
+    attribute @@toStringTag
+    method clear
+    method constructor
+    method delete
+    method get
+    method has
+    method keys
+    method set
+interface PaymentManager
+    attribute @@toStringTag
+    getter instruments
+    getter userHint
+    method constructor
+    setter userHint
 interface PaymentRequest : EventTarget
     attribute @@toStringTag
     getter id
@@ -6228,6 +6243,7 @@
     getter installing
     getter navigationPreload
     getter onupdatefound
+    getter paymentManager
     getter pushManager
     getter scope
     getter sync
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index c5dc48f..f70e9c1 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -760,6 +760,15 @@
 [Worker]     method moveTo
 [Worker]     method quadraticCurveTo
 [Worker]     method rect
+[Worker] interface PaymentInstruments
+[Worker]     attribute @@toStringTag
+[Worker]     method clear
+[Worker]     method constructor
+[Worker]     method delete
+[Worker]     method get
+[Worker]     method has
+[Worker]     method keys
+[Worker]     method set
 [Worker] interface Performance : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onresourcetimingbufferfull
@@ -926,6 +935,7 @@
 [Worker]     getter installing
 [Worker]     getter navigationPreload
 [Worker]     getter onupdatefound
+[Worker]     getter paymentManager
 [Worker]     getter pushManager
 [Worker]     getter scope
 [Worker]     getter sync
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-visual-update-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-visual-update-expected.html
deleted file mode 100644
index d544dcba1..0000000
--- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-visual-update-expected.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<style>
-#box {
-  width: 100px;
-  height: 100px;
-  background-color: #00ff00;
-  transform: translate(0, 100px);
-  opacity: 0.5;
-  will-change: transform; /* force compositing */
-}
-
-#covered {
-  width: 100px;
-  height: 100px;
-  background-color: #ff8080;
-}
-</style>
-
-<div id="box"></div>
-<div id="covered"></div>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-animate-expected.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-animate-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate-expected.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-animate.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-animate.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-animate.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-registration-expected.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-registration-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-registration-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-registration-expected.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-registration.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-registration.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-registration.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-registration.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-with-options-expected.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-with-options-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-with-options-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-with-options-expected.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-with-options.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-with-options.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-animator-with-options.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animator-with-options.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-display-none-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-display-none-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-display-none-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-display-none-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-display-none.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-display-none.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-display-none.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-display-none.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dispose.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-dispose.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dispose.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-dispose.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dynamic-update-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-dynamic-update-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dynamic-update-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-dynamic-update-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dynamic-update.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-dynamic-update.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dynamic-update.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-dynamic-update.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-compositable-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-compositable-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-compositable-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-compositable-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-compositable.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-compositable.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-compositable.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-compositable.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-scrollable-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-scrollable-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-scrollable-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-scrollable-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-scrollable.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-scrollable.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-non-scrollable.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-non-scrollable.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-overflow-hidden-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-overflow-hidden-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-overflow-hidden-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-overflow-hidden-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-overflow-hidden.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-overflow-hidden.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-overflow-hidden.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-overflow-hidden.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-root-scroller-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-root-scroller-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-root-scroller-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-root-scroller-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-root-scroller.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-root-scroller.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-root-scroller.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline-root-scroller.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/scroll-timeline.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/visual-update-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/visual-update-expected.html
index 50c1a0c7..d544dcba1 100644
--- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/visual-update-expected.html
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/visual-update-expected.html
@@ -1,46 +1,20 @@
 <!DOCTYPE html>
-<!--
-Tests that a change from the worker produces a visual update.
--->
 <style>
 #box {
   width: 100px;
   height: 100px;
-  /* A composited DIV background is clipped differently from a non-composited
-     one. This causes the box to be composited in both cases
-     TODO(majidvp): fix this mismatch between CC and blink rendering
-  */
-  backface-visibility: hidden;
-}
-
-#covered, #green {
-  width: 85px;
-  height: 85px;
-}
-
-#box, #covered {
-  background-color: #ff8080;
-  overflow: auto;
-}
-
-#green {
-  position: relative;
-  left: 100px;
-  top: 100px;
   background-color: #00ff00;
+  transform: translate(0, 100px);
+  opacity: 0.5;
+  will-change: transform; /* force compositing */
 }
 
+#covered {
+  width: 100px;
+  height: 100px;
+  background-color: #ff8080;
+}
 </style>
 
-<div id="box">
-    <div id="green"></div>
-</div>
+<div id="box"></div>
 <div id="covered"></div>
-
-<script>
-var box = document.getElementById('box');
-box.style.transform = 'translate(0, 100px)';
-box.style.opacity = 0.5;
-box.scrollLeft = 100;
-box.scrollTop = 100;
-</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-visual-update.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/visual-update.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-visual-update.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/visual-update.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-start-delay-expected.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-start-delay-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-start-delay-expected.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-start-delay-expected.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-start-delay.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-start-delay.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-start-delay.html
rename to third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-start-delay.html
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/lifecycle/README.txt b/third_party/WebKit/LayoutTests/virtual/threaded/lifecycle/README.txt
new file mode 100644
index 0000000..9322dac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/lifecycle/README.txt
@@ -0,0 +1 @@
+# This suite runs only the tests in this directory with --enable-threaded-compositing
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn
index 196f5bed..8bee93c 100644
--- a/third_party/android_deps/BUILD.gn
+++ b/third_party/android_deps/BUILD.gn
@@ -444,6 +444,12 @@
   ]
 }
 
+android_aar_prebuilt("com_google_android_play_core_java") {
+  aar_path = "libs/com_google_android_play_core/core-1.3.0.aar"
+  info_path =
+      "libs/com_google_android_play_core/com_google_android_play_core.info"
+}
+
 java_prebuilt("android_arch_core_common_java") {
   jar_path = "libs/android_arch_core_common/common-1.0.0.jar"
   output_name = "android_arch_core_common"
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json
index 464be0d..9e497c1 100644
--- a/third_party/android_deps/additional_readme_paths.json
+++ b/third_party/android_deps/additional_readme_paths.json
@@ -39,5 +39,6 @@
     "libs/com_google_android_gms_play_services_location",
     "libs/com_google_android_gms_play_services_tasks",
     "libs/com_google_android_gms_play_services_vision",
-    "libs/com_google_android_gms_play_services_vision_common"
+    "libs/com_google_android_gms_play_services_vision_common",
+    "libs/com_google_android_play_core"
 ]
diff --git a/third_party/android_deps/libs/com_google_android_play_core/OWNERS b/third_party/android_deps/libs/com_google_android_play_core/OWNERS
new file mode 100644
index 0000000..7b571d97
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_android_play_core/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
\ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_android_play_core/README.chromium b/third_party/android_deps/libs/com_google_android_play_core/README.chromium
new file mode 100644
index 0000000..db38ef1
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_android_play_core/README.chromium
@@ -0,0 +1,13 @@
+Name: Google Android Play Core
+Short Name: core
+URL: https://developer.android.com/guide/app-bundle/playcore
+Version: 1.3.0
+License: Android Software Development Kit License
+License File: /third_party/android_deps/Android_SDK_License-December_9_2016.txt
+Security Critical: yes
+
+Description:
+
+
+Local Modifications:
+No modifications.
diff --git a/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml b/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml
new file mode 100644
index 0000000..bea7177ac
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_android_play_core/cipd.yaml
@@ -0,0 +1,10 @@
+# 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.
+
+# To create CIPD package run the following command.
+# cipd create --pkg-def cipd.yaml -tag version:1.3.0-cr0
+package: chromium/third_party/android_deps/libs/com_google_android_play_core
+description: Google Android Play Core
+data:
+- file: core-1.3.0.aar
diff --git a/third_party/android_deps/libs/com_google_android_play_core/com_google_android_play_core.info b/third_party/android_deps/libs/com_google_android_play_core/com_google_android_play_core.info
new file mode 100644
index 0000000..a2ebd4a8
--- /dev/null
+++ b/third_party/android_deps/libs/com_google_android_play_core/com_google_android_play_core.info
@@ -0,0 +1,13 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = [  ]
+assets = [  ]
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = false
+has_r_text_file = false
+is_manifest_empty = true
+resources = [  ]
+subjar_tuples = [  ]
+subjars = [  ]
diff --git a/third_party/blink/perf_tests/bindings/resources/structured-clone-perf-test.js b/third_party/blink/perf_tests/bindings/resources/structured-clone-perf-test.js
index 0efc05701..3541af8 100644
--- a/third_party/blink/perf_tests/bindings/resources/structured-clone-perf-test.js
+++ b/third_party/blink/perf_tests/bindings/resources/structured-clone-perf-test.js
@@ -1,32 +1,18 @@
 const StructuredClonePerfTestRunner = (function() {
-  function pingPong(data, useWorker) {
+  function pingPong(data) {
     return new Promise((resolve, reject) => {
-      let beginSerialize, endSerialize, beginDeserialize;
-      if (useWorker) {
-        worker.addEventListener('message', function listener(e) {
-          try {
-            e.data;  // Force deserialization.
-            const endDeserialize = PerfTestRunner.now();
-            worker.removeEventListener('message', listener);
-            resolve([endSerialize - beginSerialize, endDeserialize - beginDeserialize]);
-          } catch (err) { reject(err); }
-        });
-      } else {
-        window.addEventListener('message', function listener(e) {
-          try {
-            e.data;  // Force deserialization.
-            const endDeserialize = PerfTestRunner.now();
-            window.removeEventListener('message', listener);
-            resolve([endSerialize - beginSerialize, endDeserialize - beginDeserialize]);
-          } catch (err) { reject(err); }
-        });
-      }
+      let beginSerialize, endSerialize, beginDeserialize, endDeserialize;
+      window.addEventListener('message', function listener(e) {
+        try {
+          e.data;  // Force deserialization.
+          endDeserialize = PerfTestRunner.now();
+          window.removeEventListener('message', listener);
+          resolve([endSerialize - beginSerialize, endDeserialize - beginDeserialize]);
+        } catch (err) { reject(err); }
+      });
+
       beginSerialize = PerfTestRunner.now();
-      if (useWorker) {
-        worker.postMessage(data);
-      } else {
-        window.postMessage(data, '*');
-      }
+      window.postMessage(data, '*');
       beginDeserialize = endSerialize = PerfTestRunner.now();
       // While Chrome does the deserialize lazily when e.data is read, this
       // isn't portable, so it's more fair to measure from when the message is
@@ -37,9 +23,6 @@
   return {
     measureTimeAsync(test) {
       let isDone = false;
-      if (test.worker) {
-        worker = new Worker('resources/worker-structured-clone.js');
-      }
       PerfTestRunner.startMeasureValuesAsync({
         description: test.description,
         unit: 'ms',
@@ -50,7 +33,7 @@
       });
 
       function pingPongUntilDone() {
-        pingPong(test.data, test.worker).then(([serializeTime, deserializeTime]) => {
+        pingPong(test.data).then(([serializeTime, deserializeTime]) => {
           console.log([serializeTime, deserializeTime]);
           if (test.measure === 'serialize')
             PerfTestRunner.measureValueAsync(serializeTime);
diff --git a/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js b/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js
new file mode 100644
index 0000000..91af53d
--- /dev/null
+++ b/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js
@@ -0,0 +1,52 @@
+const WorkerStructuredClonePerfTestRunner = (function() {
+  function pingPong(data) {
+    return new Promise((resolve, reject) => {
+      let beginSerialize, endSerialize, beginDeserialize, endDeserialize;
+      worker.addEventListener('message', function listener(e) {
+        try {
+          e.data;  // Force deserialization.
+          endDeserialize = PerfTestRunner.now();
+          worker.removeEventListener('message', listener);
+          // TODO(panicker): Deserialize is currently including worker hop and
+          // not accurate. Report this from the worker.
+          resolve([endSerialize - beginSerialize, endDeserialize - beginDeserialize,
+                  endDeserialize - beginSerialize]);
+        } catch (err) { reject(err); }
+      });
+      beginSerialize = PerfTestRunner.now();
+      worker.postMessage(data);
+      beginDeserialize = endSerialize = PerfTestRunner.now();
+      // While Chrome does the deserialize lazily when e.data is read, this
+      // isn't portable, so it's more fair to measure from when the message is
+      // posted.
+    });
+  }
+
+  return {
+    measureTimeAsync(test) {
+      let isDone = false;
+      worker = new Worker('resources/worker-structured-clone.js');
+      PerfTestRunner.startMeasureValuesAsync({
+        description: test.description,
+        unit: 'ms',
+        warmUpCount: test.warmUpCount || 10,
+        iterationCount: test.iterationCount || 250,
+        done() { isDone = true; },
+        run: pingPongUntilDone,
+      });
+
+      function pingPongUntilDone() {
+        pingPong(test.data).then(([serializeTime, deserializeTime, totalTime]) => {
+          console.log([serializeTime, deserializeTime, totalTime]);
+          if (test.measure === 'serialize')
+            PerfTestRunner.measureValueAsync(serializeTime);
+          else if (test.measure === 'deserialize')
+            PerfTestRunner.measureValueAsync(deserializeTime);
+          else if (test.measure === 'roundtrip')
+            PerfTestRunner.measureValueAsync(totalTime);
+          if (!isDone) pingPongUntilDone();
+        });
+      }
+    },
+  };
+})();
diff --git a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-roundtrip.html b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-roundtrip.html
new file mode 100644
index 0000000..2a59ae6
--- /dev/null
+++ b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-roundtrip.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<body>
+<script src="../resources/runner.js"></script>
+<script src="resources/worker-structured-clone-perf-test.js"></script>
+<script>
+WorkerStructuredClonePerfTestRunner.measureTimeAsync({
+  description: "Measures performance of worker round-trip with structured clone, for JSON-like data.",
+  data: JSON.parse(PerfTestRunner.loadFile("resources/blink-dev.json")),
+  measure: "roundtrip",
+});
+</script>
+</body>
diff --git a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
index 42d95c5..7597623 100644
--- a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
+++ b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
@@ -1,13 +1,12 @@
 <!DOCTYPE html>
 <body>
 <script src="../resources/runner.js"></script>
-<script src="resources/structured-clone-perf-test.js"></script>
+<script src="resources/worker-structured-clone-perf-test.js"></script>
 <script>
-StructuredClonePerfTestRunner.measureTimeAsync({
+WorkerStructuredClonePerfTestRunner.measureTimeAsync({
   description: "Measures performance of serializing JSON-like data.",
   data: JSON.parse(PerfTestRunner.loadFile("resources/blink-dev.json")),
     measure: "serialize",
-    worker: true,
 });
 </script>
 </body>
diff --git a/third_party/blink/public/platform/web_cors.h b/third_party/blink/public/platform/web_cors.h
index a24e284..31b92009 100644
--- a/third_party/blink/public/platform/web_cors.h
+++ b/third_party/blink/public/platform/web_cors.h
@@ -39,23 +39,9 @@
 namespace blink {
 
 class WebURLResponse;
-class WebSecurityOrigin;
-struct ResourceLoaderOptions;
 
 namespace WebCORS {
 
-// TODO(toyoshim): Using platform/loader/fetch/ResourceLoaderOptions violates
-// the DEPS rule. This will be fixed soon by making HandleRedirect() not
-// depending on ResourceLoaderOptions.
-BLINK_PLATFORM_EXPORT base::Optional<network::CORSErrorStatus> HandleRedirect(
-    WebSecurityOrigin&,
-    WebURLRequest&,
-    const WebURL,
-    const int redirect_response_status_code,
-    const WebHTTPHeaderMap&,
-    network::mojom::FetchCredentialsMode,
-    ResourceLoaderOptions&);
-
 BLINK_PLATFORM_EXPORT WebHTTPHeaderSet
 ExtractCorsExposedHeaderNamesList(network::mojom::FetchCredentialsMode,
                                   const WebURLResponse&);
diff --git a/third_party/blink/public/platform/web_gamepad_listener.h b/third_party/blink/public/platform/web_gamepad_listener.h
index ae68610..0586c0b 100644
--- a/third_party/blink/public/platform/web_gamepad_listener.h
+++ b/third_party/blink/public/platform/web_gamepad_listener.h
@@ -15,8 +15,22 @@
 
 class WebGamepadListener : public WebPlatformEventListener {
  public:
-  virtual void DidConnectGamepad(unsigned index, const device::Gamepad&) = 0;
-  virtual void DidDisconnectGamepad(unsigned index, const device::Gamepad&) = 0;
+  // Called when a gamepad is connected. |index| is the index of the gamepad in
+  // the gamepad array, and |gamepad| is a reference to the connected gamepad.
+  virtual void DidConnectGamepad(uint32_t index,
+                                 const device::Gamepad& gamepad) = 0;
+
+  // Called when a gamepad is disconnected. |index| is the former index of the
+  // gamepad in the gamepad array, and |gamepad| is a reference to the
+  // connected gamepad.
+  virtual void DidDisconnectGamepad(uint32_t index,
+                                    const device::Gamepad& gamepad) = 0;
+
+  // Called when a button or axis is changed on a connected gamepad. |index| is
+  // the index of the gamepad in the gamepad array, and |gamepad| is a reference
+  // to the gamepad.
+  virtual void ButtonOrAxisDidChange(uint32_t index,
+                                     const device::Gamepad& gamepad) = 0;
 
  protected:
   ~WebGamepadListener() override = default;
diff --git a/third_party/blink/public/platform/web_rtc_rtp_receiver.h b/third_party/blink/public/platform/web_rtc_rtp_receiver.h
index 36accec0..de7375e8 100644
--- a/third_party/blink/public/platform/web_rtc_rtp_receiver.h
+++ b/third_party/blink/public/platform/web_rtc_rtp_receiver.h
@@ -24,6 +24,7 @@
  public:
   virtual ~WebRTCRtpReceiver();
 
+  virtual std::unique_ptr<WebRTCRtpReceiver> ShallowCopy() const = 0;
   // Two |WebRTCRtpReceiver|s referencing the same WebRTC-layer receiver have
   // the same |id|.
   virtual uintptr_t Id() const = 0;
diff --git a/third_party/blink/public/platform/web_rtc_rtp_sender.h b/third_party/blink/public/platform/web_rtc_rtp_sender.h
index dbf7ac96..a2bcd8b 100644
--- a/third_party/blink/public/platform/web_rtc_rtp_sender.h
+++ b/third_party/blink/public/platform/web_rtc_rtp_sender.h
@@ -23,6 +23,7 @@
 class BLINK_PLATFORM_EXPORT WebRTCRtpSender {
  public:
   virtual ~WebRTCRtpSender();
+  virtual std::unique_ptr<WebRTCRtpSender> ShallowCopy() const = 0;
 
   // Two |WebRTCRtpSender|s referencing the same WebRTC-layer sender have the
   // same |id|. IDs are guaranteed to be unique amongst senders but they are
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 2517f97..380ca3f6 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -72,6 +72,7 @@
 
   // WebWidget overrides.
   using WebWidget::Close;
+  using WebWidget::LifecycleUpdate;
   using WebWidget::Size;
   using WebWidget::Resize;
   using WebWidget::ResizeVisualViewport;
@@ -79,6 +80,7 @@
   using WebWidget::DidExitFullscreen;
   using WebWidget::BeginFrame;
   using WebWidget::UpdateAllLifecyclePhases;
+  using WebWidget::UpdateLifecycle;
   using WebWidget::PaintContent;
   using WebWidget::LayoutAndPaintAsync;
   using WebWidget::CompositeAndReadbackAsync;
@@ -266,7 +268,8 @@
   // Returns the "preferred" contents size, defined as the preferred minimum
   // width of the main document's contents and the minimum height required to
   // display the main document without scrollbars.  The returned size has the
-  // page zoom factor applied.
+  // page zoom factor applied. The lifecycle must be updated to at least layout
+  // before calling this (see: |UpdateLifecycle|).
   virtual WebSize ContentsPreferredMinimumSize() = 0;
 
   // Sets the display mode of the web app.
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h
index ade50b6..069c531 100644
--- a/third_party/blink/public/web/web_widget.h
+++ b/third_party/blink/public/web/web_widget.h
@@ -92,10 +92,10 @@
   // and it may result in calls to WebWidgetClient::didInvalidateRect.
   virtual void UpdateAllLifecyclePhases() { UpdateLifecycle(); }
 
-  // Selectively runs all lifecycle phases or all phases excluding paint. The
-  // latter can be used to trigger side effects of updating layout and
-  // animations if painting is not required.
-  enum class LifecycleUpdate { kPrePaint, kAll };
+  // By default, all phases are updated by |UpdateLifecycle| (e.g., style,
+  // layout, prepaint, paint, etc. See: document_lifecycle.h). |LifecycleUpdate|
+  // can be used to only update to a specific lifecycle phase.
+  enum class LifecycleUpdate { kLayout, kPrePaint, kAll };
   virtual void UpdateLifecycle(
       LifecycleUpdate requested_update = LifecycleUpdate::kAll) {}
 
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index c49b31b2..d07f8140 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -150,8 +150,6 @@
                     "core/v8/v8_v0_custom_element_lifecycle_callbacks.h",
                     "core/v8/v8_wasm_response_extensions.cc",
                     "core/v8/v8_wasm_response_extensions.h",
-                    "core/v8/v8_worker_or_worklet_event_listener.cc",
-                    "core/v8/v8_worker_or_worklet_event_listener.h",
                     "core/v8/window_proxy.cc",
                     "core/v8/window_proxy.h",
                     "core/v8/window_proxy_manager.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.cc b/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.cc
index 99611d9..f7acae63 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.cc
@@ -114,9 +114,6 @@
 
 void V8AbstractEventListener::HandleEvent(ScriptState* script_state,
                                           Event* event) {
-  if (!script_state->ContextIsValid())
-    return;
-
   ScriptState::Scope scope(script_state);
 
   // Get the V8 wrapper for the event object.
@@ -215,14 +212,15 @@
         ToBeforeUnloadEvent(event)->setReturnValue(string_return_value);
       }
     }
-  } else if (ShouldPreventDefault(return_value) &&
+  } else if (ShouldPreventDefault(return_value, event) &&
              event->type() != EventTypeNames::beforeunload) {
     event->preventDefault();
   }
 }
 
 bool V8AbstractEventListener::ShouldPreventDefault(
-    v8::Local<v8::Value> return_value) {
+    v8::Local<v8::Value> return_value,
+    Event*) {
   // Prevent default action if the return value is false in accord with the spec
   // http://www.w3.org/TR/html5/webappapis.html#event-handler-attributes
   return return_value->IsBoolean() && !return_value.As<v8::Boolean>()->Value();
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.h b/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.h
index d915954..54e5947 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_abstract_event_listener.h
@@ -132,7 +132,7 @@
   virtual v8::Local<v8::Value>
   CallListenerFunction(ScriptState*, v8::Local<v8::Value> jsevent, Event*) = 0;
 
-  virtual bool ShouldPreventDefault(v8::Local<v8::Value> return_value);
+  virtual bool ShouldPreventDefault(v8::Local<v8::Value> return_value, Event*);
 
   static void WrapperCleared(
       const v8::WeakCallbackInfo<V8AbstractEventListener>&);
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_error_handler.cc b/third_party/blink/renderer/bindings/core/v8/v8_error_handler.cc
index 005c55c1..9035a82 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_error_handler.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_error_handler.cc
@@ -130,8 +130,15 @@
   return error;
 }
 
-bool V8ErrorHandler::ShouldPreventDefault(v8::Local<v8::Value> return_value) {
-  return return_value->IsBoolean() && return_value.As<v8::Boolean>()->Value();
+bool V8ErrorHandler::ShouldPreventDefault(v8::Local<v8::Value> return_value,
+                                          Event* event) {
+  // Special event handling should be done here according to HTML Standard:
+  // https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm
+  // We do not need to check current target of event because it must be window
+  // or worker on calling this method.
+  if (event->HasInterface(EventNames::ErrorEvent) && event->type() == "error")
+    return return_value->IsBoolean() && return_value.As<v8::Boolean>()->Value();
+  return return_value->IsBoolean() && !return_value.As<v8::Boolean>()->Value();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_error_handler.h b/third_party/blink/renderer/bindings/core/v8/v8_error_handler.h
index a5a00fa..843113c 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_error_handler.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_error_handler.h
@@ -65,7 +65,7 @@
   v8::Local<v8::Value> CallListenerFunction(ScriptState*,
                                             v8::Local<v8::Value>,
                                             Event*) override;
-  bool ShouldPreventDefault(v8::Local<v8::Value> return_value) override;
+  bool ShouldPreventDefault(v8::Local<v8::Value> return_value, Event*) override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_event_listener.cc b/third_party/blink/renderer/bindings/core/v8/v8_event_listener.cc
index 9770f7f..1fa1f7d 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_event_listener.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_event_listener.cc
@@ -97,12 +97,6 @@
 
   ExecutionContext* execution_context =
       ToExecutionContext(script_state->GetContext());
-  if (!execution_context->IsDocument())
-    return v8::Local<v8::Value>();
-
-  LocalFrame* frame = ToDocument(execution_context)->GetFrame();
-  if (!frame)
-    return v8::Local<v8::Value>();
 
   // TODO(jochen): Consider moving this check into canExecuteScripts.
   // http://crbug.com/608641
@@ -112,7 +106,7 @@
 
   v8::Local<v8::Value> parameters[1] = {js_event};
   v8::Local<v8::Value> result;
-  if (!V8ScriptRunner::CallFunction(handler_function, frame->GetDocument(),
+  if (!V8ScriptRunner::CallFunction(handler_function, execution_context,
                                     receiver, base::size(parameters),
                                     parameters, script_state->GetIsolate())
            .ToLocal(&result))
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc b/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
index cee9f1e..ddabd2e9 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_error_handler.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_event_listener.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_window.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 
 namespace blink {
@@ -80,11 +79,8 @@
   return GetEventListenerInternal<V8AbstractEventListener>(
       script_state, object, listener_property, lookup,
       [object, is_attribute, script_state, listener_property]() {
-        return script_state->World().IsWorkerWorld()
-                   ? V8WorkerOrWorkletEventListener::Create(
-                         object, is_attribute, script_state, listener_property)
-                   : V8EventListener::Create(object, is_attribute, script_state,
-                                             listener_property);
+        return V8EventListener::Create(object, is_attribute, script_state,
+                                       listener_property);
       });
 }
 
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.cc b/third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.cc
deleted file mode 100644
index 79cff5ba..0000000
--- a/third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_event.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_event_target.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
-#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
-#include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
-
-namespace blink {
-
-V8WorkerOrWorkletEventListener::V8WorkerOrWorkletEventListener(
-    bool is_inline,
-    ScriptState* script_state)
-    : V8EventListener(is_inline, script_state) {}
-
-v8::Local<v8::Value> V8WorkerOrWorkletEventListener::CallListenerFunction(
-    ScriptState* script_state,
-    v8::Local<v8::Value> js_event,
-    Event* event) {
-  DCHECK(!js_event.IsEmpty());
-  v8::Local<v8::Function> handler_function = GetListenerFunction(script_state);
-  v8::Local<v8::Object> receiver = GetReceiverObject(script_state, event);
-  if (handler_function.IsEmpty() || receiver.IsEmpty())
-    return v8::Local<v8::Value>();
-
-  v8::Local<v8::Value> parameters[1] = {js_event};
-  v8::MaybeLocal<v8::Value> maybe_result = V8ScriptRunner::CallFunction(
-      handler_function, ToExecutionContext(script_state->GetContext()),
-      receiver, base::size(parameters), parameters, GetIsolate());
-
-  v8::Local<v8::Value> result;
-  if (!maybe_result.ToLocal(&result))
-    return v8::Local<v8::Value>();
-  return result;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.h b/third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.h
deleted file mode 100644
index 59a9d23c..0000000
--- a/third_party/blink/renderer/bindings/core/v8/v8_worker_or_worklet_event_listener.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_WORKER_OR_WORKLET_EVENT_LISTENER_H_
-#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_WORKER_OR_WORKLET_EVENT_LISTENER_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-class Event;
-
-class V8WorkerOrWorkletEventListener final : public V8EventListener {
- public:
-  static V8WorkerOrWorkletEventListener* Create(
-      v8::Local<v8::Object> listener,
-      bool is_inline,
-      ScriptState* script_state,
-      const V8PrivateProperty::Symbol& property) {
-    V8WorkerOrWorkletEventListener* event_listener =
-        new V8WorkerOrWorkletEventListener(is_inline, script_state);
-    event_listener->SetListenerObject(script_state, listener, property);
-    return event_listener;
-  }
-
- protected:
-  V8WorkerOrWorkletEventListener(bool is_inline, ScriptState*);
-
- private:
-  v8::Local<v8::Value> CallListenerFunction(ScriptState*,
-                                            v8::Local<v8::Value>,
-                                            Event*) override;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_V8_WORKER_OR_WORKLET_EVENT_LISTENER_H_
diff --git a/third_party/blink/renderer/bindings/scripts/v8_callback_function.py b/third_party/blink/renderer/bindings/scripts/v8_callback_function.py
index 8b9288b..4a46b5c 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_callback_function.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_callback_function.py
@@ -85,13 +85,21 @@
                 creation_context='argument_creation_context'),
             'enum_type': idl_type.enum_type,
             'enum_values': idl_type.enum_values,
+            'is_variadic': argument.is_variadic,
             'name': argument.name,
             'v8_name': 'v8_%s' % argument.name,
         }
 
+    def argument_cpp_type(argument):
+        cpp_type = argument.idl_type.callback_cpp_type
+        if argument.is_variadic:
+            return 'const Vector<%s>&' % cpp_type
+        else:
+            return cpp_type
+
     argument_declarations = ['ScriptWrappable* callback_this_value']
     argument_declarations.extend(
-        '%s %s' % (argument.idl_type.callback_cpp_type, argument.name)
+        '%s %s' % (argument_cpp_type(argument), argument.name)
         for argument in arguments)
     return {
         'argument_declarations': argument_declarations,
diff --git a/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl b/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
index b4e90663..f40221f 100644
--- a/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
@@ -89,11 +89,29 @@
   v8::Local<v8::Object> argument_creation_context =
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
-  {% for argument in arguments %}
+  {% set has_variadic_argument = arguments[-1].is_variadic %}
+  {% set non_variadic_arguments = arguments | rejectattr('is_variadic') | list %}
+  {% set variadic_argument = arguments[-1] if has_variadic_argument else None %}
+  {% set arguments_length = '%d + %s.size()' % (non_variadic_arguments|length, variadic_argument.name) if has_variadic_argument else non_variadic_arguments|length %}
+  {% for argument in non_variadic_arguments %}
   v8::Local<v8::Value> {{argument.v8_name}} = {{argument.cpp_value_to_v8_value}};
   {% endfor %}
-  v8::Local<v8::Value> argv[] = { {{arguments | join(', ', 'v8_name')}} };
-  {% else %}
+  {% if has_variadic_argument %}
+  const int argc = {{arguments_length}};
+  v8::Local<v8::Value> argv[argc];
+  {% for argument in non_variadic_arguments %}
+  argv[{{loop.index0}}] = {{argument.v8_name}};
+  {% endfor %}
+  for (wtf_size_t i = 0; i < {{variadic_argument.name}}.size(); ++i) {
+    argv[{{non_variadic_arguments|length}} + i] = ToV8({{variadic_argument.name}}[i], argument_creation_context, GetIsolate());
+  }
+  {% else %}{# if has_variadic_argument #}
+  constexpr int argc = {{arguments_length}};
+  v8::Local<v8::Value> argv[] = { {{non_variadic_arguments | join(', ', 'v8_name')}} };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
+  {% endif %}
+  {% else %}{# if arguments #}
+  const int argc = 0;
   {# Zero-length arrays are ill-formed in C++. #}
   v8::Local<v8::Value> *argv = nullptr;
   {% endif %}
@@ -104,7 +122,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          {{arguments | length}},
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl
index 10edce1..f7ca558 100644
--- a/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl
+++ b/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl
@@ -4,6 +4,9 @@
 
 callback VoidCallbackFunction = void ();
 callback AnyCallbackFunctionOptionalAnyArg = any (optional any optionalAnyArg);
+// |AnyCallbackFunctionVariadicAnyArgs| is the same as Function.
+// https://heycam.github.io/webidl/#Function
+callback AnyCallbackFunctionVariadicAnyArgs = any (any... arguments);
 callback LongCallbackFunction = long (long num1, long num2);
 
 // Following callback functions are to be generated as expected.
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
index 5abe124..8e197ed1 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
@@ -78,7 +78,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_optionalAnyArg = optionalAnyArg.V8Value();
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_optionalAnyArg };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -86,7 +88,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
new file mode 100644
index 0000000..83940c5f
--- /dev/null
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
@@ -0,0 +1,117 @@
+// 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.
+
+// This file has been auto-generated from the Jinja2 template
+// third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
+// by the script code_generator_v8.py.
+// DO NOT MODIFY!
+
+// clang-format off
+
+#include "third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+const char* V8AnyCallbackFunctionVariadicAnyArgs::NameInHeapSnapshot() const {
+  return "V8AnyCallbackFunctionVariadicAnyArgs";
+}
+
+v8::Maybe<ScriptValue> V8AnyCallbackFunctionVariadicAnyArgs::Invoke(ScriptWrappable* callback_this_value, const Vector<ScriptValue>& arguments) {
+  // This function implements "invoke" algorithm defined in
+  // "3.10. Invoking callback functions".
+  // https://heycam.github.io/webidl/#es-invoking-callback-functions
+
+  if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState(),
+                                  IncumbentScriptState())) {
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    CHECK(!CallbackFunction().IsEmpty());
+    v8::Context::Scope context_scope(CallbackFunction()->CreationContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "AnyCallbackFunctionVariadicAnyArgs",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<ScriptValue>();
+  }
+
+  // step 4. If ! IsCallable(F) is false:
+  //
+  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
+  // case.
+#if DCHECK_IS_ON()
+  {
+    v8::HandleScope handle_scope(GetIsolate());
+    DCHECK(CallbackFunction()->IsFunction());
+  }
+#endif
+
+  // step 8. Prepare to run script with relevant settings.
+  ScriptState::Scope callback_relevant_context_scope(
+      CallbackRelevantScriptState());
+  // step 9. Prepare to run a callback with stored settings.
+  v8::Context::BackupIncumbentScope backup_incumbent_scope(
+      IncumbentScriptState()->GetContext());
+
+  v8::Local<v8::Value> this_arg = ToV8(callback_this_value,
+                                       CallbackRelevantScriptState());
+
+  // step 10. Let esArgs be the result of converting args to an ECMAScript
+  //   arguments list. If this throws an exception, set completion to the
+  //   completion value representing the thrown exception and jump to the step
+  //   labeled return.
+  v8::Local<v8::Object> argument_creation_context =
+      CallbackRelevantScriptState()->GetContext()->Global();
+  ALLOW_UNUSED_LOCAL(argument_creation_context);
+  const int argc = 0 + arguments.size();
+  v8::Local<v8::Value> argv[argc];
+  for (wtf_size_t i = 0; i < arguments.size(); ++i) {
+    argv[0 + i] = ToV8(arguments[i], argument_creation_context, GetIsolate());
+  }
+
+  // step 11. Let callResult be Call(X, thisArg, esArgs).
+  v8::Local<v8::Value> call_result;
+  if (!V8ScriptRunner::CallFunction(
+          CallbackFunction(),
+          ExecutionContext::From(CallbackRelevantScriptState()),
+          this_arg,
+          argc,
+          argv,
+          GetIsolate()).ToLocal(&call_result)) {
+    // step 12. If callResult is an abrupt completion, set completion to
+    //   callResult and jump to the step labeled return.
+    return v8::Nothing<ScriptValue>();
+  }
+
+  // step 13. Set completion to the result of converting callResult.[[Value]] to
+  //   an IDL value of the same type as the operation's return type.
+  {
+    ExceptionState exceptionState(GetIsolate(),
+                                  ExceptionState::kExecutionContext,
+                                  "AnyCallbackFunctionVariadicAnyArgs",
+                                  "invoke");
+    ScriptValue native_result = ScriptValue(ScriptState::Current(GetIsolate()), call_result);
+    return v8::Just<ScriptValue>(native_result);
+  }
+}
+
+v8::Maybe<ScriptValue> V8PersistentCallbackFunction<V8AnyCallbackFunctionVariadicAnyArgs>::Invoke(ScriptWrappable* callback_this_value, const Vector<ScriptValue>& arguments) {
+  return Proxy()->Invoke(
+      callback_this_value, arguments);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.h b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.h
new file mode 100644
index 0000000..b3d6bb9
--- /dev/null
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.h
@@ -0,0 +1,76 @@
+// 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.
+
+// This file has been auto-generated from the Jinja2 template
+// third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
+// by the script code_generator_v8.py.
+// DO NOT MODIFY!
+
+// clang-format off
+
+#ifndef V8AnyCallbackFunctionVariadicAnyArgs_h
+#define V8AnyCallbackFunctionVariadicAnyArgs_h
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
+
+namespace blink {
+
+class ScriptWrappable;
+
+class CORE_EXPORT V8AnyCallbackFunctionVariadicAnyArgs final : public CallbackFunctionBase {
+ public:
+  static V8AnyCallbackFunctionVariadicAnyArgs* Create(v8::Local<v8::Function> callback_function) {
+    return new V8AnyCallbackFunctionVariadicAnyArgs(callback_function);
+  }
+
+  ~V8AnyCallbackFunctionVariadicAnyArgs() override = default;
+
+  // NameClient overrides:
+  const char* NameInHeapSnapshot() const override;
+
+  // Performs "invoke".
+  // https://heycam.github.io/webidl/#es-invoking-callback-functions
+  v8::Maybe<ScriptValue> Invoke(ScriptWrappable* callback_this_value, const Vector<ScriptValue>& arguments) WARN_UNUSED_RESULT;
+
+ private:
+  explicit V8AnyCallbackFunctionVariadicAnyArgs(v8::Local<v8::Function> callback_function)
+      : CallbackFunctionBase(callback_function) {}
+};
+
+template <>
+class V8PersistentCallbackFunction<V8AnyCallbackFunctionVariadicAnyArgs> final : public V8PersistentCallbackFunctionBase {
+  using V8CallbackFunction = V8AnyCallbackFunctionVariadicAnyArgs;
+
+ public:
+  ~V8PersistentCallbackFunction() override = default;
+
+  // Returns a wrapper-tracing version of this callback function.
+  V8CallbackFunction* ToNonV8Persistent() { return Proxy(); }
+
+  v8::Maybe<ScriptValue> Invoke(ScriptWrappable* callback_this_value, const Vector<ScriptValue>& arguments) WARN_UNUSED_RESULT;
+
+ private:
+  explicit V8PersistentCallbackFunction(V8CallbackFunction* callback_function)
+      : V8PersistentCallbackFunctionBase(callback_function) {}
+
+  V8CallbackFunction* Proxy() {
+    return As<V8CallbackFunction>();
+  }
+
+  template <typename V8CallbackFunction>
+  friend V8PersistentCallbackFunction<V8CallbackFunction>*
+  ToV8PersistentCallbackFunction(V8CallbackFunction*);
+};
+
+// V8AnyCallbackFunctionVariadicAnyArgs is designed to be used with wrapper-tracing.
+// As blink::Persistent does not perform wrapper-tracing, use of
+// |WrapPersistent| for callback functions is likely (if not always) misuse.
+// Thus, this code prohibits such a use case. The call sites should explicitly
+// use WrapPersistent(V8PersistentCallbackFunction<T>*).
+Persistent<V8AnyCallbackFunctionVariadicAnyArgs> WrapPersistent(V8AnyCallbackFunctionVariadicAnyArgs*) = delete;
+
+}  // namespace blink
+
+#endif  // V8AnyCallbackFunctionVariadicAnyArgs_h
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
index f97451f..5b74926 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
@@ -79,7 +79,9 @@
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_num1 = v8::Integer::New(GetIsolate(), num1);
   v8::Local<v8::Value> v8_num2 = v8::Integer::New(GetIsolate(), num2);
+  constexpr int argc = 2;
   v8::Local<v8::Value> argv[] = { v8_num1, v8_num2 };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -87,7 +89,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          2,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
index 2799ade..9bc2bf2 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
@@ -78,7 +78,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_arg = ToV8(arg, argument_creation_context, GetIsolate());
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_arg };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -86,7 +88,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
index c2f94e5..b0647919 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
@@ -73,6 +73,7 @@
   //   arguments list. If this throws an exception, set completion to the
   //   completion value representing the thrown exception and jump to the step
   //   labeled return.
+  const int argc = 0;
   v8::Local<v8::Value> *argv = nullptr;
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
@@ -81,7 +82,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          0,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
index 0cd2a62e..b3fc80e5 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
@@ -78,7 +78,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_arg = ToV8(arg, argument_creation_context, GetIsolate());
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_arg };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -86,7 +88,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
index 0b360a93..91f7884d 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
@@ -98,7 +98,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_arg = V8String(GetIsolate(), arg);
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_arg };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -106,7 +108,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
index 73b3f028..c8ad2c2 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
@@ -78,7 +78,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_divElement = ToV8(divElement, argument_creation_context, GetIsolate());
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_divElement };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -86,7 +88,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
index e3feafa..6f4a8fc1 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
@@ -79,7 +79,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_arg = ToV8(arg, argument_creation_context, GetIsolate());
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_arg };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -87,7 +89,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
index 5e8b6a6..00e11e9c 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
@@ -78,7 +78,9 @@
       CallbackRelevantScriptState()->GetContext()->Global();
   ALLOW_UNUSED_LOCAL(argument_creation_context);
   v8::Local<v8::Value> v8_arg = V8String(GetIsolate(), arg);
+  constexpr int argc = 1;
   v8::Local<v8::Value> argv[] = { v8_arg };
+  static_assert(static_cast<size_t>(argc) == base::size(argv), "size mismatch");
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
   v8::Local<v8::Value> call_result;
@@ -86,7 +88,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          1,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc b/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
index 93044fc..8a9b0e1 100644
--- a/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
+++ b/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
@@ -73,6 +73,7 @@
   //   arguments list. If this throws an exception, set completion to the
   //   completion value representing the thrown exception and jump to the step
   //   labeled return.
+  const int argc = 0;
   v8::Local<v8::Value> *argv = nullptr;
 
   // step 11. Let callResult be Call(X, thisArg, esArgs).
@@ -81,7 +82,7 @@
           CallbackFunction(),
           ExecutionContext::From(CallbackRelevantScriptState()),
           this_arg,
-          0,
+          argc,
           argv,
           GetIsolate()).ToLocal(&call_result)) {
     // step 12. If callResult is an abrupt completion, set completion to
diff --git a/third_party/blink/renderer/core/OWNERS b/third_party/blink/renderer/core/OWNERS
index cad509d..995cd607f 100644
--- a/third_party/blink/renderer/core/OWNERS
+++ b/third_party/blink/renderer/core/OWNERS
@@ -60,7 +60,6 @@
 robhogan@gmail.com
 schenney@chromium.org
 senorblanco@chromium.org
-sashab@chromium.org
 skobes@chromium.org
 svillar@igalia.com
 szager@chromium.org
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index cb2afa4..c1e5fcec 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -641,6 +641,7 @@
                     "intersection_observer/intersection_observer_init.idl",
                     "layout/custom/custom_layout_constraints_options.idl",
                     "layout/custom/fragment_result_options.idl",
+                    "messaging/post_message_options.idl",
                     "mojo/mojo_create_data_pipe_options.idl",
                     "mojo/mojo_create_data_pipe_result.idl",
                     "mojo/mojo_create_message_pipe_result.idl",
diff --git a/third_party/blink/renderer/core/css/CSSProperties.json5 b/third_party/blink/renderer/core/css/CSSProperties.json5
index 3fb4382..e52d3220 100644
--- a/third_party/blink/renderer/core/css/CSSProperties.json5
+++ b/third_party/blink/renderer/core/css/CSSProperties.json5
@@ -2420,7 +2420,6 @@
     {
       name: "overscroll-behavior-x",
       property_methods: ["CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSOverscrollBehavior",
       field_template: "keyword",
       keywords: ["auto", "contain", "none"],
       default_value: "auto",
@@ -2430,7 +2429,6 @@
     {
       name: "overscroll-behavior-y",
       property_methods: ["CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSOverscrollBehavior",
       field_template: "keyword",
       keywords: ["auto", "contain", "none"],
       default_value: "auto",
@@ -4868,7 +4866,6 @@
       name: "overscroll-behavior",
       longhands: ["overscroll-behavior-x", "overscroll-behavior-y"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
-      runtime_flag: "CSSOverscrollBehavior",
     },
     {
       name: "padding",
diff --git a/third_party/blink/renderer/core/css/font_face_cache_test.cc b/third_party/blink/renderer/core/css/font_face_cache_test.cc
index 0e6a0f1..ce44d55 100644
--- a/third_party/blink/renderer/core/css/font_face_cache_test.cc
+++ b/third_party/blink/renderer/core/css/font_face_cache_test.cc
@@ -222,7 +222,8 @@
   }
 }
 
-TEST_F(FontFaceCacheTest, MatchCombinations) {
+// Flaky; https://crbug.com/871812
+TEST_F(FontFaceCacheTest, FLAKY_MatchCombinations) {
   CSSValue* widths[] = {CSSIdentifierValue::Create(CSSValueCondensed),
                         CSSIdentifierValue::Create(CSSValueExpanded)};
   CSSValue* slopes[] = {CSSIdentifierValue::Create(CSSValueNormal),
diff --git a/third_party/blink/renderer/core/dom/common_definitions.idl b/third_party/blink/renderer/core/dom/common_definitions.idl
index d9e3f29..9ba34cae 100644
--- a/third_party/blink/renderer/core/dom/common_definitions.idl
+++ b/third_party/blink/renderer/core/dom/common_definitions.idl
@@ -7,6 +7,13 @@
 typedef (ArrayBuffer or ArrayBufferView) BufferSource;
 typedef unsigned long long DOMTimeStamp;
 
+
+// https://heycam.github.io/webidl/#Function
+
+// TODO(yukishiino): Use the generated V8Function instead of ScriptValue.
+// callback Function = any (any... arguments);
+
+
 // typedefs used in multiple files.
 
 typedef object JSON;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 70b424f..e962c09 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2043,8 +2043,7 @@
   EOverscrollBehavior overscroll_behavior_y =
       overflow_style->OverscrollBehaviorY();
   using OverscrollBehaviorType = cc::OverscrollBehavior::OverscrollBehaviorType;
-  if (RuntimeEnabledFeatures::CSSOverscrollBehaviorEnabled() &&
-      IsInMainFrame()) {
+  if (IsInMainFrame()) {
     GetPage()->GetOverscrollController().SetOverscrollBehavior(
         cc::OverscrollBehavior(
             static_cast<OverscrollBehaviorType>(overscroll_behavior_x),
@@ -3487,8 +3486,8 @@
   if (ProcessingBeforeUnload())
     return false;
 
-  BeforeUnloadEvent* before_unload_event = BeforeUnloadEvent::Create();
-  before_unload_event->initEvent(EventTypeNames::beforeunload, false, true);
+  BeforeUnloadEvent& before_unload_event = *BeforeUnloadEvent::Create();
+  before_unload_event.initEvent(EventTypeNames::beforeunload, false, true);
   load_event_progress_ = kBeforeUnloadEventInProgress;
   const TimeTicks beforeunload_event_start = CurrentTimeTicks();
   dom_window_->DispatchEvent(before_unload_event, this);
@@ -3499,8 +3498,8 @@
       ("DocumentEventTiming.BeforeUnloadDuration", 0, 10000000, 50));
   beforeunload_histogram.CountMicroseconds(beforeunload_event_end -
                                            beforeunload_event_start);
-  if (!before_unload_event->defaultPrevented())
-    DefaultEventHandler(before_unload_event);
+  if (!before_unload_event.defaultPrevented())
+    DefaultEventHandler(&before_unload_event);
 
   enum BeforeUnloadDialogHistogramEnum {
     kNoDialogNoText,
@@ -3511,10 +3510,10 @@
   };
   DEFINE_STATIC_LOCAL(EnumerationHistogram, beforeunload_dialog_histogram,
                       ("Document.BeforeUnloadDialog", kDialogEnumMax));
-  if (before_unload_event->returnValue().IsNull()) {
+  if (before_unload_event.returnValue().IsNull()) {
     beforeunload_dialog_histogram.Count(kNoDialogNoText);
   }
-  if (!GetFrame() || before_unload_event->returnValue().IsNull())
+  if (!GetFrame() || before_unload_event.returnValue().IsNull())
     return true;
 
   if (!GetFrame()->HasBeenActivated()) {
@@ -3536,7 +3535,7 @@
     Intervention::GenerateReport(frame_, "BeforeUnloadMultiple", message);
     return true;
   }
-  String text = before_unload_event->returnValue();
+  String text = before_unload_event.returnValue();
   beforeunload_dialog_histogram.Count(
       BeforeUnloadDialogHistogramEnum::kShowDialog);
   if (chrome_client.OpenBeforeUnloadConfirmPanel(text, frame_, is_reload)) {
@@ -3564,7 +3563,8 @@
       if (LocalDOMWindow* window = domWindow()) {
         const TimeTicks pagehide_event_start = CurrentTimeTicks();
         window->DispatchEvent(
-            PageTransitionEvent::Create(EventTypeNames::pagehide, false), this);
+            *PageTransitionEvent::Create(EventTypeNames::pagehide, false),
+            this);
         const TimeTicks pagehide_event_end = CurrentTimeTicks();
         DEFINE_STATIC_LOCAL(
             CustomCountHistogram, pagehide_histogram,
@@ -3600,7 +3600,7 @@
       DocumentLoader* document_loader =
           frame_->Loader().GetProvisionalDocumentLoader();
       load_event_progress_ = kUnloadEventInProgress;
-      Event* unload_event(Event::Create(EventTypeNames::unload));
+      Event& unload_event = *Event::Create(EventTypeNames::unload);
       if (document_loader &&
           document_loader->GetTiming().UnloadEventStart().is_null() &&
           document_loader->GetTiming().UnloadEventEnd().is_null()) {
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index eabb632..a9ff7be8 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2137,16 +2137,8 @@
   AttachPseudoElement(kPseudoIdAfter, children_context);
   AttachPseudoElement(kPseudoIdBackdrop, children_context);
 
-  // We create the first-letter element after the :before, :after and
-  // children are attached because the first letter text could come
-  // from any of them.
-  //
-  // TODO(futhark@chromium.org: Replace with AttachPseudoElement when we create
-  // ::first-letter elements during style recalc.
-  if (PseudoElement* first_letter =
-          CreatePseudoElementIfNeeded(kPseudoIdFirstLetter)) {
-    first_letter->AttachLayoutTree(children_context);
-  }
+  UpdateFirstLetterPseudoElement(StyleUpdatePhase::kAttachLayoutTree);
+  AttachPseudoElement(kPseudoIdFirstLetter, children_context);
 
   if (layout_object) {
     if (!layout_object->IsFloatingOrOutOfFlowPositioned())
@@ -2162,9 +2154,7 @@
   RemoveCallbackSelectors();
   if (HasRareData()) {
     ElementRareData* data = GetElementRareData();
-    if (context.performing_reattach)
-      data->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
-    else
+    if (!context.performing_reattach)
       data->ClearPseudoElements();
 
     // attachLayoutTree() will clear the computed style for us when inside
@@ -2233,8 +2223,7 @@
                                            ? CustomStyleForLayoutObject()
                                            : OriginalStyleForLayoutObject();
   if (!style) {
-    DCHECK(IsBeforePseudoElement() || IsAfterPseudoElement() ||
-           GetPseudoId() == kPseudoIdBackdrop);
+    DCHECK(IsPseudoElement());
     return nullptr;
   }
 
@@ -2361,13 +2350,11 @@
 
     UpdatePseudoElement(kPseudoIdAfter, change);
 
-    // If our children have changed then we need to force the first-letter
-    // checks as we don't know if they effected the first letter or not.
-    // This can be seen when a child transitions from floating to
-    // non-floating we have to take it into account for the first letter.
-    UpdatePseudoElement(
-        kPseudoIdFirstLetter,
-        change < kForce && ChildNeedsStyleRecalc() ? kForce : change);
+    // If we are re-attaching us or any of our descendants, we need to attach
+    // the descendants before we know if this element generates a ::first-letter
+    // and which element the ::first-letter inherits style from.
+    if (change < kReattach && !ChildNeedsReattachLayoutTree())
+      UpdateFirstLetterPseudoElement(StyleUpdatePhase::kRecalc);
 
     ClearChildNeedsStyleRecalc();
   }
@@ -2544,7 +2531,6 @@
 void Element::RebuildPseudoElementLayoutTree(
     PseudoId pseudo_id,
     WhitespaceAttacher& whitespace_attacher) {
-  PseudoElement* element = GetPseudoElement(pseudo_id);
   if (pseudo_id == kPseudoIdFirstLetter) {
     // Need to create a ::first-letter element here for the following case:
     //
@@ -2560,14 +2546,12 @@
     // up here for #outer after AttachLayoutTree is called on #inner at which
     // point the layout sub-tree is available for deciding on creating the
     // ::first-letter.
-    if (!element)
-      element = CreatePseudoElementIfNeeded(pseudo_id);
-    else if (UpdateFirstLetter(element))
-      return;
+    UpdateFirstLetterPseudoElement(StyleUpdatePhase::kRebuildLayoutTree);
   }
-
-  if (element && element->NeedsRebuildLayoutTree(whitespace_attacher))
-    element->RebuildLayoutTree(whitespace_attacher);
+  if (PseudoElement* element = GetPseudoElement(pseudo_id)) {
+    if (element->NeedsRebuildLayoutTree(whitespace_attacher))
+      element->RebuildLayoutTree(whitespace_attacher);
+  }
 }
 
 void Element::UpdateCallbackSelectors(const ComputedStyle* old_style,
@@ -3930,35 +3914,99 @@
     GetDocument().CancelFocusAppearanceUpdate();
 }
 
+void Element::UpdateFirstLetterPseudoElement(StyleUpdatePhase phase) {
+  // Update the ::first-letter pseudo elements presence and its style. This
+  // method may be called from style recalc or layout tree rebuilding/
+  // reattachment. In order to know if an element generates a ::first-letter
+  // element, we need to know if:
+  //
+  // * The element generates a block level box to which ::first-letter applies.
+  // * The element's layout subtree generates any first letter text.
+  // * None of the descendant blocks generate a ::first-letter element.
+  //   (This is not correct according to spec as all block containers should be
+  //   able to generate ::first-letter elements around the first letter of the
+  //   first formatted text, but Blink is only supporting a single
+  //   ::first-letter element which is the innermost block generating a
+  //   ::first-letter).
+  //
+  // We do not always do this at style recalc time as that would have required
+  // us to collect the information about how the layout tree will look like
+  // after the layout tree is attached. So, instead we will wait until we have
+  // an up-to-date layout sub-tree for the element we are considering for
+  // ::first-letter.
+  //
+  // The StyleUpdatePhase tells where we are in the process of updating style
+  // and layout tree.
+
+  PseudoElement* element = GetPseudoElement(kPseudoIdFirstLetter);
+  if (!element) {
+    element = CreatePseudoElementIfNeeded(kPseudoIdFirstLetter);
+    // If we are in Element::AttachLayoutTree, don't mess up the ancestor flags
+    // for layout tree attachment/rebuilding. We will unconditionally call
+    // AttachLayoutTree for the created pseudo element immediately after this
+    // call.
+    if (element && phase != StyleUpdatePhase::kAttachLayoutTree)
+      element->SetNeedsReattachLayoutTree();
+    return;
+  }
+
+  if (phase == StyleUpdatePhase::kRebuildLayoutTree &&
+      element->NeedsReattachLayoutTree()) {
+    // We were already updated in RecalcStyle and ready for reattach.
+    DCHECK(element->GetNonAttachedStyle());
+    return;
+  }
+
+  if (!CanGeneratePseudoElement(kPseudoIdFirstLetter)) {
+    GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
+    return;
+  }
+
+  LayoutObject* remaining_text_layout_object =
+      FirstLetterPseudoElement::FirstLetterTextLayoutObject(*element);
+
+  if (!remaining_text_layout_object) {
+    GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
+    return;
+  }
+
+  bool text_node_changed =
+      remaining_text_layout_object !=
+      ToFirstLetterPseudoElement(element)->RemainingTextLayoutObject();
+
+  if (phase == StyleUpdatePhase::kAttachLayoutTree) {
+    // RemainingTextLayoutObject should have been cleared from DetachLayoutTree.
+    DCHECK(!ToFirstLetterPseudoElement(element)->RemainingTextLayoutObject());
+    DCHECK(text_node_changed);
+    scoped_refptr<ComputedStyle> pseudo_style = element->StyleForLayoutObject();
+    if (PseudoElementLayoutObjectIsNeeded(pseudo_style.get()))
+      element->SetNonAttachedStyle(std::move(pseudo_style));
+    else
+      GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
+    return;
+  }
+
+  element->RecalcStyle(text_node_changed ? kReattach : kForce);
+
+  if (element->NeedsReattachLayoutTree() &&
+      !PseudoElementLayoutObjectIsNeeded(element->GetNonAttachedStyle())) {
+    GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
+  }
+}
+
 void Element::UpdatePseudoElement(PseudoId pseudo_id,
                                   StyleRecalcChange change) {
-  // TODO(futhark@chromium.org): Update ::first-letter pseudo elements and style
-  // as part of style recalc also when re-attaching.
-  if (change == kReattach && pseudo_id == kPseudoIdFirstLetter)
-    return;
-
   PseudoElement* element = GetPseudoElement(pseudo_id);
   if (!element) {
-    if (change >= kUpdatePseudoElements)
-      element = CreatePseudoElementIfNeeded(pseudo_id);
-    // TODO(futhark@chromium.org): We cannot SetNeedsReattachLayoutTree() for
-    // ::first-letter inside CreatePseudoElementIfNeeded() because it may be
-    // called from layout tree attachment.
-    if (element && pseudo_id == kPseudoIdFirstLetter)
+    if (change < kUpdatePseudoElements)
+      return;
+    if ((element = CreatePseudoElementIfNeeded(pseudo_id)))
       element->SetNeedsReattachLayoutTree();
     return;
   }
 
   if (change == kUpdatePseudoElements ||
       element->ShouldCallRecalcStyle(change)) {
-    if (pseudo_id == kPseudoIdFirstLetter) {
-      if (UpdateFirstLetter(element))
-        return;
-      // Need to clear the cached style if the PseudoElement wants a recalc so
-      // it computes a new style.
-      if (element->NeedsStyleRecalc())
-        MutableComputedStyle()->RemoveCachedPseudoStyle(kPseudoIdFirstLetter);
-    }
     if (CanGeneratePseudoElement(pseudo_id)) {
       element->RecalcStyle(change == kUpdatePseudoElements ? kForce : change);
       if (!element->NeedsReattachLayoutTree())
@@ -3967,39 +4015,9 @@
         return;
     }
     GetElementRareData()->SetPseudoElement(pseudo_id, nullptr);
-  } else if (pseudo_id == kPseudoIdFirstLetter &&
-             change >= kUpdatePseudoElements &&
-             !FirstLetterPseudoElement::FirstLetterTextLayoutObject(*element)) {
-    // We can end up here if we change to a float, for example. We need to
-    // cleanup the first-letter PseudoElement and then fix the text of the
-    // original remaining text LayoutObject. This can be seen in Test 7 of
-    // fast/css/first-letter-removed-added.html
-    GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
   }
 }
 
-// If we're updating first letter, and the current first letter layoutObject
-// is not the same as the one we're currently using we need to re-create
-// the first letter layoutObject.
-bool Element::UpdateFirstLetter(Element* element) {
-  LayoutObject* remaining_text_layout_object =
-      FirstLetterPseudoElement::FirstLetterTextLayoutObject(*element);
-  if (!remaining_text_layout_object ||
-      remaining_text_layout_object !=
-          ToFirstLetterPseudoElement(element)->RemainingTextLayoutObject()) {
-    // We have to clear out the old first letter here because when it is
-    // disposed it will set the original text back on the remaining text
-    // layoutObject. If we dispose after creating the new one we will get
-    // incorrect results due to setting the first letter back.
-    if (remaining_text_layout_object)
-      element->ReattachLayoutTree();
-    else
-      GetElementRareData()->SetPseudoElement(kPseudoIdFirstLetter, nullptr);
-    return true;
-  }
-  return false;
-}
-
 PseudoElement* Element::CreatePseudoElementIfNeeded(PseudoId pseudo_id) {
   if (IsPseudoElement())
     return nullptr;
@@ -4026,12 +4044,6 @@
 
   pseudo_element->SetNonAttachedStyle(std::move(pseudo_style));
 
-  // TODO(futhark@chromium.org): We cannot SetNeedsReattachLayoutTree() for
-  // ::first-letter inside CreatePseudoElementIfNeeded() because it may be
-  // called from layout tree attachment.
-  if (pseudo_id != kPseudoIdFirstLetter)
-    pseudo_element->SetNeedsReattachLayoutTree();
-
   probe::pseudoElementCreated(pseudo_element);
 
   return pseudo_element;
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 671b88c..8a7ae70a 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -985,7 +985,14 @@
                                        const Node* node_after_change);
 
   void UpdatePseudoElement(PseudoId, StyleRecalcChange);
-  bool UpdateFirstLetter(Element*);
+
+  enum class StyleUpdatePhase {
+    kRecalc,
+    kRebuildLayoutTree,
+    kAttachLayoutTree,
+  };
+
+  void UpdateFirstLetterPseudoElement(StyleUpdatePhase);
 
   inline PseudoElement* CreatePseudoElementIfNeeded(PseudoId);
   void AttachPseudoElement(PseudoId, AttachContext&);
diff --git a/third_party/blink/renderer/core/dom/events/event_path.cc b/third_party/blink/renderer/core/dom/events/event_path.cc
index 1f29d1b8..c596bf3 100644
--- a/third_party/blink/renderer/core/dom/events/event_path.cc
+++ b/third_party/blink/renderer/core/dom/events/event_path.cc
@@ -101,7 +101,7 @@
 
   nodes_in_path.push_back(current);
   while (current) {
-    if (event_ && current->KeepEventInNode(event_))
+    if (event_ && current->KeepEventInNode(*event_))
       break;
     HeapVector<Member<V0InsertionPoint>, 8> insertion_points;
     CollectDestinationInsertionPoints(*current, insertion_points);
diff --git a/third_party/blink/renderer/core/dom/events/event_queue.cc b/third_party/blink/renderer/core/dom/events/event_queue.cc
index acedb80f..78bea34c 100644
--- a/third_party/blink/renderer/core/dom/events/event_queue.cc
+++ b/third_party/blink/renderer/core/dom/events/event_queue.cc
@@ -53,16 +53,16 @@
   ContextLifecycleObserver::Trace(visitor);
 }
 
-bool EventQueue::EnqueueEvent(const base::Location& from_here, Event* event) {
+bool EventQueue::EnqueueEvent(const base::Location& from_here, Event& event) {
   if (is_closed_)
     return false;
 
-  DCHECK(event->target());
+  DCHECK(event.target());
   DCHECK(GetExecutionContext());
 
-  probe::AsyncTaskScheduled(GetExecutionContext(), event->type(), event);
+  probe::AsyncTaskScheduled(GetExecutionContext(), event.type(), &event);
 
-  bool was_added = queued_events_.insert(event).is_new_entry;
+  bool was_added = queued_events_.insert(&event).is_new_entry;
   DCHECK(was_added);  // It should not have already been in the list.
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
@@ -72,7 +72,7 @@
   // object like IDBTransaction as soon as possible.
   task_runner->PostTask(
       FROM_HERE, WTF::Bind(&EventQueue::DispatchEvent, WrapPersistent(this),
-                           WrapWeakPersistent(event)));
+                           WrapWeakPersistent(&event)));
 
   return true;
 }
@@ -85,8 +85,8 @@
   DoCancelAllEvents(GetExecutionContext());
 }
 
-bool EventQueue::RemoveEvent(Event* event) {
-  auto found = queued_events_.find(event);
+bool EventQueue::RemoveEvent(Event& event) {
+  auto found = queued_events_.find(&event);
   if (found == queued_events_.end())
     return false;
   queued_events_.erase(found);
@@ -94,7 +94,7 @@
 }
 
 void EventQueue::DispatchEvent(Event* event) {
-  if (!event || !RemoveEvent(event))
+  if (!event || !RemoveEvent(*event))
     return;
 
   DCHECK(GetExecutionContext());
diff --git a/third_party/blink/renderer/core/dom/events/event_queue.h b/third_party/blink/renderer/core/dom/events/event_queue.h
index cc446451d..1906634 100644
--- a/third_party/blink/renderer/core/dom/events/event_queue.h
+++ b/third_party/blink/renderer/core/dom/events/event_queue.h
@@ -46,14 +46,14 @@
   ~EventQueue();
 
   void Trace(blink::Visitor*) override;
-  bool EnqueueEvent(const base::Location&, Event*);
+  bool EnqueueEvent(const base::Location&, Event&);
   void CancelAllEvents();
   bool HasPendingEvents() const;
 
  private:
   EventQueue(ExecutionContext*, TaskType);
 
-  bool RemoveEvent(Event*);
+  bool RemoveEvent(Event&);
   void DispatchEvent(Event*);
 
   void ContextDestroyed(ExecutionContext*) override;
diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc
index 4797cf2c..f3ed84c 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.cc
+++ b/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -907,15 +907,15 @@
   }
 }
 
-void EventTarget::EnqueueEvent(Event* event, TaskType task_type) {
+void EventTarget::EnqueueEvent(Event& event, TaskType task_type) {
   ExecutionContext* context = GetExecutionContext();
   if (!context)
     return;
-  probe::AsyncTaskScheduled(context, event->type(), event);
+  probe::AsyncTaskScheduled(context, event.type(), &event);
   context->GetTaskRunner(task_type)->PostTask(
       FROM_HERE,
       WTF::Bind(&EventTarget::DispatchEnqueuedEvent, WrapPersistent(this),
-                WrapPersistent(event), WrapPersistent(context)));
+                WrapPersistent(&event), WrapPersistent(context)));
 }
 
 void EventTarget::DispatchEnqueuedEvent(Event* event,
diff --git a/third_party/blink/renderer/core/dom/events/event_target.h b/third_party/blink/renderer/core/dom/events/event_target.h
index 7c33c10..d6b5d57 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.h
+++ b/third_party/blink/renderer/core/dom/events/event_target.h
@@ -156,7 +156,7 @@
 
   DispatchEventResult DispatchEvent(Event&);
 
-  void EnqueueEvent(Event*, TaskType);
+  void EnqueueEvent(Event&, TaskType);
 
   // dispatchEventForBindings is intended to only be called from
   // javascript originated calls. This method will validate and may adjust
@@ -179,7 +179,7 @@
 
   static DispatchEventResult GetDispatchEventResult(const Event&);
 
-  virtual bool KeepEventInNode(Event*) { return false; }
+  virtual bool KeepEventInNode(const Event&) const { return false; }
 
   // Returns true if the target is window, window.document, or
   // window.document.body.
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
index 00d6c2f7..70d6fc3 100644
--- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -26,6 +26,7 @@
 
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/layout/generated_children.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
@@ -271,27 +272,16 @@
   PseudoElement::DetachLayoutTree(context);
 }
 
-ComputedStyle* FirstLetterPseudoElement::StyleForFirstLetter(
-    LayoutObject* layout_object_container) {
-  DCHECK(layout_object_container);
-
-  LayoutObject* style_container =
-      ParentOrShadowHostElement()->GetLayoutObject();
-  DCHECK(style_container);
-
-  // We always force the pseudo style to recompute as the first-letter style
-  // computed by the style container may not have taken the layoutObjects styles
-  // into account.
-  style_container->MutableStyle()->RemoveCachedPseudoStyle(
-      kPseudoIdFirstLetter);
-
-  ComputedStyle* pseudo_style = style_container->GetCachedPseudoStyle(
-      kPseudoIdFirstLetter, layout_object_container->FirstLineStyle());
-  DCHECK(pseudo_style);
-  pseudo_style->UpdateIsStackingContext(false /* is_document_element */,
-                                        false /* is_in_top_layer */,
-                                        false /* is_svg_stacking */);
-  return pseudo_style;
+scoped_refptr<ComputedStyle>
+FirstLetterPseudoElement::CustomStyleForLayoutObject() {
+  LayoutObject* first_letter_text =
+      FirstLetterPseudoElement::FirstLetterTextLayoutObject(*this);
+  if (!first_letter_text)
+    return nullptr;
+  DCHECK(first_letter_text->Parent());
+  return ParentOrShadowHostElement()->StyleForPseudoElement(
+      PseudoStyleRequest(GetPseudoId()),
+      first_letter_text->Parent()->FirstLineStyle());
 }
 
 void FirstLetterPseudoElement::AttachFirstLetterTextLayoutObjects(LayoutText* first_letter_text) {
@@ -304,12 +294,6 @@
   String old_text = first_letter_text->IsTextFragment() ? ToLayoutTextFragment(first_letter_text)->CompleteText() : first_letter_text->OriginalText();
   DCHECK(old_text.Impl());
 
-  // :first-letter inherits from the parent of the text. It may not be
-  // this->Parent() when e.g., <div><span>text</span></div>.
-  ComputedStyle* pseudo_style =
-      StyleForFirstLetter(first_letter_text->Parent());
-  GetLayoutObject()->SetStyle(pseudo_style);
-
   // FIXME: This would already have been calculated in firstLetterLayoutObject.
   // Can we pass the length through?
   unsigned length = FirstLetterPseudoElement::FirstLetterLength(old_text);
@@ -344,7 +328,7 @@
   LayoutTextFragment* letter =
       LayoutTextFragment::CreateAnonymous(*this, old_text.Impl(), 0, length);
   letter->SetFirstLetterPseudoElement(this);
-  letter->SetStyle(pseudo_style);
+  letter->SetStyle(MutableComputedStyle());
   GetLayoutObject()->AddChild(letter);
 
   first_letter_text->Destroy();
@@ -355,30 +339,15 @@
   if (!layout_object)
     return;
 
-  // :first-letter inherits from the parent of the text. It may not be
-  // this->Parent() when e.g., <div><span>text</span></div>.
-  DCHECK(remaining_text_layout_object_);
-  ComputedStyle* pseudo_style =
-      StyleForFirstLetter(remaining_text_layout_object_->Parent());
-  DCHECK(pseudo_style);
-  // TODO(kojii): While setting to GetLayoutObject() looks correct all the time,
-  // as we do so in AttachFirstLetterTextLayoutObjects(), it is required only
-  // when inline box has text children, and can break layout tree when changing
-  // :first-letter to floats. The check in Element::UpdatePseudoElement() does
-  // not catch all such cases.
-  if (!pseudo_style->IsDisplayBlockContainer())
-    layout_object->SetStyle(pseudo_style);
-
-  // The layoutObjects inside pseudo elements are anonymous so they don't get
-  // notified of recalcStyle and must have
-  // the style propagated downward manually similar to
-  // LayoutObject::propagateStyleToAnonymousChildren.
+  // The layout objects inside pseudo elements are anonymous so they don't get
+  // notified of RecalcStyle and must have the style propagated downward
+  // manually similar to LayoutObject::PropagateStyleToAnonymousChildren.
   for (LayoutObject* child = layout_object->NextInPreOrder(layout_object);
        child; child = child->NextInPreOrder(layout_object)) {
     // We need to re-calculate the correct style for the first letter element
     // and then apply that to the container and the text fragment inside.
     if (child->Style()->StyleType() == kPseudoIdFirstLetter) {
-      child->SetPseudoStyle(pseudo_style);
+      child->SetPseudoStyle(layout_object->MutableStyle());
       continue;
     }
 
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
index 142b17d..6c8b5b1 100644
--- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
+++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.h
@@ -33,7 +33,6 @@
 namespace blink {
 
 class Element;
-class LayoutObject;
 class LayoutText;
 class LayoutTextFragment;
 
@@ -61,10 +60,10 @@
  private:
   explicit FirstLetterPseudoElement(Element*);
 
+  scoped_refptr<ComputedStyle> CustomStyleForLayoutObject() override;
   void DidRecalcStyle(StyleRecalcChange) override;
 
   void AttachFirstLetterTextLayoutObjects(LayoutText* first_letter_text);
-  ComputedStyle* StyleForFirstLetter(LayoutObject*);
 
   LayoutTextFragment* remaining_text_layout_object_;
   DISALLOW_COPY_AND_ASSIGN(FirstLetterPseudoElement);
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index e7ac71fa..ec2589e 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -131,11 +131,7 @@
 }
 
 ComputedStyle& LayoutTreeBuilderForElement::Style() const {
-  if (!style_) {
-    DCHECK(!node_->GetNonAttachedStyle());
-    DCHECK(node_->IsFirstLetterPseudoElement());
-    style_ = node_->StyleForLayoutObject();
-  }
+  DCHECK(style_);
   return *style_;
 }
 
diff --git a/third_party/blink/renderer/core/dom/scripted_animation_controller.cc b/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
index ac322f2d..5bdc1ac0 100644
--- a/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
+++ b/third_party/blink/renderer/core/dom/scripted_animation_controller.cc
@@ -120,7 +120,7 @@
     // tree.
     probe::AsyncTask async_task(event_target->GetExecutionContext(), event);
     if (LocalDOMWindow* window = event_target->ToLocalDOMWindow())
-      window->DispatchEvent(event, nullptr);
+      window->DispatchEvent(*event, nullptr);
     else
       event_target->DispatchEvent(*event);
   }
diff --git a/third_party/blink/renderer/core/editing/commands/split_text_node_command_test.cc b/third_party/blink/renderer/core/editing/commands/split_text_node_command_test.cc
index c3b9f0d2..06478b1 100644
--- a/third_party/blink/renderer/core/editing/commands/split_text_node_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/split_text_node_command_test.cc
@@ -37,8 +37,8 @@
   EditingState editingState;
   command->DoApply(&editingState);
 
-  Node* text1 = ToText(div->firstChild());
-  Node* text2 = ToText(text1->nextSibling());
+  Text* text1 = ToText(div->firstChild());
+  Text* text2 = ToText(text1->nextSibling());
 
   // The first marker should end up in text1, the second marker should be
   // truncated and end up text1, the third marker should end up in text2
@@ -60,7 +60,7 @@
   // Test undo
   command->DoUnapply();
 
-  Node* text = ToText(div->firstChild());
+  Text* text = ToText(div->firstChild());
 
   EXPECT_EQ(3u, GetDocument().Markers().MarkersFor(text).size());
 
diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc
index f922217e..76bed03 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -295,7 +295,7 @@
   // The task source should be kDOMManipulation, but the spec doesn't say
   // anything about this.
   frame_->DomWindow()->EnqueueDocumentEvent(
-      Event::Create(EventTypeNames::selectionchange),
+      *Event::Create(EventTypeNames::selectionchange),
       TaskType::kMiscPlatformAPI);
 }
 
diff --git a/third_party/blink/renderer/core/editing/frame_selection_test.cc b/third_party/blink/renderer/core/editing/frame_selection_test.cc
index 928567b6..77eab39f 100644
--- a/third_party/blink/renderer/core/editing/frame_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection_test.cc
@@ -51,8 +51,8 @@
   }
 
   Text* AppendTextNode(const String& data);
-  int LayoutCount() const {
-    return GetDummyPageHolder().GetFrameView().LayoutCount();
+  unsigned LayoutCount() const {
+    return GetDummyPageHolder().GetFrameView().LayoutCountForTesting();
   }
 
   PositionWithAffinity CaretPosition() const {
@@ -133,7 +133,7 @@
   EXPECT_TRUE(ToLayoutBlock(GetDocument().body()->GetLayoutObject())
                   ->ShouldPaintCursorCaret());
 
-  int start_count = LayoutCount();
+  unsigned start_count = LayoutCount();
   {
     // To force layout in next updateLayout calling, widen view.
     LocalFrameView& frame_view = GetDummyPageHolder().GetFrameView();
diff --git a/third_party/blink/renderer/core/editing/granularity_strategy_test.cc b/third_party/blink/renderer/core/editing/granularity_strategy_test.cc
index 6749dd0..8f33fe2c 100644
--- a/third_party/blink/renderer/core/editing/granularity_strategy_test.cc
+++ b/third_party/blink/renderer/core/editing/granularity_strategy_test.cc
@@ -42,9 +42,6 @@
   void SetUp() override;
 
   Text* AppendTextNode(const String& data);
-  int LayoutCount() const {
-    return GetDummyPageHolder().GetFrameView().LayoutCount();
-  }
   void SetInnerHTML(const char*);
   // Parses the text node, appending the info to m_letterPos and m_wordMiddles.
   void ParseText(Text*);
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
index 8f2a7c34..d527039 100644
--- a/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/ime/input_method_controller_test.cc
@@ -1477,14 +1477,16 @@
       PlainTextRange(2).CreateRange(*div).StartPosition();
   const Position& second_line_position =
       PlainTextRange(8).CreateRange(*div).StartPosition();
-  ASSERT_EQ(0u, GetDocument()
-                    .Markers()
-                    .MarkersFor(first_line_position.ComputeContainerNode())
-                    .size());
-  ASSERT_EQ(1u, GetDocument()
-                    .Markers()
-                    .MarkersFor(second_line_position.ComputeContainerNode())
-                    .size());
+  ASSERT_EQ(0u,
+            GetDocument()
+                .Markers()
+                .MarkersFor(ToText(first_line_position.ComputeContainerNode()))
+                .size());
+  ASSERT_EQ(1u,
+            GetDocument()
+                .Markers()
+                .MarkersFor(ToText(second_line_position.ComputeContainerNode()))
+                .size());
 
   // Verify marker has correct start/end offsets (measured from the beginning
   // of the node, which is the beginning of the line)
@@ -1624,7 +1626,8 @@
 
   // Check that the marker is still attached to "text" and doesn't include
   // either space around it
-  EXPECT_EQ(1u, GetDocument().Markers().MarkersFor(div->firstChild()).size());
+  EXPECT_EQ(
+      1u, GetDocument().Markers().MarkersFor(ToText(div->firstChild())).size());
   EXPECT_STREQ("text",
                GetMarkedText(GetDocument().Markers(), div->firstChild(), 0)
                    .Utf8()
@@ -2406,8 +2409,8 @@
   Controller().SetComposition("test", ime_text_spans, 0, 4);
 
   Node* b = div->firstChild();
-  Node* text1 = b->firstChild();
-  Node* text2 = b->nextSibling();
+  Text* text1 = ToText(b->firstChild());
+  Text* text2 = ToText(b->nextSibling());
 
   const DocumentMarkerVector& text1_markers =
       GetDocument().Markers().MarkersFor(
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
index 650ea7a..a4b0cec7 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
@@ -472,8 +472,8 @@
 }
 
 DocumentMarkerVector DocumentMarkerController::MarkersFor(
-    const Node* node,
-    DocumentMarker::MarkerTypes marker_types) {
+    const Text* node,
+    DocumentMarker::MarkerTypes marker_types) const {
   DocumentMarkerVector result;
   if (!PossiblyHasMarkers(marker_types))
     return result;
@@ -498,10 +498,10 @@
   return result;
 }
 
-DocumentMarkerVector DocumentMarkerController::Markers() {
+DocumentMarkerVector DocumentMarkerController::Markers() const {
   DocumentMarkerVector result;
-  for (MarkerMap::iterator i = markers_.begin(); i != markers_.end(); ++i) {
-    MarkerLists* markers = i->value.Get();
+  for (const auto& node_markers : markers_) {
+    MarkerLists* markers = node_markers.value;
     for (DocumentMarker::MarkerType type : DocumentMarker::MarkerTypes::All()) {
       DocumentMarkerList* const list = ListForType(markers, type);
       if (!list)
@@ -518,7 +518,7 @@
 }
 
 DocumentMarkerVector DocumentMarkerController::ComputeMarkersToPaint(
-    const Node& node) {
+    const Text& node) const {
   // We don't render composition or spelling markers that overlap suggestion
   // markers.
   // Note: DocumentMarkerController::MarkersFor() returns markers sorted by
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
index 34036b30..288db67 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
@@ -117,11 +117,10 @@
   MarkersIntersectingRange(const EphemeralRangeInFlatTree&,
                            DocumentMarker::MarkerTypes);
   DocumentMarkerVector MarkersFor(
-      const Node*,
-      DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All());
-  DocumentMarkerVector Markers();
-  // TODO(yoichio): Make const by making PossiblyHasMarkers const.
-  DocumentMarkerVector ComputeMarkersToPaint(const Node&);
+      const Text*,
+      DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All()) const;
+  DocumentMarkerVector Markers() const;
+  DocumentMarkerVector ComputeMarkersToPaint(const Text&) const;
 
   Vector<IntRect> LayoutRectsForTextMatchMarkers();
   void InvalidateRectsForAllTextMatchMarkers();
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
index 426ff09..a85d300 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
@@ -586,13 +586,13 @@
                                      .ComputeVisibleSelectionInDOMTree()
                                      .Start()
                                      .AnchorNode());
-  if (!node)
+  if (!node || !node->IsTextNode())
     return false;
 
   unsigned start_offset = static_cast<unsigned>(from);
   unsigned end_offset = static_cast<unsigned>(from + length);
   DocumentMarkerVector markers =
-      GetFrame().GetDocument()->Markers().MarkersFor(node);
+      GetFrame().GetDocument()->Markers().MarkersFor(ToText(node));
   for (size_t i = 0; i < markers.size(); ++i) {
     DocumentMarker* marker = markers[i];
     if (marker->StartOffset() <= start_offset &&
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_checker_test.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_checker_test.cc
index ae13fc6..3489945 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_checker_test.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_checker_test.cc
@@ -21,7 +21,9 @@
 
 class SpellCheckerTest : public SpellCheckTestBase {
  protected:
-  int LayoutCount() const { return Page().GetFrameView().LayoutCount(); }
+  unsigned LayoutCount() const {
+    return Page().GetFrameView().LayoutCountForTesting();
+  }
   DummyPageHolder& Page() const { return GetDummyPageHolder(); }
 
   void ForceLayout();
@@ -91,7 +93,7 @@
 
   EXPECT_TRUE(GetSpellChecker().IsSpellCheckingEnabled());
   ForceLayout();
-  int start_count = LayoutCount();
+  unsigned start_count = LayoutCount();
   GetSpellChecker().RespondToChangedSelection();
   EXPECT_EQ(start_count, LayoutCount());
 }
diff --git a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc
index f7906a2..d9167561 100644
--- a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller_test.cc
@@ -57,7 +57,7 @@
       "word1 word2 word3 word4"
       "</div>");
   Element* div = GetDocument().QuerySelector("div");
-  Node* text = div->firstChild();
+  Text* text = ToText(div->firstChild());
 
   // Add marker on "word1". This marker should *not* be cleared by the
   // replace operation.
@@ -169,7 +169,7 @@
       "mispelled"
       "</div>");
   Element* div = GetDocument().QuerySelector("div");
-  Node* text = div->firstChild();
+  Text* text = ToText(div->firstChild());
 
   // Add marker on "mispelled". This marker should be cleared by the replace
   // operation.
diff --git a/third_party/blink/renderer/core/exported/web_form_control_element.cc b/third_party/blink/renderer/core/exported/web_form_control_element.cc
index 31a463e..3ddef9c 100644
--- a/third_party/blink/renderer/core/exported/web_form_control_element.cc
+++ b/third_party/blink/renderer/core/exported/web_form_control_element.cc
@@ -79,6 +79,8 @@
 bool WebFormControlElement::UserHasEditedTheField() const {
   if (auto* input = ToHTMLInputElementOrNull(*private_))
     return input->UserHasEditedTheField();
+  if (auto* select_element = ToHTMLSelectElementOrNull(*private_))
+    return select_element->UserHasEditedTheField();
   return true;
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index b5e5f28..4f1ab2d 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -328,7 +328,7 @@
     int node_count = 0;
     for (Node& node : range.Nodes()) {
       const DocumentMarkerVector& markers_in_node =
-          document->Markers().MarkersFor(&node, marker_types);
+          document->Markers().MarkersFor(ToText(&node), marker_types);
       node_count += std::count_if(
           markers_in_node.begin(), markers_in_node.end(),
           [start_offset, end_offset, &node, &start_container,
@@ -2577,8 +2577,8 @@
                                     &client, nullptr, ConfigureAndroid);
   web_view_helper.Resize(WebSize(viewport_width, viewport_height));
 
-  int prev_layout_count =
-      web_view_helper.LocalMainFrame()->GetFrameView()->LayoutCount();
+  unsigned prev_layout_count =
+      web_view_helper.LocalMainFrame()->GetFrameView()->LayoutCountForTesting();
   web_view_helper.GetWebView()->SetPageScaleFactor(3);
   EXPECT_FALSE(web_view_helper.GetWebView()
                    ->MainFrameImpl()
@@ -2587,7 +2587,7 @@
   EXPECT_EQ(prev_layout_count, web_view_helper.GetWebView()
                                    ->MainFrameImpl()
                                    ->GetFrameView()
-                                   ->LayoutCount());
+                                   ->LayoutCountForTesting());
 }
 
 TEST_F(WebFrameTest, setPageScaleFactorWithOverlayScrollbarsDoesNotLayout) {
@@ -2603,8 +2603,8 @@
                                     &client, nullptr, ConfigureAndroid);
   web_view_helper.Resize(WebSize(viewport_width, viewport_height));
 
-  int prev_layout_count =
-      web_view_helper.LocalMainFrame()->GetFrameView()->LayoutCount();
+  unsigned prev_layout_count =
+      web_view_helper.LocalMainFrame()->GetFrameView()->LayoutCountForTesting();
   web_view_helper.GetWebView()->SetPageScaleFactor(30);
   EXPECT_FALSE(web_view_helper.GetWebView()
                    ->MainFrameImpl()
@@ -2613,7 +2613,7 @@
   EXPECT_EQ(prev_layout_count, web_view_helper.GetWebView()
                                    ->MainFrameImpl()
                                    ->GetFrameView()
-                                   ->LayoutCount());
+                                   ->LayoutCountForTesting());
 }
 
 TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem) {
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index e623502..384e8a913 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -460,7 +460,7 @@
     const WebDOMMessageEvent& event) {
   if (!element_->GetExecutionContext())
     return;
-  element_->EnqueueEvent(event, TaskType::kInternalDefault);
+  element_->EnqueueEvent(*event, TaskType::kInternalDefault);
 }
 
 void WebPluginContainerImpl::Invalidate() {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index ff939dc..23f0d6f 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1604,6 +1604,9 @@
 
   PageWidgetDelegate::UpdateLifecycle(*page_, *MainFrameImpl()->GetFrame(),
                                       requested_update);
+  if (requested_update == LifecycleUpdate::kLayout)
+    return;
+
   UpdateLayerTreeBackgroundColor();
 
   if (requested_update == LifecycleUpdate::kPrePaint)
@@ -2663,13 +2666,6 @@
 }
 
 WebSize WebViewImpl::ContentsPreferredMinimumSize() {
-  if (MainFrameImpl()) {
-    MainFrameImpl()
-        ->GetFrame()
-        ->View()
-        ->UpdateLifecycleToLayoutClean();
-  }
-
   Document* document = page_->MainFrame()->IsLocalFrame()
                            ? page_->DeprecatedLocalMainFrame()->GetDocument()
                            : nullptr;
@@ -2677,6 +2673,10 @@
       !document->documentElement()->GetLayoutBox())
     return WebSize();
 
+  // The preferred size requires an up-to-date layout tree.
+  DCHECK(!document->NeedsLayoutTreeUpdate() &&
+         !document->View()->NeedsLayout());
+
   // Needed for computing MinPreferredWidth.
   FontCachePurgePreventer fontCachePurgePreventer;
   int width_scaled = document->GetLayoutView()
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 3ab8efdf..0cf9f60 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -4132,25 +4132,6 @@
   EXPECT_EQ(2, size.height);
 }
 
-TEST_F(WebViewTest, PreferredSizeDirtyLayout) {
-  std::string url = base_url_ + "specify_size.html?100px:100px";
-  URLTestHelpers::RegisterMockedURLLoad(
-      ToKURL(url), test::CoreTestDataPath("specify_size.html"));
-  WebViewImpl* web_view = web_view_helper_.InitializeAndLoad(url);
-  WebElement document_element =
-      web_view->MainFrameImpl()->GetDocument().DocumentElement();
-
-  WebSize size = web_view->ContentsPreferredMinimumSize();
-  EXPECT_EQ(100, size.width);
-  EXPECT_EQ(100, size.height);
-
-  document_element.SetAttribute("style", "display: none");
-
-  size = web_view->ContentsPreferredMinimumSize();
-  EXPECT_EQ(0, size.width);
-  EXPECT_EQ(0, size.height);
-}
-
 TEST_F(WebViewTest, PreferredSizeWithGrid) {
   WebViewImpl* web_view = web_view_helper_.Initialize();
   WebURL base_url = URLTestHelpers::ToKURL("http://example.com/");
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index c103e02..67af69ff 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1420,9 +1420,9 @@
   if (execution_context_->IsWorkletGlobalScope())
     return;
 
-  SecurityPolicyViolationEvent* event = SecurityPolicyViolationEvent::Create(
+  SecurityPolicyViolationEvent& event = *SecurityPolicyViolationEvent::Create(
       EventTypeNames::securitypolicyviolation, violation_data);
-  DCHECK(event->bubbles());
+  DCHECK(event.bubbles());
 
   if (execution_context_->IsDocument()) {
     Document* document = ToDocument(execution_context_);
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index e41b02e..1bf6ed2 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -338,11 +338,11 @@
   return document_;
 }
 
-void LocalDOMWindow::EnqueueWindowEvent(Event* event, TaskType task_type) {
+void LocalDOMWindow::EnqueueWindowEvent(Event& event, TaskType task_type) {
   EnqueueEvent(event, task_type);
 }
 
-void LocalDOMWindow::EnqueueDocumentEvent(Event* event, TaskType task_type) {
+void LocalDOMWindow::EnqueueDocumentEvent(Event& event, TaskType task_type) {
   if (document_)
     document_->EnqueueEvent(event, task_type);
 }
@@ -379,19 +379,19 @@
     // The task source should be kDOMManipulation, but the spec doesn't say
     // anything about this.
     EnqueueWindowEvent(
-        PageTransitionEvent::Create(EventTypeNames::pageshow, persisted),
+        *PageTransitionEvent::Create(EventTypeNames::pageshow, persisted),
         TaskType::kMiscPlatformAPI);
     return;
   }
   DispatchEvent(
-      PageTransitionEvent::Create(EventTypeNames::pageshow, persisted),
+      *PageTransitionEvent::Create(EventTypeNames::pageshow, persisted),
       document_.Get());
 }
 
 void LocalDOMWindow::EnqueueHashchangeEvent(const String& old_url,
                                             const String& new_url) {
   // https://html.spec.whatwg.org/#history-traversal
-  EnqueueWindowEvent(HashChangeEvent::Create(old_url, new_url),
+  EnqueueWindowEvent(*HashChangeEvent::Create(old_url, new_url),
                      TaskType::kDOMManipulation);
 }
 
@@ -1447,7 +1447,7 @@
 }
 
 void LocalDOMWindow::DispatchLoadEvent() {
-  Event* load_event(Event::Create(EventTypeNames::load));
+  Event& load_event = *Event::Create(EventTypeNames::load);
   DocumentLoader* document_loader =
       GetFrame() ? GetFrame()->Loader().GetDocumentLoader() : nullptr;
   if (document_loader &&
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index 6c1c776..66664c4 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -313,13 +313,6 @@
 
   using EventTarget::DispatchEvent;
   DispatchEventResult DispatchEvent(Event&, EventTarget*);
-  // Deprecated: Use DispatchEvent(Event&, ...), instead of this.
-  // This will be removed after every callers of this function are replaced.
-  // See crbub.com/871637.
-  DispatchEventResult DispatchEvent(Event* event, EventTarget* event_target) {
-    DCHECK(event);
-    return DispatchEvent(*event, event_target);
-  }
 
   void FinishedLoading();
 
@@ -327,8 +320,8 @@
   // recurse on its child frames.
   void SendOrientationChangeEvent();
 
-  void EnqueueWindowEvent(Event*, TaskType);
-  void EnqueueDocumentEvent(Event*, TaskType);
+  void EnqueueWindowEvent(Event&, TaskType);
+  void EnqueueDocumentEvent(Event&, TaskType);
   void EnqueuePageshowEvent(PageshowEventPersistence);
   void EnqueueHashchangeEvent(const String& old_url, const String& new_url);
   void EnqueuePopstateEvent(scoped_refptr<SerializedScriptValue>);
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index fbd25ea..301304d4c 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -292,7 +292,8 @@
   has_pending_layout_ = false;
   layout_scheduling_enabled_ = true;
   in_synchronous_post_layout_ = false;
-  layout_count_ = 0;
+  layout_count_for_testing_ = 0;
+  lifecycle_update_count_for_testing_ = 0;
   nested_layout_count_ = 0;
   post_layout_tasks_timer_.Stop();
   update_plugins_timer_.Stop();
@@ -961,8 +962,7 @@
         this, TracedLayoutObject::Create(*GetLayoutView(), true));
 
     GetLayoutView()->Compositor()->DidLayout();
-
-    layout_count_++;
+    layout_count_for_testing_++;
 
     if (AXObjectCache* cache = document->GetOrCreateAXObjectCache()) {
       const KURL& url = document->Url();
@@ -991,8 +991,7 @@
     GetLayoutView()->AssertSubtreeIsLaidOut();
 #endif
 
-    if (frame_->IsMainFrame() &&
-        RuntimeEnabledFeatures::VisualViewportAPIEnabled()) {
+    if (frame_->IsMainFrame()) {
       // Scrollbars changing state can cause a visual viewport size change.
       DoubleSize new_viewport_size(visual_viewport.VisibleWidthCSSPx(),
                                    visual_viewport.VisibleHeightCSSPx());
@@ -2083,8 +2082,7 @@
   last_viewport_size_ = GetLayoutSize();
   last_zoom_factor_ = layout_view->StyleRef().Zoom();
 
-  if (RuntimeEnabledFeatures::VisualViewportAPIEnabled())
-    frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
+  frame_->GetDocument()->EnqueueVisualViewportResizeEvent();
 
   frame_->GetDocument()->EnqueueResizeEvent();
 
@@ -2370,6 +2368,7 @@
          target_state == DocumentLifecycle::kCompositingClean ||
          target_state == DocumentLifecycle::kPrePaintClean ||
          target_state == DocumentLifecycle::kPaintClean);
+  lifecycle_update_count_for_testing_++;
 
   // If the document is not active then it is either not yet initialized, or it
   // is stopping. In either case, we can't reach one of the supported target
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 59920cc..d753520 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -152,7 +152,11 @@
   bool HasOrthogonalWritingModeRoots() const;
   void LayoutOrthogonalWritingModeRoots();
   void ScheduleOrthogonalWritingModeRootsForLayout();
-  int LayoutCount() const { return layout_count_; }
+
+  unsigned LayoutCountForTesting() const { return layout_count_for_testing_; }
+  unsigned LifecycleUpdateCountForTesting() const {
+    return lifecycle_update_count_for_testing_;
+  }
 
   void CountObjectsNeedingLayout(unsigned& needs_layout_objects,
                                  unsigned& total_objects,
@@ -829,7 +833,8 @@
 
   bool layout_scheduling_enabled_;
   bool in_synchronous_post_layout_;
-  int layout_count_;
+  unsigned layout_count_for_testing_;
+  unsigned lifecycle_update_count_for_testing_;
   unsigned nested_layout_count_;
   TaskRunnerTimer<LocalFrameView> post_layout_tasks_timer_;
   TaskRunnerTimer<LocalFrameView> update_plugins_timer_;
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc
index 675c0d0..3d340f4 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -183,17 +183,11 @@
 }
 
 void VisualViewport::EnqueueScrollEvent() {
-  if (!RuntimeEnabledFeatures::VisualViewportAPIEnabled())
-    return;
-
   if (Document* document = MainFrame()->GetDocument())
     document->EnqueueVisualViewportScrollEvent();
 }
 
 void VisualViewport::EnqueueResizeEvent() {
-  if (!RuntimeEnabledFeatures::VisualViewportAPIEnabled())
-    return;
-
   if (Document* document = MainFrame()->GetDocument())
     document->EnqueueVisualViewportResizeEvent();
 }
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.idl b/third_party/blink/renderer/core/frame/visual_viewport.idl
index be7e37d..00317b9 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.idl
+++ b/third_party/blink/renderer/core/frame/visual_viewport.idl
@@ -27,7 +27,6 @@
  // WICG proposal: https://github.com/WICG/ViewportAPI
 
 [
-    RuntimeEnabled=VisualViewportAPI,
     ImplementedAs=DOMVisualViewport
 ] interface VisualViewport : EventTarget {
     [Measure] readonly attribute double offsetLeft;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index d2026b6..11ac1780 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -293,10 +293,11 @@
   if (!LocalRootImpl())
     return;
 
-  bool pre_paint_only = requested_update == LifecycleUpdate::kPrePaint;
+  bool should_paint = requested_update != LifecycleUpdate::kLayout &&
+                      requested_update != LifecycleUpdate::kPrePaint;
 
   WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl();
-  if (devtools && !pre_paint_only)
+  if (devtools && should_paint)
     devtools->PaintOverlay();
 
   DocumentLifecycle::AllowThrottlingScope throttling_scope(
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index 3b5cf14..66a5f34 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -148,7 +148,7 @@
 
     // Visual Viewport API
     // https://github.com/WICG/ViewportAPI
-    [RuntimeEnabled=VisualViewportAPI, Replaceable, SameObject] readonly attribute VisualViewport visualViewport;
+    [Replaceable, SameObject] readonly attribute VisualViewport visualViewport;
 
     // client
     [Affects=Nothing, Replaceable] readonly attribute long screenX;
diff --git a/third_party/blink/renderer/core/frame/window_post_message_options.idl b/third_party/blink/renderer/core/frame/window_post_message_options.idl
index 15ca5e2..55e815a5 100644
--- a/third_party/blink/renderer/core/frame/window_post_message_options.idl
+++ b/third_party/blink/renderer/core/frame/window_post_message_options.idl
@@ -4,8 +4,7 @@
 
 // https://github.com/dtapuska/useractivation
 
-dictionary WindowPostMessageOptions {
+dictionary WindowPostMessageOptions : PostMessageOptions {
     USVString targetOrigin = "/";
-    sequence<object> transfer = [];
     [RuntimeEnabled=UserActivationAPI] boolean includeUserActivation = false;
 };
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index dd3fee71..90b0f4fc 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -77,10 +77,13 @@
                 ? CanvasResourceProvider::kAllowImageChromiumPresentationMode
                 : CanvasResourceProvider::kDefaultPresentationMode;
 
+        const bool is_origin_top_left =
+            !SharedGpuContext::IsGpuCompositingEnabled();
+
         ReplaceResourceProvider(CanvasResourceProvider::Create(
             Size(), usage, SharedGpuContext::ContextProviderWrapper(),
             0 /* msaa_sample_count */, ColorParams(), presentation_mode,
-            std::move(dispatcher)));
+            std::move(dispatcher), is_origin_top_left));
       } else {
         DCHECK(Is2d());
         const bool want_acceleration =
@@ -96,10 +99,13 @@
                 ? CanvasResourceProvider::kAllowImageChromiumPresentationMode
                 : CanvasResourceProvider::kDefaultPresentationMode;
 
+        const bool is_origin_top_left =
+            !want_acceleration || LowLatencyEnabled();
+
         ReplaceResourceProvider(CanvasResourceProvider::Create(
             Size(), usage, SharedGpuContext::ContextProviderWrapper(),
             GetMSAASampleCountFor2dContext(), ColorParams(), presentation_mode,
-            std::move(dispatcher)));
+            std::move(dispatcher), is_origin_top_left));
 
         if (ResourceProvider()) {
           // Always save an initial frame, to support resetting the top level
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h b/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h
index fab6339..6ab06be5 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h
+++ b/third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h
@@ -55,8 +55,12 @@
   void NotifyFormStateChanged();
 
   void Trace(Visitor*) override;
+  bool UserHasEditedTheField() const { return user_has_edited_the_field_; }
+  // This is only used in tests, to fake the user's action
+  void SetUserHasEditedTheFieldForTest() { user_has_edited_the_field_ = true; }
 
  protected:
+  bool user_has_edited_the_field_ = false;
   HTMLFormControlElementWithState(const QualifiedName& tag_name, Document&);
 
   void FinishParsingChildren() override;
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index a6a13c6..cda962b 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -1705,6 +1705,11 @@
   if (!GetLayoutObject())
     return;
 
+  if (event->type() == EventTypeNames::click ||
+      event->type() == EventTypeNames::change) {
+    user_has_edited_the_field_ = true;
+  }
+
   if (IsDisabledFormControl()) {
     HTMLFormControlElementWithState::DefaultEventHandler(event);
     return;
@@ -2079,4 +2084,12 @@
   popup_->UpdateFromElement(PopupMenu::kByDOMChange);
 }
 
+void HTMLSelectElement::CloneNonAttributePropertiesFrom(
+    const Element& source,
+    CloneChildrenFlag flag) {
+  const auto& source_element = static_cast<const HTMLSelectElement&>(source);
+  user_has_edited_the_field_ = source_element.user_has_edited_the_field_;
+  HTMLFormControlElement::CloneNonAttributePropertiesFrom(source, flag);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.h b/third_party/blink/renderer/core/html/forms/html_select_element.h
index 1474997..97dc043b 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.h
@@ -173,6 +173,8 @@
   bool HasNonInBodyInsertionMode() const override { return true; }
 
   void Trace(blink::Visitor*) override;
+  void CloneNonAttributePropertiesFrom(const Element&,
+                                       CloneChildrenFlag) override;
 
  protected:
   explicit HTMLSelectElement(Document&);
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc
index a17e8c2c..e9af8fc5 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -68,7 +68,6 @@
                                        Document& doc)
     : HTMLFormControlElementWithState(tag_name, doc),
       last_change_was_user_edit_(false),
-      user_has_edited_the_field_(false),
       cached_selection_start_(0),
       cached_selection_end_(0) {
   cached_selection_direction_ =
@@ -753,12 +752,6 @@
   }
 }
 
-bool TextControlElement::UserHasEditedTheField() const {
-  if (!IsTextControl())
-    return false;
-  return user_has_edited_the_field_;
-}
-
 bool TextControlElement::LastChangeWasUserEdit() const {
   if (!IsTextControl())
     return false;
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.h b/third_party/blink/renderer/core/html/forms/text_control_element.h
index e479e52..4a9c145 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.h
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.h
@@ -134,10 +134,8 @@
   void DropInnerEditorElement() { inner_editor_ = nullptr; }
 
   void SelectionChanged(bool user_triggered);
-  bool UserHasEditedTheField() const;
   bool LastChangeWasUserEdit() const;
-  // This is only used in tests, to fake the user's action
-  void SetUserHasEditedTheFieldForTest() { user_has_edited_the_field_ = true; }
+
   virtual void SetInnerEditorValue(const String&);
   String InnerEditorValue() const;
   Node* CreatePlaceholderBreakElement() const;
@@ -221,7 +219,6 @@
   // zero-length String is a valid data.
   String value_before_first_user_edit_;
   bool last_change_was_user_edit_;
-  bool user_has_edited_the_field_;
 
   unsigned cached_selection_start_;
   unsigned cached_selection_end_;
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element_test.cc b/third_party/blink/renderer/core/html/forms/text_control_element_test.cc
index cf430c80..6f52800 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element_test.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element_test.cc
@@ -73,10 +73,10 @@
   // Force layout if document().updateStyleAndLayoutIgnorePendingStylesheets()
   // is called.
   GetDocument().body()->AppendChild(GetDocument().createTextNode("foo"));
-  const int start_layout_count = Page().GetFrameView().LayoutCount();
+  unsigned start_layout_count = Page().GetFrameView().LayoutCountForTesting();
   EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
   Input().SetSelectionRange(2, 2);
-  EXPECT_EQ(start_layout_count, Page().GetFrameView().LayoutCount());
+  EXPECT_EQ(start_layout_count, Page().GetFrameView().LayoutCountForTesting());
 }
 
 TEST_F(TextControlElementTest, IndexForPosition) {
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc
index 8e157267..5ec2f4c 100644
--- a/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -276,8 +276,7 @@
       UseCounter::Count(GetDocument(),
                         WebFeature::kHTMLImageElementReferrerPolicyAttribute);
     }
-  } else if (name == decodingAttr &&
-             RuntimeEnabledFeatures::ImageDecodingAttributeEnabled()) {
+  } else if (name == decodingAttr) {
     UseCounter::Count(GetDocument(), WebFeature::kImageDecodingAttribute);
     decoding_mode_ = ParseImageDecodingMode(params.new_value);
   } else {
diff --git a/third_party/blink/renderer/core/html/html_image_element.idl b/third_party/blink/renderer/core/html/html_image_element.idl
index c3e7980..e17cc92d 100644
--- a/third_party/blink/renderer/core/html/html_image_element.idl
+++ b/third_party/blink/renderer/core/html/html_image_element.idl
@@ -40,7 +40,7 @@
     readonly attribute boolean complete;
     readonly attribute DOMString currentSrc;
     [CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
-    [RuntimeEnabled=ImageDecodingAttribute, CEReactions, Reflect, ReflectOnly=("async", "sync", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString decoding;
+    [CEReactions, Reflect, ReflectOnly=("async", "sync", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString decoding;
     [CEReactions, RuntimeEnabled=PriorityHints, Reflect, ReflectOnly=("low", "auto", "high"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString importance;
 
     // obsolete members
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 1965daa7..81168424 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -761,7 +761,7 @@
   BLINK_MEDIA_LOG << "ScheduleEvent(" << (void*)this << ")"
                   << " - scheduling '" << event->type() << "'";
 #endif
-  async_event_queue_->EnqueueEvent(FROM_HERE, event);
+  async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 void HTMLMediaElement::LoadTimerFired(TimerBase*) {
diff --git a/third_party/blink/renderer/core/html/track/text_track_container.cc b/third_party/blink/renderer/core/html/track/text_track_container.cc
index 2b39733f..bec2694 100644
--- a/third_party/blink/renderer/core/html/track/text_track_container.cc
+++ b/third_party/blink/renderer/core/html/track/text_track_container.cc
@@ -29,6 +29,7 @@
 
 #include "third_party/blink/renderer/core/html/track/text_track_container.h"
 
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
 #include "third_party/blink/renderer/core/html/track/cue_timeline.h"
 #include "third_party/blink/renderer/core/html/track/text_track.h"
@@ -112,6 +113,8 @@
   LayoutUnit smallest_dimension =
       std::min(video_size.Height(), video_size.Width());
   float font_size = smallest_dimension * 0.05f;
+  if (media_layout_object->GetFrame())
+    font_size /= media_layout_object->GetFrame()->PageZoomFactor();
 
   // Avoid excessive FP precision issue.
   // C11 5.2.4.2.2:9 requires assignment and cast to remove extra precision, but
diff --git a/third_party/blink/renderer/core/html/track/text_track_list.cc b/third_party/blink/renderer/core/html/track/text_track_list.cc
index 1e34771..a9c5149 100644
--- a/third_party/blink/renderer/core/html/track/text_track_list.cc
+++ b/third_party/blink/renderer/core/html/track/text_track_list.cc
@@ -245,7 +245,7 @@
 
 void TextTrackList::ScheduleTrackEvent(const AtomicString& event_name,
                                        TextTrack* track) {
-  EnqueueEvent(TrackEvent::Create(event_name, track),
+  EnqueueEvent(*TrackEvent::Create(event_name, track),
                TaskType::kMediaElementEvent);
 }
 
@@ -267,7 +267,7 @@
   // ...
   // Fire a simple event named change at the media element's textTracks
   // attribute's TextTrackList object.
-  EnqueueEvent(Event::Create(EventTypeNames::change),
+  EnqueueEvent(*Event::Create(EventTypeNames::change),
                TaskType::kMediaElementEvent);
 }
 
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index 8aece21..41e62337 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -623,7 +623,8 @@
           0,                    // msaa_sample_count
           CanvasColorParams(),  // TODO: set color space here to avoid clamping
           CanvasResourceProvider::kDefaultPresentationMode,
-          nullptr);  // canvas_resource_dispatcher
+          nullptr,              // canvas_resource_dispatcher
+          IsAccelerated());     // is_origin_top_left
   if (!resource_provider)
     return;
 
diff --git a/third_party/blink/renderer/core/inspector/DEPS b/third_party/blink/renderer/core/inspector/DEPS
index 5676a4a..1f2b7d8 100644
--- a/third_party/blink/renderer/core/inspector/DEPS
+++ b/third_party/blink/renderer/core/inspector/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
     "+base/time/time_override.h",
+    "+base/sampling_heap_profiler/module_cache.h",
     "+base/sampling_heap_profiler/sampling_heap_profiler.h",
     # for base::GetUniqueIdForProcess
     "+base/process/process_handle.h",
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 237448d..2702d45 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -3414,6 +3414,20 @@
   type SamplingProfile extends object
     properties
       array of SamplingProfileNode samples
+      array of Module modules
+
+  # Executable module information
+  type Module extends object
+    properties
+      # Name of the module.
+      string name
+      # UUID of the module.
+      string uuid
+      # Base address where the module is loaded into memory. Encoded as a decimal
+      # or hexadecimal (0x prefixed) string.
+      string baseAddress
+      # Size of the module in bytes.
+      number size
 
 # Network domain allows tracking network activities of the page. It exposes information about http,
 # file, data and other requests and responses, their headers, bodies, timing, etc.
diff --git a/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc b/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc
index de7caa8..0166743 100644
--- a/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc
@@ -33,6 +33,7 @@
 #include <cstdio>
 
 #include "base/debug/stack_trace.h"
+#include "base/sampling_heap_profiler/module_cache.h"
 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -110,6 +111,7 @@
 
 std::unique_ptr<protocol::Memory::SamplingProfile>
 InspectorMemoryAgent::GetSamplingProfileById(uint32_t id) {
+  base::ModuleCache module_cache;
   std::unique_ptr<protocol::Array<protocol::Memory::SamplingProfileNode>>
       samples =
           protocol::Array<protocol::Memory::SamplingProfileNode>::create();
@@ -119,6 +121,10 @@
   for (auto& it : raw_samples) {
     std::unique_ptr<protocol::Array<protocol::String>> stack =
         protocol::Array<protocol::String>::create();
+    for (const void* frame : it.stack) {
+      uintptr_t address = reinterpret_cast<uintptr_t>(frame);
+      module_cache.GetModuleForAddress(address);  // Populates module_cache.
+    }
     std::vector<std::string> source_stack = Symbolize(it.stack);
     for (auto& it2 : source_stack)
       stack->addItem(it2.c_str());
@@ -145,8 +151,21 @@
                          .build());
   }
 
+  std::unique_ptr<protocol::Array<protocol::Memory::Module>> modules =
+      protocol::Array<protocol::Memory::Module>::create();
+  for (const auto* module : module_cache.GetModules()) {
+    modules->addItem(
+        protocol::Memory::Module::create()
+            .setName(module->filename.value().c_str())
+            .setUuid(module->id.c_str())
+            .setBaseAddress(String::Format("0x%" PRIxPTR, module->base_address))
+            .setSize(static_cast<double>(module->size))
+            .build());
+  }
+
   return protocol::Memory::SamplingProfile::create()
       .setSamples(std::move(samples))
+      .setModules(std::move(modules))
       .build();
 }
 
@@ -175,21 +194,19 @@
         line.substr(space_pos == std::string::npos ? 0 : space_pos + 1);
     symbols_cache_.insert(addresses_to_symbolize[i], name);
   }
+#endif
 
   std::vector<std::string> result;
-  for (void* address : addresses)
-    result.push_back(symbols_cache_.at(address));
-
-  return result;
-#else
-  std::vector<std::string> result;
   for (void* address : addresses) {
     char buffer[20];
-    std::snprintf(buffer, sizeof(buffer), "%p", address);
-    result.push_back(buffer);
+    std::snprintf(buffer, sizeof(buffer), "0x%" PRIxPTR,
+                  reinterpret_cast<uintptr_t>(address));
+    if (symbols_cache_.Contains(address))
+      result.push_back(std::string(buffer) + " " + symbols_cache_.at(address));
+    else
+      result.push_back(buffer);
   }
   return result;
-#endif
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/intersection_geometry.cc b/third_party/blink/renderer/core/layout/intersection_geometry.cc
index 2efb1a9..54b0474 100644
--- a/third_party/blink/renderer/core/layout/intersection_geometry.cc
+++ b/third_party/blink/renderer/core/layout/intersection_geometry.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -104,9 +105,11 @@
 }
 
 void IntersectionGeometry::InitializeTargetRect() {
-  if (target_->IsBoxModelObject()) {
+  if (target_->IsBox()) {
     target_rect_ =
         LayoutRect(ToLayoutBoxModelObject(target_)->BorderBoundingBox());
+  } else if (target_->IsLayoutInline()) {
+    target_rect_ = ToLayoutInline(target_)->LinesBoundingBox();
   } else {
     target_rect_ = ToLayoutText(target_)->LinesBoundingBox();
   }
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 7719f110..bdf10dd 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -65,7 +65,6 @@
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 #include "third_party/blink/renderer/core/paint/box_paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
index 49ec2bcf..66e5e93 100644
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
 #include "third_party/blink/renderer/core/paint/grid_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style/grid_area.h"
 #include "third_party/blink/renderer/platform/length_functions.h"
@@ -256,6 +257,8 @@
 
   SubtreeLayoutScope layout_scope(*this);
 
+  PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
+
   {
     // LayoutState needs this deliberate scope to pop before updating scroll
     // information (which may trigger relayout).
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 8bef427..2198215 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -20,7 +20,6 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_block_flow_painter.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
 
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc
index 9ce4140..65ec582 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -187,12 +187,12 @@
   DISALLOW_COPY_AND_ASSIGN(AssignOnScopeExit);
 };
 
-// Max number of CORS redirects handled in ThreadableLoader. Same number
-// as net/url_request/url_request.cc, and same number as
-// https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4.
-// FIXME: currently the number of redirects is counted and limited here and in
-// net/url_request/url_request.cc separately.
-static const int kMaxCORSRedirects = 20;
+// Max number of CORS redirects handled in ThreadableLoader.
+// See https://fetch.spec.whatwg.org/#http-redirect-fetch.
+// //net/url_request/url_request.cc and
+// //services/network/cors/cors_url_loader.cc also implement the same logic
+// separately.
+static const int kMaxRedirects = 20;
 
 // static
 std::unique_ptr<ResourceRequest>
@@ -252,7 +252,6 @@
       execution_context_(execution_context),
       resource_loader_options_(resource_loader_options),
       out_of_blink_cors_(RuntimeEnabledFeatures::OutOfBlinkCORSEnabled()),
-      cors_flag_(false),
       security_origin_(resource_loader_options_.security_origin),
       is_using_data_consumer_handle_(false),
       async_(resource_loader_options.synchronous_policy ==
@@ -263,7 +262,7 @@
       timeout_timer_(execution_context_->GetTaskRunner(TaskType::kNetworking),
                      this,
                      &ThreadableLoader::DidTimeout),
-      redirect_limit_(kMaxCORSRedirects),
+      redirect_limit_(kMaxRedirects),
       redirect_mode_(network::mojom::FetchRedirectMode::kFollow),
       override_referrer_(false) {
   DCHECK(client);
@@ -689,11 +688,10 @@
             : nullptr,
         redirect_response, resource);
 
-    base::Optional<network::mojom::CORSError> redirect_error =
-        CORS::CheckRedirectLocation(new_url);
-    if (redirect_error) {
-      DispatchDidFail(ResourceError(original_url,
-                                    network::CORSErrorStatus(*redirect_error)));
+    if (auto error_status = CORS::CheckRedirectLocation(
+            new_url, fetch_request_mode_, GetSecurityOrigin(),
+            cors_flag_ ? CORSFlag::Set : CORSFlag::Unset)) {
+      DispatchDidFail(ResourceError(original_url, *error_status));
       return false;
     }
 
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.h b/third_party/blink/renderer/core/loader/threadable_loader.h
index f76b267..edc0e7a6 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.h
+++ b/third_party/blink/renderer/core/loader/threadable_loader.h
@@ -225,7 +225,7 @@
   bool out_of_blink_cors_;
 
   // Corresponds to the CORS flag in the Fetch spec.
-  bool cors_flag_;
+  bool cors_flag_ = false;
   scoped_refptr<const SecurityOrigin> security_origin_;
 
   // Set to true when the response data is given to a data consumer handle.
diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc
index bb0ab33..ac04a2c 100644
--- a/third_party/blink/renderer/core/messaging/message_port.cc
+++ b/third_party/blink/renderer/core/messaging/message_port.cc
@@ -47,12 +47,8 @@
 
 namespace blink {
 
-// TODO(altimin): Remove these after per-task mojo dispatching.
 // The maximum number of MessageEvents to dispatch from one task.
-constexpr int kMaximumMessagesPerTask = 200;
-// The threshold to stop processing new tasks.
-constexpr base::TimeDelta kYieldThreshold =
-    base::TimeDelta::FromMilliseconds(50);
+static const int kMaximumMessagesPerTask = 200;
 
 MessagePort* MessagePort::Create(ExecutionContext& execution_context) {
   return new MessagePort(execution_context);
@@ -249,13 +245,12 @@
   // the connector is temporarily paused after |kMaximumMessagesPerTask| have
   // been received without other tasks having had a chance to run (in particular
   // the ResetMessageCount task posted here).
-  // TODO(altimin): Remove this after per-task mojo dispatching lands[1].
-  // [1] https://chromium-review.googlesource.com/c/chromium/src/+/1145692
   if (messages_in_current_task_ == 0) {
     task_runner_->PostTask(FROM_HERE, WTF::Bind(&MessagePort::ResetMessageCount,
                                                 WrapWeakPersistent(this)));
   }
-  if (ShouldYieldAfterNewMessage()) {
+  ++messages_in_current_task_;
+  if (messages_in_current_task_ > kMaximumMessagesPerTask) {
     connector_->PauseIncomingMethodCallProcessing();
   }
 
@@ -296,20 +291,9 @@
 void MessagePort::ResetMessageCount() {
   DCHECK_GT(messages_in_current_task_, 0);
   messages_in_current_task_ = 0;
-  task_start_time_ = base::nullopt;
   // No-op if not paused already.
   if (connector_)
     connector_->ResumeIncomingMethodCallProcessing();
 }
 
-bool MessagePort::ShouldYieldAfterNewMessage() {
-  ++messages_in_current_task_;
-  if (messages_in_current_task_ > kMaximumMessagesPerTask)
-    return true;
-  base::TimeTicks now = base::TimeTicks::Now();
-  if (!task_start_time_)
-    task_start_time_ = now;
-  return now - task_start_time_.value() > kYieldThreshold;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/messaging/message_port.h b/third_party/blink/renderer/core/messaging/message_port.h
index 41c3f8b2..f940655 100644
--- a/third_party/blink/renderer/core/messaging/message_port.h
+++ b/third_party/blink/renderer/core/messaging/message_port.h
@@ -135,7 +135,6 @@
   // mojo::MessageReceiver implementation.
   bool Accept(mojo::Message*) override;
   void ResetMessageCount();
-  bool ShouldYieldAfterNewMessage();
 
   std::unique_ptr<mojo::Connector> connector_;
   int messages_in_current_task_ = 0;
@@ -143,8 +142,6 @@
   bool started_ = false;
   bool closed_ = false;
 
-  base::Optional<base::TimeTicks> task_start_time_;
-
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
diff --git a/third_party/blink/renderer/core/messaging/post_message_options.idl b/third_party/blink/renderer/core/messaging/post_message_options.idl
new file mode 100644
index 0000000..d8dd000
--- /dev/null
+++ b/third_party/blink/renderer/core/messaging/post_message_options.idl
@@ -0,0 +1,9 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/whatwg/html/issues/3799
+
+dictionary PostMessageOptions {
+    sequence<object> transfer = [];
+};
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index a3c7196..0f3d66c 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -322,7 +322,7 @@
     ReplaceResourceProvider(CanvasResourceProvider::Create(
         surface_size, usage, SharedGpuContext::ContextProviderWrapper(), 0,
         context_->ColorParams(), presentation_mode,
-        std::move(dispatcher_weakptr)));
+        std::move(dispatcher_weakptr), false /* is_origin_top_left */));
 
     // The fallback chain for k*CompositedResourceUsage should never fall
     // all the way through to BitmapResourceProvider, except in unit tests.
diff --git a/third_party/blink/renderer/core/page/page_animator.cc b/third_party/blink/renderer/core/page/page_animator.cc
index 8d5ad84..4d91bf9 100644
--- a/third_party/blink/renderer/core/page/page_animator.cc
+++ b/third_party/blink/renderer/core/page/page_animator.cc
@@ -114,4 +114,11 @@
   view->UpdateAllLifecyclePhasesExceptPaint();
 }
 
+void PageAnimator::UpdateLifecycleToLayoutClean(LocalFrame& root_frame) {
+  LocalFrameView* view = root_frame.View();
+  base::AutoReset<bool> servicing(&updating_layout_and_style_for_painting_,
+                                  true);
+  view->UpdateLifecycleToLayoutClean();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/page_animator.h b/third_party/blink/renderer/core/page/page_animator.h
index 5d3531c2..3ee99c4 100644
--- a/third_party/blink/renderer/core/page/page_animator.h
+++ b/third_party/blink/renderer/core/page/page_animator.h
@@ -33,6 +33,7 @@
   // See documents of methods with the same names in LocalFrameView class.
   void UpdateAllLifecyclePhases(LocalFrame& root_frame);
   void UpdateAllLifecyclePhasesExceptPaint(LocalFrame& root_frame);
+  void UpdateLifecycleToLayoutClean(LocalFrame& root_frame);
   AnimationClock& Clock() { return animation_clock_; }
 
  private:
diff --git a/third_party/blink/renderer/core/page/page_widget_delegate.cc b/third_party/blink/renderer/core/page/page_widget_delegate.cc
index 9a7c5ec..311c87d0 100644
--- a/third_party/blink/renderer/core/page/page_widget_delegate.cc
+++ b/third_party/blink/renderer/core/page/page_widget_delegate.cc
@@ -61,7 +61,9 @@
     Page& page,
     LocalFrame& root,
     WebWidget::LifecycleUpdate requested_update) {
-  if (requested_update == WebWidget::LifecycleUpdate::kPrePaint) {
+  if (requested_update == WebWidget::LifecycleUpdate::kLayout) {
+    page.Animator().UpdateLifecycleToLayoutClean(root);
+  } else if (requested_update == WebWidget::LifecycleUpdate::kPrePaint) {
     page.Animator().UpdateAllLifecyclePhasesExceptPaint(root);
   } else {
     page.Animator().UpdateAllLifecyclePhases(root);
diff --git a/third_party/blink/renderer/core/page/pointer_lock_controller.cc b/third_party/blink/renderer/core/page/pointer_lock_controller.cc
index a4551c4..bfeb63e0 100644
--- a/third_party/blink/renderer/core/page/pointer_lock_controller.cc
+++ b/third_party/blink/renderer/core/page/pointer_lock_controller.cc
@@ -166,7 +166,7 @@
 void PointerLockController::EnqueueEvent(const AtomicString& type,
                                          Document* document) {
   if (document && document->domWindow()) {
-    document->domWindow()->EnqueueDocumentEvent(Event::Create(type),
+    document->domWindow()->EnqueueDocumentEvent(*Event::Create(type),
                                                 TaskType::kMiscPlatformAPI);
   }
 }
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
index 616035d..5e4a515 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
@@ -92,6 +92,21 @@
   return ToLayoutBox(element.GetLayoutObject())->GetScrollableArea();
 }
 
+bool ScrollsVerticalOverflow(LayoutView& layout_view) {
+  DCHECK(layout_view.GetScrollableArea());
+
+  if (layout_view.Size().IsZero() ||
+      !layout_view.GetScrollableArea()->HasVerticalOverflow() ||
+      !layout_view.ScrollsOverflowY())
+    return false;
+
+  ScrollbarMode h_mode;
+  ScrollbarMode v_mode;
+  layout_view.CalculateScrollbarModes(h_mode, v_mode);
+
+  return v_mode != kScrollbarAlwaysOff;
+}
+
 }  // namespace
 
 // static
@@ -374,9 +389,9 @@
   if (!document_->GetLayoutView())
     return;
 
-  // If the document has scrollable content, that's a good sign we shouldn't
-  // implicitly promote anything.
-  if (document_->GetLayoutView()->GetScrollableArea()->ScrollsOverflow())
+  // If the main document has vertical scrolling, that's a good sign we
+  // shouldn't implicitly promote anything.
+  if (ScrollsVerticalOverflow(*document_->GetLayoutView()))
     return;
 
   Element* highest_z_element = nullptr;
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index 8af7d56..4ace9aa9 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -2335,6 +2335,66 @@
       << "Once loaded, the iframe should be promoted.";
 }
 
+// Test that we don't promote any elements implicitly if the main document have
+// vertical overflow.
+TEST_F(ImplicitRootScrollerSimTest, OverflowInMainDocumentRestrictsImplicit) {
+  WebView().ResizeWithBrowserControls(IntSize(800, 600), 50, 0, true);
+  SimRequest main_request("https://example.com/test.html", "text/html");
+  SimRequest child_request("https://example.com/child.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  main_request.Complete(R"HTML(
+          <!DOCTYPE html>
+          <style>
+            ::-webkit-scrollbar {
+              width: 0px;
+              height: 0px;
+            }
+            body, html {
+              width: 100%;
+              height: 100%;
+              margin: 0px;
+            }
+            iframe {
+              width: 100%;
+              height: 100%;
+              border: 0;
+            }
+            div {
+              position: absolute;
+              left: 0;
+              top: 0;
+              height: 150%;
+              width: 150%;
+            }
+          </style>
+          <iframe id="container" src="child.html">
+          </iframe>
+          <div id="spacer"></div>
+      )HTML");
+  child_request.Complete(R"HTML(
+        <!DOCTYPE html>
+        <style>
+          body {
+            height: 1000px;
+          }
+        </style>
+  )HTML");
+
+  Compositor().BeginFrame();
+  EXPECT_EQ(GetDocument(),
+            GetDocument().GetRootScrollerController().EffectiveRootScroller())
+      << "iframe shouldn't be promoted due to overflow in the main document.";
+
+  Element* spacer = GetDocument().getElementById("spacer");
+  spacer->style()->setProperty(&GetDocument(), "height", "100%", String(),
+                               ASSERT_NO_EXCEPTION);
+  Compositor().BeginFrame();
+
+  EXPECT_EQ(GetDocument().getElementById("container"),
+            GetDocument().GetRootScrollerController().EffectiveRootScroller())
+      << "Once vertical overflow is removed, the iframe should be promoted.";
+}
+
 class RootScrollerHitTest : public RootScrollerTest {
  public:
   void CheckHitTestAtBottomOfScreen() {
diff --git a/third_party/blink/renderer/core/paint/BUILD.gn b/third_party/blink/renderer/core/paint/BUILD.gn
index f769e9c9..d8e2d9b4f 100644
--- a/third_party/blink/renderer/core/paint/BUILD.gn
+++ b/third_party/blink/renderer/core/paint/BUILD.gn
@@ -7,8 +7,6 @@
 blink_core_sources("paint") {
   split_count = 2
   sources = [
-    "adjust_paint_offset_scope.cc",
-    "adjust_paint_offset_scope.h",
     "applied_decoration_painter.cc",
     "applied_decoration_painter.h",
     "background_image_geometry.cc",
@@ -159,6 +157,8 @@
     "object_painter_base.h",
     "paint_event.h",
     "paint_info.h",
+    "paint_info_with_offset.cc",
+    "paint_info_with_offset.h",
     "paint_invalidator.cc",
     "paint_invalidator.h",
     "paint_layer.cc",
diff --git a/third_party/blink/renderer/core/paint/block_flow_painter.cc b/third_party/blink/renderer/core/paint/block_flow_painter.cc
index cc7810ab..dc29d0a 100644
--- a/third_party/blink/renderer/core/paint/block_flow_painter.cc
+++ b/third_party/blink/renderer/core/paint/block_flow_painter.cc
@@ -6,7 +6,6 @@
 
 #include "third_party/blink/renderer/core/layout/floating_objects.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/block_painter.h"
 #include "third_party/blink/renderer/core/paint/line_box_list_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
diff --git a/third_party/blink/renderer/core/paint/block_painter.cc b/third_party/blink/renderer/core/paint/block_painter.cc
index 3c688a1..c055a97a 100644
--- a/third_party/blink/renderer/core/paint/block_painter.cc
+++ b/third_party/blink/renderer/core/paint/block_painter.cc
@@ -12,12 +12,12 @@
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/block_flow_painter.h"
 #include "third_party/blink/renderer/core/paint/box_clipper.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
@@ -28,19 +28,19 @@
 
 DISABLE_CFI_PERF
 void BlockPainter::Paint(const PaintInfo& paint_info) {
-  AdjustPaintOffsetScope adjustment(layout_block_, paint_info);
-  auto paint_offset = adjustment.PaintOffset();
-  auto& local_paint_info = adjustment.MutablePaintInfo();
-
+  PaintInfoWithOffset paint_info_with_offset(layout_block_, paint_info);
   // We can't early return if there is no fragment to paint for this block,
   // because there may be overflowing children that exist in the painting
-  // fragment. We also can't check IntersectsPaintRect() in the case because we
+  // fragment. We also can't check ShouldPaint() in the case because we
   // don't have a meaningful paint offset. TODO(wangxianzhu): only paint
   // children if !adjustment.FragmentToPaint().
-  if (adjustment.FragmentToPaint() &&
-      !IntersectsPaintRect(local_paint_info, paint_offset))
+  if (paint_info_with_offset.FragmentToPaint() &&
+      !ShouldPaint(paint_info_with_offset))
     return;
 
+  auto paint_offset = paint_info_with_offset.PaintOffset();
+  auto& local_paint_info = paint_info_with_offset.MutablePaintInfo();
+
   PaintPhase original_phase = local_paint_info.phase;
 
   if (original_phase == PaintPhase::kOutline) {
@@ -276,16 +276,16 @@
 }
 
 DISABLE_CFI_PERF
-bool BlockPainter::IntersectsPaintRect(const PaintInfo& paint_info,
-                                       const LayoutPoint& paint_offset) const {
+bool BlockPainter::ShouldPaint(
+    const PaintInfoWithOffset& paint_info_with_offset) const {
   LayoutRect overflow_rect;
-  if (paint_info.IsPrinting() && layout_block_.IsAnonymousBlock() &&
-      layout_block_.ChildrenInline()) {
-    // For case <a href="..."><div>...</div></a>, when m_layoutBlock is the
+  if (paint_info_with_offset.GetPaintInfo().IsPrinting() &&
+      layout_block_.IsAnonymousBlock() && layout_block_.ChildrenInline()) {
+    // For case <a href="..."><div>...</div></a>, when layout_block_ is the
     // anonymous container of <a>, the anonymous container's visual overflow is
     // empty, but we need to continue painting to output <a>'s PDF URL rect
     // which covers the continuations, as if we included <a>'s PDF URL rect into
-    // m_layoutBlock's visual overflow.
+    // layout_block_'s visual overflow.
     Vector<LayoutRect> rects;
     layout_block_.AddElementVisualOverflowRects(rects, LayoutPoint());
     overflow_rect = UnionRect(rects);
@@ -307,8 +307,7 @@
     overflow_rect.Move(-layout_block_.ScrolledContentOffset());
   }
 
-  overflow_rect.MoveBy(paint_offset);
-  return paint_info.GetCullRect().IntersectsCullRect(overflow_rect);
+  return paint_info_with_offset.LocalRectIntersectsCullRect(overflow_rect);
 }
 
 void BlockPainter::PaintContents(const PaintInfo& paint_info,
diff --git a/third_party/blink/renderer/core/paint/block_painter.h b/third_party/blink/renderer/core/paint/block_painter.h
index 190d45e..c8f6de4 100644
--- a/third_party/blink/renderer/core/paint/block_painter.h
+++ b/third_party/blink/renderer/core/paint/block_painter.h
@@ -10,6 +10,7 @@
 namespace blink {
 
 struct PaintInfo;
+class PaintInfoWithOffset;
 class InlineBox;
 class LayoutBlock;
 class LayoutBox;
@@ -36,10 +37,7 @@
                                          const PaintInfo&);
   static void PaintInlineBox(const InlineBox&, const PaintInfo&);
 
-  // The adjustedPaintOffset should include the location (offset) of the object
-  // itself.
-  bool IntersectsPaintRect(const PaintInfo&,
-                           const LayoutPoint& paint_offset) const;
+  bool ShouldPaint(const PaintInfoWithOffset&) const;
 
  private:
   // Paint scroll hit test placeholders in the correct paint order (see:
diff --git a/third_party/blink/renderer/core/paint/box_painter.cc b/third_party/blink/renderer/core/paint/box_painter.cc
index 4bc1750..59fbcce 100644
--- a/third_party/blink/renderer/core/paint/box_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_painter.cc
@@ -11,7 +11,6 @@
 #include "third_party/blink/renderer/core/layout/layout_table.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
 #include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
@@ -20,6 +19,7 @@
 #include "third_party/blink/renderer/core/paint/nine_piece_image_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/svg_foreign_object_painter.h"
 #include "third_party/blink/renderer/core/paint/theme_painter.h"
 #include "third_party/blink/renderer/platform/geometry/layout_point.h"
@@ -33,8 +33,8 @@
 
 void BoxPainter::Paint(const PaintInfo& paint_info) {
   // Default implementation. Just pass paint through to the children.
-  AdjustPaintOffsetScope adjustment(layout_box_, paint_info);
-  PaintChildren(adjustment.GetPaintInfo());
+  PaintInfoWithOffset paint_info_with_offset(layout_box_, paint_info);
+  PaintChildren(paint_info_with_offset.GetPaintInfo());
 }
 
 void BoxPainter::PaintChildren(const PaintInfo& paint_info) {
diff --git a/third_party/blink/renderer/core/paint/collapsed_border_painter.cc b/third_party/blink/renderer/core/paint/collapsed_border_painter.cc
index 66d874d..135bfca6 100644
--- a/third_party/blink/renderer/core/paint/collapsed_border_painter.cc
+++ b/third_party/blink/renderer/core/paint/collapsed_border_painter.cc
@@ -4,10 +4,10 @@
 
 #include "third_party/blink/renderer/core/paint/collapsed_border_painter.h"
 
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/block_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/table_cell_painter.h"
 
 namespace blink {
@@ -350,10 +350,10 @@
   // Now left=start_, right=end_, before_=top, after_=bottom.
 
   // Collapsed borders are half inside and half outside of |rect|.
-  AdjustPaintOffsetScope adjustment(cell_, paint_info);
+  PaintInfoWithOffset paint_info_with_offset(cell_, paint_info);
   IntRect rect = PixelSnappedIntRect(
       TableCellPainter(cell_).PaintRectNotIncludingVisualOverflow(
-          adjustment.PaintOffset()));
+          paint_info_with_offset.PaintOffset()));
   // |paint_rect| covers the whole collapsed borders.
   IntRect paint_rect = rect;
   paint_rect.Expand(IntRectOutsets(before_.outer_width, end_.outer_width,
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index a2d0f67f..7d576c1 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -442,7 +442,7 @@
       !layer->DescendantHasDirectOrScrollingCompositingReason() &&
       !needs_recursion_for_composited_scrolling_plus_fixed_or_sticky &&
       !needs_recursion_for_out_of_flow_descendant &&
-      layer->GetLayoutObject().HasOverflowClip() &&
+      layer->GetLayoutObject().ShouldClipOverflow() &&
       !layer->HasCompositingDescendant() &&
       !layer->DescendantMayNeedCompositingRequirementsUpdate();
 
diff --git a/third_party/blink/renderer/core/paint/details_marker_painter.cc b/third_party/blink/renderer/core/paint/details_marker_painter.cc
index 7f1868f..2c525dcf 100644
--- a/third_party/blink/renderer/core/paint/details_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/details_marker_painter.cc
@@ -5,9 +5,9 @@
 #include "third_party/blink/renderer/core/paint/details_marker_painter.h"
 
 #include "third_party/blink/renderer/core/layout/layout_details_marker.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/block_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/platform/geometry/layout_point.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/path.h"
@@ -25,20 +25,20 @@
           paint_info.context, layout_details_marker_, paint_info.phase))
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_details_marker_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  auto box_origin = adjustment.PaintOffset();
-  LayoutRect overflow_rect(layout_details_marker_.VisualOverflowRect());
-  overflow_rect.MoveBy(box_origin);
-
-  if (!local_paint_info.GetCullRect().IntersectsCullRect(overflow_rect))
+  PaintInfoWithOffset paint_info_with_offset(layout_details_marker_,
+                                             paint_info);
+  // TODO(wangxianzhu): Flip VisualOverflowRect into physical coordinates.
+  if (!paint_info_with_offset.LocalRectIntersectsCullRect(
+          layout_details_marker_.VisualOverflowRect()))
     return;
 
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
   DrawingRecorder recorder(local_paint_info.context, layout_details_marker_,
                            local_paint_info.phase);
   const Color color(layout_details_marker_.ResolveColor(GetCSSPropertyColor()));
   local_paint_info.context.SetFillColor(color);
 
+  auto box_origin = paint_info_with_offset.PaintOffset();
   box_origin.Move(
       layout_details_marker_.BorderLeft() +
           layout_details_marker_.PaddingLeft(),
diff --git a/third_party/blink/renderer/core/paint/embedded_content_painter.cc b/third_party/blink/renderer/core/paint/embedded_content_painter.cc
index e75323dc..4c70338 100644
--- a/third_party/blink/renderer/core/paint/embedded_content_painter.cc
+++ b/third_party/blink/renderer/core/paint/embedded_content_painter.cc
@@ -7,10 +7,10 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/frame/embedded_content_view.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/replaced_painter.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
diff --git a/third_party/blink/renderer/core/paint/frame_set_painter.cc b/third_party/blink/renderer/core/paint/frame_set_painter.cc
index ac119bf..d45b623d 100644
--- a/third_party/blink/renderer/core/paint/frame_set_painter.cc
+++ b/third_party/blink/renderer/core/paint/frame_set_painter.cc
@@ -6,8 +6,8 @@
 
 #include "third_party/blink/renderer/core/html/html_frame_set_element.h"
 #include "third_party/blink/renderer/core/layout/layout_frame_set.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 
 namespace blink {
@@ -154,10 +154,10 @@
   if (!child)
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_frame_set_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
+  PaintInfoWithOffset paint_info_with_offset(layout_frame_set_, paint_info);
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
   PaintChildren(local_paint_info);
-  PaintBorders(local_paint_info, adjustment.PaintOffset());
+  PaintBorders(local_paint_info, paint_info_with_offset.PaintOffset());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/image_painter.cc b/third_party/blink/renderer/core/paint/image_painter.cc
index 43ba924..c467818 100644
--- a/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/third_party/blink/renderer/core/paint/image_painter.cc
@@ -15,8 +15,8 @@
 #include "third_party/blink/renderer/core/layout/text_run_constructor.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/platform/geometry/layout_point.h"
 #include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
@@ -61,8 +61,8 @@
   if (path.IsEmpty())
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_image_, paint_info);
-  auto paint_offset = adjustment.PaintOffset();
+  PaintInfoWithOffset paint_info_with_offset(layout_image_, paint_info);
+  auto paint_offset = paint_info_with_offset.PaintOffset();
   path.Translate(FloatSize(paint_offset.X(), paint_offset.Y()));
 
   if (DrawingRecorder::UseCachedDrawingIfPossible(
diff --git a/third_party/blink/renderer/core/paint/inline_painter.cc b/third_party/blink/renderer/core/paint/inline_painter.cc
index f40a16f..a467c04 100644
--- a/third_party/blink/renderer/core/paint/inline_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_painter.cc
@@ -6,19 +6,19 @@
 
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/line_box_list_painter.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/platform/geometry/layout_point.h"
 
 namespace blink {
 
 void InlinePainter::Paint(const PaintInfo& paint_info) {
-  AdjustPaintOffsetScope adjustment(layout_inline_, paint_info);
-  auto paint_offset = adjustment.PaintOffset();
-  const auto& local_paint_info = adjustment.GetPaintInfo();
+  PaintInfoWithOffset paint_info_with_offset(layout_inline_, paint_info);
+  auto paint_offset = paint_info_with_offset.PaintOffset();
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
 
   if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
     // Inline box with self painting layer is painted in this code path.
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index 4e03b11e..f5494b3f 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -530,12 +530,12 @@
 
 DocumentMarkerVector InlineTextBoxPainter::ComputeMarkersToPaint() const {
   Node* const node = inline_text_box_.GetLineLayoutItem().GetNode();
-  if (!node)
+  if (!node || !node->IsTextNode())
     return DocumentMarkerVector();
 
   DocumentMarkerController& document_marker_controller =
       inline_text_box_.GetLineLayoutItem().GetDocument().Markers();
-  return document_marker_controller.ComputeMarkersToPaint(*node);
+  return document_marker_controller.ComputeMarkersToPaint(ToText(*node));
 }
 
 void InlineTextBoxPainter::PaintDocumentMarkers(
diff --git a/third_party/blink/renderer/core/paint/list_marker_painter.cc b/third_party/blink/renderer/core/paint/list_marker_painter.cc
index 823fafa0..0981a540 100644
--- a/third_party/blink/renderer/core/paint/list_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/list_marker_painter.cc
@@ -7,9 +7,9 @@
 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
 #include "third_party/blink/renderer/core/layout/layout_list_marker.h"
 #include "third_party/blink/renderer/core/layout/list_marker_text.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
 #include "third_party/blink/renderer/core/paint/text_painter.h"
 #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
@@ -61,15 +61,15 @@
           paint_info.context, layout_list_marker_, paint_info.phase))
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_list_marker_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  auto box_origin = adjustment.PaintOffset();
-  LayoutRect overflow_rect(layout_list_marker_.VisualOverflowRect());
-  overflow_rect.MoveBy(box_origin);
-
-  if (!local_paint_info.GetCullRect().IntersectsCullRect(overflow_rect))
+  PaintInfoWithOffset paint_info_with_offset(layout_list_marker_, paint_info);
+  // TODO(wangxianzhu): Flip VisualOverflowRect into physical coordinates.
+  if (!paint_info_with_offset.LocalRectIntersectsCullRect(
+          layout_list_marker_.VisualOverflowRect()))
     return;
 
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
+  auto box_origin = paint_info_with_offset.PaintOffset();
+
   DrawingRecorder recorder(local_paint_info.context, layout_list_marker_,
                            local_paint_info.phase);
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 20a2fab..5d925da 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
 #include "third_party/blink/renderer/core/paint/list_marker_painter.h"
@@ -28,6 +27,7 @@
 #include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_phase.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
@@ -130,16 +130,15 @@
 }
 
 void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) {
-  AdjustPaintOffsetScope adjustment(box_fragment_, paint_info);
-  auto& info = adjustment.MutablePaintInfo();
-  auto paint_offset = adjustment.PaintOffset();
-
-  if (!IntersectsPaintRect(info, paint_offset))
+  PaintInfoWithOffset paint_info_with_offset(box_fragment_, paint_info);
+  if (!ShouldPaint(paint_info_with_offset))
     return;
 
+  PaintInfo& info = paint_info_with_offset.MutablePaintInfo();
   if (PhysicalFragment().IsAtomicInline())
     return PaintAtomicInline(info);
 
+  LayoutPoint paint_offset = paint_info_with_offset.PaintOffset();
   PaintPhase original_phase = info.phase;
 
   if (original_phase == PaintPhase::kOutline) {
@@ -521,9 +520,9 @@
 void NGBoxFragmentPainter::PaintAllPhasesAtomically(
     const PaintInfo& paint_info,
     bool is_self_painting) {
-  AdjustPaintOffsetScope adjustment(box_fragment_, paint_info);
-  auto paint_offset = adjustment.PaintOffset();
-  PaintInfo local_paint_info = adjustment.MutablePaintInfo();
+  PaintInfoWithOffset paint_info_with_offset(box_fragment_, paint_info);
+  auto paint_offset = paint_info_with_offset.PaintOffset();
+  PaintInfo& local_paint_info = paint_info_with_offset.MutablePaintInfo();
 
   // Pass PaintPhaseSelection and PaintPhaseTextClip is handled by the regular
   // foreground paint implementation. We don't need complete painting for these
@@ -733,14 +732,11 @@
   }
 }
 
-bool NGBoxFragmentPainter::IntersectsPaintRect(
-    const PaintInfo& paint_info,
-    const LayoutPoint& paint_offset) const {
-  // TODO(layout-dev): Add support for scrolling, see
-  // BlockPainter::IntersectsPaintRect.
-  LayoutRect overflow_rect(box_fragment_.SelfInkOverflow());
-  overflow_rect.MoveBy(paint_offset);
-  return paint_info.GetCullRect().IntersectsCullRect(overflow_rect);
+bool NGBoxFragmentPainter::ShouldPaint(
+    const PaintInfoWithOffset& paint_info_with_offset) const {
+  // TODO(layout-dev): Add support for scrolling, see BlockPainter::ShouldPaint.
+  return paint_info_with_offset.LocalRectIntersectsCullRect(
+      box_fragment_.SelfInkOverflow());
 }
 
 void NGBoxFragmentPainter::PaintTextClipMask(GraphicsContext& context,
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 5534781..1d59da30 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -23,6 +23,7 @@
 class LayoutRect;
 class NGPaintFragment;
 class NGPhysicalFragment;
+class PaintInfoWithOffset;
 struct PaintInfo;
 
 // Painter for LayoutNG box fragments, paints borders and background. Delegates
@@ -66,8 +67,7 @@
   bool IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
       const NGPaintFragment&,
       const PaintInfo&);
-  bool IntersectsPaintRect(const PaintInfo&,
-                           const LayoutPoint& paint_offset) const;
+  bool ShouldPaint(const PaintInfoWithOffset&) const;
 
   void PaintBoxDecorationBackground(const PaintInfo&,
                                     const LayoutPoint& paint_offset);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 5dd25cad..4910c70f 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -73,7 +73,7 @@
     const NGPaintFragment& paint_fragment) {
   // TODO(yoichio): Handle first-letter
   Node* const node = paint_fragment.GetNode();
-  if (!node)
+  if (!node || !node->IsTextNode())
     return DocumentMarkerVector();
   // We don't paint any marker on ellipsis.
   if (paint_fragment.PhysicalFragment().StyleVariant() ==
@@ -82,7 +82,7 @@
 
   DocumentMarkerController& document_marker_controller =
       node->GetDocument().Markers();
-  return document_marker_controller.ComputeMarkersToPaint(*node);
+  return document_marker_controller.ComputeMarkersToPaint(ToText(*node));
 }
 
 unsigned GetTextContentOffset(const Text& text, unsigned offset) {
diff --git a/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.cc b/third_party/blink/renderer/core/paint/paint_info_with_offset.cc
similarity index 87%
rename from third_party/blink/renderer/core/paint/adjust_paint_offset_scope.cc
rename to third_party/blink/renderer/core/paint/paint_info_with_offset.cc
index e0f8049..f2586bd 100644
--- a/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.cc
+++ b/third_party/blink/renderer/core/paint/paint_info_with_offset.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 
 namespace blink {
 
-void AdjustPaintOffsetScope::AdjustForPaintOffsetTranslation(
+void PaintInfoWithOffset::AdjustForPaintOffsetTranslation(
     const LayoutObject& object,
     const TransformPaintPropertyNode* paint_offset_translation) {
   if (input_paint_info_.context.InDrawingRecorder()) {
@@ -32,7 +32,7 @@
       paint_offset_translation->Matrix().ToAffineTransform());
 }
 
-void AdjustPaintOffsetScope::FinishPaintOffsetTranslationAsDrawing() {
+void PaintInfoWithOffset::FinishPaintOffsetTranslationAsDrawing() {
   // This scope should not interlace with scopes of DrawingRecorders.
   DCHECK(paint_offset_translation_as_drawing_);
   DCHECK(input_paint_info_.context.InDrawingRecorder());
diff --git a/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h b/third_party/blink/renderer/core/paint/paint_info_with_offset.h
similarity index 75%
rename from third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h
rename to third_party/blink/renderer/core/paint/paint_info_with_offset.h
index b698402..bd8a00b 100644
--- a/third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h
+++ b/third_party/blink/renderer/core/paint/paint_info_with_offset.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 THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_ADJUST_PAINT_OFFSET_SCOPE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_ADJUST_PAINT_OFFSET_SCOPE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_INFO_WITH_OFFSET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_INFO_WITH_OFFSET_H_
 
 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -14,15 +14,14 @@
 
 // Adjusts cull rect of the input PaintInfo and finds the paint offset for a
 // LayoutObject or an NGPaintFragment before painting. Normally a
-// Paint(const PaintInfo&) method creates an AdjustPaintOffsetScope and holds it
+// Paint(const PaintInfo&) method creates an PaintInfoWithOffset and holds it
 // in the stack, and passes it to other PaintXXX() methods that paint different
 // parts of the object.
-class AdjustPaintOffsetScope {
+class PaintInfoWithOffset {
   STACK_ALLOCATED();
 
  public:
-  AdjustPaintOffsetScope(const LayoutObject& object,
-                         const PaintInfo& paint_info)
+  PaintInfoWithOffset(const LayoutObject& object, const PaintInfo& paint_info)
       : fragment_to_paint_(paint_info.FragmentToPaint(object)),
         input_paint_info_(paint_info) {
     if (!fragment_to_paint_) {
@@ -41,11 +40,11 @@
     }
   }
 
-  AdjustPaintOffsetScope(const NGPaintFragment& fragment,
-                         const PaintInfo& paint_info)
-      : AdjustPaintOffsetScope(*fragment.GetLayoutObject(), paint_info) {}
+  PaintInfoWithOffset(const NGPaintFragment& fragment,
+                      const PaintInfo& paint_info)
+      : PaintInfoWithOffset(*fragment.GetLayoutObject(), paint_info) {}
 
-  ~AdjustPaintOffsetScope() {
+  ~PaintInfoWithOffset() {
     if (paint_offset_translation_as_drawing_)
       FinishPaintOffsetTranslationAsDrawing();
   }
@@ -70,6 +69,13 @@
 
   const FragmentData* FragmentToPaint() const { return fragment_to_paint_; }
 
+  bool LocalRectIntersectsCullRect(const LayoutRect& local_rect) const {
+    LayoutRect rect_in_paint_info_space = local_rect;
+    rect_in_paint_info_space.MoveBy(PaintOffset());
+    return GetPaintInfo().GetCullRect().IntersectsCullRect(
+        rect_in_paint_info_space);
+  }
+
  private:
   void AdjustForPaintOffsetTranslation(
       const LayoutObject&,
@@ -86,4 +92,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_ADJUST_PAINT_OFFSET_SCOPE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_INFO_WITH_OFFSET_H_
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index 30d0760..11fbcd3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -545,14 +545,14 @@
 
   bool VisualViewportSuppliesScrollbars() const override;
 
+  bool HasHorizontalOverflow() const;
+  bool HasVerticalOverflow() const;
+
   void Trace(blink::Visitor*) override;
 
  private:
   explicit PaintLayerScrollableArea(PaintLayer&);
 
-  bool HasHorizontalOverflow() const;
-  bool HasVerticalOverflow() const;
-
   bool NeedsScrollbarReconstruction() const;
 
   void ResetScrollOriginChanged() { scroll_origin_changed_ = false; }
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 a9d3c8e..550b002 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
@@ -145,12 +145,18 @@
   auto* positioned_scroll_translation =
       positioned_scroll_properties->ScrollTranslation();
   auto* positioned_scroll_node = positioned_scroll_translation->ScrollNode();
-  EXPECT_EQ(GetDocument()
-                .GetPage()
-                ->GetVisualViewport()
-                .GetScrollTranslationNode()
-                ->ScrollNode(),
-            positioned_scroll_node->Parent());
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(GetDocument()
+                  .GetPage()
+                  ->GetVisualViewport()
+                  .GetScrollTranslationNode()
+                  ->ScrollNode(),
+              positioned_scroll_node->Parent());
+  } else {
+    EXPECT_TRUE(positioned_scroll_node->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -3),
             positioned_scroll_translation->Matrix());
   EXPECT_EQ(nullptr, target1_properties->ScrollTranslation());
@@ -177,12 +183,18 @@
   auto* transformed_scroll_translation =
       transformed_scroll_properties->ScrollTranslation();
   auto* transformed_scroll_node = transformed_scroll_translation->ScrollNode();
-  EXPECT_EQ(GetDocument()
-                .GetPage()
-                ->GetVisualViewport()
-                .GetScrollTranslationNode()
-                ->ScrollNode(),
-            transformed_scroll_node->Parent());
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(GetDocument()
+                  .GetPage()
+                  ->GetVisualViewport()
+                  .GetScrollTranslationNode()
+                  ->ScrollNode(),
+              transformed_scroll_node->Parent());
+  } else {
+    EXPECT_TRUE(transformed_scroll_node->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -5),
             transformed_scroll_translation->Matrix());
   EXPECT_EQ(nullptr, target2_properties->ScrollTranslation());
@@ -386,9 +398,15 @@
   LocalFrameView* frame_view = GetDocument().View();
   frame_view->UpdateAllLifecyclePhases();
   EXPECT_EQ(TransformationMatrix(), DocPreTranslation()->Matrix());
-  EXPECT_EQ(
-      GetDocument().GetPage()->GetVisualViewport().GetScrollTranslationNode(),
-      DocPreTranslation()->Parent());
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(
+        GetDocument().GetPage()->GetVisualViewport().GetScrollTranslationNode(),
+        DocPreTranslation()->Parent());
+  } else {
+    EXPECT_TRUE(DocPreTranslation()->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -100),
             DocScrollTranslation()->Matrix());
   EXPECT_EQ(DocPreTranslation(), DocScrollTranslation()->Parent());
@@ -3307,12 +3325,18 @@
   auto* scroll_a_translation =
       overflow_a_scroll_properties->ScrollTranslation();
   auto* overflow_a_scroll_node = scroll_a_translation->ScrollNode();
-  EXPECT_EQ(GetDocument()
-                .GetPage()
-                ->GetVisualViewport()
-                .GetScrollTranslationNode()
-                ->ScrollNode(),
-            overflow_a_scroll_node->Parent());
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(GetDocument()
+                  .GetPage()
+                  ->GetVisualViewport()
+                  .GetScrollTranslationNode()
+                  ->ScrollNode(),
+              overflow_a_scroll_node->Parent());
+  } else {
+    EXPECT_TRUE(overflow_a_scroll_node->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -37),
             scroll_a_translation->Matrix());
   EXPECT_EQ(IntRect(0, 0, 5, 3), overflow_a_scroll_node->ContainerRect());
@@ -3429,12 +3453,16 @@
   auto* fixed_overflow_scroll_node = fixed_scroll_translation->ScrollNode();
   // The fixed position overflow scroll node is parented under the root, not the
   // dom-order parent or frame's scroll.
-  EXPECT_EQ(GetDocument()
-                .GetPage()
-                ->GetVisualViewport()
-                .GetScrollTranslationNode()
-                ->ScrollNode(),
-            fixed_overflow_scroll_node->Parent());
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(GetDocument()
+                  .GetPage()
+                  ->GetVisualViewport()
+                  .GetScrollTranslationNode()
+                  ->ScrollNode(),
+              fixed_overflow_scroll_node->Parent());
+  } else {
+    EXPECT_TRUE(fixed_overflow_scroll_node->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -43),
             fixed_scroll_translation->Matrix());
   EXPECT_EQ(IntRect(0, 0, 13, 11), fixed_overflow_scroll_node->ContainerRect());
@@ -3490,12 +3518,18 @@
   auto* scroll_a_translation =
       overflow_a_scroll_properties->ScrollTranslation();
   auto* overflow_a_scroll_node = scroll_a_translation->ScrollNode();
-  EXPECT_EQ(GetDocument()
-                .GetPage()
-                ->GetVisualViewport()
-                .GetScrollTranslationNode()
-                ->ScrollNode(),
-            overflow_a_scroll_node->Parent());
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(GetDocument()
+                  .GetPage()
+                  ->GetVisualViewport()
+                  .GetScrollTranslationNode()
+                  ->ScrollNode(),
+              overflow_a_scroll_node->Parent());
+  } else {
+    EXPECT_TRUE(overflow_a_scroll_node->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -37),
             scroll_a_translation->Matrix());
   EXPECT_EQ(IntRect(0, 0, 20, 20), overflow_a_scroll_node->ContainerRect());
@@ -4749,12 +4783,18 @@
   auto* scroll_translation = scroll_properties->ScrollTranslation();
   auto* paint_offset_translation = scroll_properties->PaintOffsetTranslation();
   auto* scroll_node = scroll_translation->ScrollNode();
-  EXPECT_EQ(GetDocument()
-                .GetPage()
-                ->GetVisualViewport()
-                .GetScrollTranslationNode()
-                ->ScrollNode(),
-            scroll_node->Parent());
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(GetDocument()
+                  .GetPage()
+                  ->GetVisualViewport()
+                  .GetScrollTranslationNode()
+                  ->ScrollNode(),
+              scroll_node->Parent());
+  } else {
+    EXPECT_TRUE(scroll_node->Parent()->IsRoot());
+  }
   EXPECT_EQ(TransformationMatrix().Translate(0, -42),
             scroll_translation->Matrix());
   // The paint offset node should be offset by the margin.
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 52f90e7..9c0248b1 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -268,12 +268,25 @@
                    ->ScrollTranslation()
                    ->ScrollNode()
                    ->HasBackgroundAttachmentFixedDescendants());
-  EXPECT_EQ(visual_viewport.GetScrollNode(), overflow_b->GetLayoutObject()
-                                                 ->FirstFragment()
-                                                 .PaintProperties()
-                                                 ->ScrollTranslation()
-                                                 ->ScrollNode()
-                                                 ->Parent());
+
+  // TODO(bokan): Viewport property node generation has been disabled
+  // temporarily with the flag off to diagnose https//crbug.com/868927.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    EXPECT_EQ(visual_viewport.GetScrollNode(), overflow_b->GetLayoutObject()
+                                                   ->FirstFragment()
+                                                   .PaintProperties()
+                                                   ->ScrollTranslation()
+                                                   ->ScrollNode()
+                                                   ->Parent());
+  } else {
+    EXPECT_TRUE(overflow_b->GetLayoutObject()
+                  ->FirstFragment()
+                  .PaintProperties()
+                  ->ScrollTranslation()
+                  ->ScrollNode()
+                  ->Parent()
+                  ->IsRoot());
+  }
 
   // Removing a main thread scrolling reason should update the entire tree.
   overflow_b->removeAttribute("class");
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index e94ac0f..78fa248 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -46,9 +46,11 @@
   if (needs_tree_builder_context_update)
     GeometryMapper::ClearCache();
 
-  VisualViewportPaintPropertyTreeBuilder::Update(
-      root_frame_view.GetPage()->GetVisualViewport(),
-      *context_storage_.back().tree_builder_context);
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+    VisualViewportPaintPropertyTreeBuilder::Update(
+        root_frame_view.GetPage()->GetVisualViewport(),
+        *context_storage_.back().tree_builder_context);
+  }
 
   Walk(root_frame_view);
   paint_invalidator_.ProcessPendingDelayedPaintInvalidations();
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.cc b/third_party/blink/renderer/core/paint/replaced_painter.cc
index 5d3a041..8a6cfc7 100644
--- a/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -8,11 +8,11 @@
 #include "third_party/blink/renderer/core/layout/api/selection_state.h"
 #include "third_party/blink/renderer/core/layout/layout_replaced.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/rounded_inner_rect_clipper.h"
 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
@@ -35,13 +35,12 @@
       cache_skipper.emplace(paint_info.context);
   }
 
-  AdjustPaintOffsetScope adjustment(layout_replaced_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  auto paint_offset = adjustment.PaintOffset();
-
-  if (!ShouldPaint(local_paint_info, paint_offset))
+  PaintInfoWithOffset paint_info_with_offset(layout_replaced_, paint_info);
+  if (!ShouldPaint(paint_info_with_offset))
     return;
 
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
+  auto paint_offset = paint_info_with_offset.PaintOffset();
   LayoutRect border_rect(paint_offset, layout_replaced_.Size());
 
   if (ShouldPaintSelfBlockBackground(local_paint_info.phase)) {
@@ -161,8 +160,9 @@
   }
 }
 
-bool ReplacedPainter::ShouldPaint(const PaintInfo& paint_info,
-                                  const LayoutPoint& paint_offset) const {
+bool ReplacedPainter::ShouldPaint(
+    const PaintInfoWithOffset& paint_info_with_offset) const {
+  const auto& paint_info = paint_info_with_offset.GetPaintInfo();
   if (paint_info.phase != PaintPhase::kForeground &&
       !ShouldPaintSelfOutline(paint_info.phase) &&
       paint_info.phase != PaintPhase::kSelection &&
@@ -180,11 +180,9 @@
       layout_replaced_.Style()->Visibility() != EVisibility::kVisible)
     return false;
 
-  LayoutRect paint_rect(layout_replaced_.VisualOverflowRect());
-  paint_rect.Unite(layout_replaced_.LocalSelectionRect());
-  paint_rect.MoveBy(paint_offset);
-
-  if (!paint_info.GetCullRect().IntersectsCullRect(paint_rect))
+  LayoutRect local_rect(layout_replaced_.VisualOverflowRect());
+  local_rect.Unite(layout_replaced_.LocalSelectionRect());
+  if (!paint_info_with_offset.LocalRectIntersectsCullRect(local_rect))
     return false;
 
   return true;
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.h b/third_party/blink/renderer/core/paint/replaced_painter.h
index 6cbc1381..b0579dd9 100644
--- a/third_party/blink/renderer/core/paint/replaced_painter.h
+++ b/third_party/blink/renderer/core/paint/replaced_painter.h
@@ -10,7 +10,7 @@
 namespace blink {
 
 struct PaintInfo;
-class LayoutPoint;
+class PaintInfoWithOffset;
 class LayoutReplaced;
 
 class ReplacedPainter {
@@ -22,7 +22,7 @@
 
   void Paint(const PaintInfo&);
 
-  bool ShouldPaint(const PaintInfo&, const LayoutPoint& paint_offset) const;
+  bool ShouldPaint(const PaintInfoWithOffset&) const;
 
  private:
   const LayoutReplaced& layout_replaced_;
diff --git a/third_party/blink/renderer/core/paint/table_cell_painter.cc b/third_party/blink/renderer/core/paint/table_cell_painter.cc
index 226d034..af876cc6 100644
--- a/third_party/blink/renderer/core/paint/table_cell_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_cell_painter.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/core/paint/table_cell_painter.h"
 
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 #include "third_party/blink/renderer/core/paint/block_painter.h"
 #include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
@@ -13,6 +12,7 @@
 #include "third_party/blink/renderer/core/paint/box_painter_base.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 
@@ -32,10 +32,11 @@
       !layout_table_cell_.FirstChild())
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_table_cell_, paint_info);
+  PaintInfoWithOffset paint_info_with_offset(layout_table_cell_, paint_info);
   auto paint_rect =
-      PaintRectNotIncludingVisualOverflow(adjustment.PaintOffset());
-  PaintBackground(adjustment.GetPaintInfo(), paint_rect, background_object);
+      PaintRectNotIncludingVisualOverflow(paint_info_with_offset.PaintOffset());
+  PaintBackground(paint_info_with_offset.GetPaintInfo(), paint_rect,
+                  background_object);
 }
 
 void TableCellPainter::PaintBackground(const PaintInfo& paint_info,
diff --git a/third_party/blink/renderer/core/paint/table_row_painter.cc b/third_party/blink/renderer/core/paint/table_row_painter.cc
index e7e29a9..450b3a1 100644
--- a/third_party/blink/renderer/core/paint/table_row_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_row_painter.cc
@@ -6,12 +6,12 @@
 
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
 #include "third_party/blink/renderer/core/layout/layout_table_row.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
 #include "third_party/blink/renderer/core/paint/box_painter_base.h"
 #include "third_party/blink/renderer/core/paint/collapsed_border_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/table_cell_painter.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 
@@ -50,9 +50,10 @@
 
 void TableRowPainter::PaintOutline(const PaintInfo& paint_info) {
   DCHECK(ShouldPaintSelfOutline(paint_info.phase));
-  AdjustPaintOffsetScope adjustment(layout_table_row_, paint_info);
+  PaintInfoWithOffset paint_info_with_offset(layout_table_row_, paint_info);
   ObjectPainter(layout_table_row_)
-      .PaintOutline(adjustment.GetPaintInfo(), adjustment.PaintOffset());
+      .PaintOutline(paint_info_with_offset.GetPaintInfo(),
+                    paint_info_with_offset.PaintOffset());
 }
 
 void TableRowPainter::HandleChangedPartialPaint(
@@ -77,14 +78,14 @@
 
   HandleChangedPartialPaint(paint_info, dirtied_columns);
 
+  PaintInfoWithOffset paint_info_with_offset(layout_table_row_, paint_info);
   if (DrawingRecorder::UseCachedDrawingIfPossible(
           paint_info.context, layout_table_row_,
           DisplayItem::kBoxDecorationBackground))
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_table_row_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  auto paint_offset = adjustment.PaintOffset();
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
+  auto paint_offset = paint_info_with_offset.PaintOffset();
   DrawingRecorder recorder(local_paint_info.context, layout_table_row_,
                            DisplayItem::kBoxDecorationBackground);
   LayoutRect paint_rect(paint_offset, layout_table_row_.Size());
diff --git a/third_party/blink/renderer/core/paint/table_section_painter.cc b/third_party/blink/renderer/core/paint/table_section_painter.cc
index 85d6a08..eeec607 100644
--- a/third_party/blink/renderer/core/paint/table_section_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_section_painter.cc
@@ -8,13 +8,13 @@
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
 #include "third_party/blink/renderer/core/layout/layout_table_col.h"
 #include "third_party/blink/renderer/core/layout/layout_table_row.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/box_clipper.h"
 #include "third_party/blink/renderer/core/paint/box_painter.h"
 #include "third_party/blink/renderer/core/paint/box_painter_base.h"
 #include "third_party/blink/renderer/core/paint/collapsed_border_painter.h"
 #include "third_party/blink/renderer/core/paint/object_painter.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/table_cell_painter.h"
 #include "third_party/blink/renderer/core/paint/table_row_painter.h"
@@ -65,9 +65,9 @@
   if (!total_rows || !total_cols)
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_table_section_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  auto paint_offset = adjustment.PaintOffset();
+  PaintInfoWithOffset paint_info_with_offset(layout_table_section_, paint_info);
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
+  auto paint_offset = paint_info_with_offset.PaintOffset();
 
   if (local_paint_info.phase != PaintPhase::kSelfOutlineOnly) {
     base::Optional<BoxClipper> box_clipper;
@@ -125,9 +125,9 @@
       !layout_table_section_.Table()->EffectiveColumns().size())
     return;
 
-  AdjustPaintOffsetScope adjustment(layout_table_section_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  auto paint_offset = adjustment.PaintOffset();
+  PaintInfoWithOffset paint_info_with_offset(layout_table_section_, paint_info);
+  const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
+  auto paint_offset = paint_info_with_offset.PaintOffset();
   BoxClipper box_clipper(layout_table_section_, local_paint_info);
 
   CellSpan dirtied_rows;
diff --git a/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc b/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc
index b63136d1..04dad1b 100644
--- a/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc
+++ b/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc
@@ -6,8 +6,8 @@
 
 #include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
-#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
 #include "third_party/blink/renderer/core/paint/block_painter.h"
+#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
 #include "third_party/blink/renderer/core/paint/theme_painter.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 
@@ -38,12 +38,11 @@
   }
 
   // Convert the rect into the coords used for painting the content.
-  AdjustPaintOffsetScope adjustment(text_control_, paint_info);
-  const auto& local_paint_info = adjustment.GetPaintInfo();
-  contents_rect.MoveBy(adjustment.PaintOffset());
+  PaintInfoWithOffset paint_info_with_offset(text_control_, paint_info);
+  contents_rect.MoveBy(paint_info_with_offset.PaintOffset());
   IntRect snapped_rect = PixelSnappedIntRect(contents_rect);
   LayoutTheme::GetTheme().Painter().PaintCapsLockIndicator(
-      text_control_, local_paint_info, snapped_rect);
+      text_control_, paint_info_with_offset.GetPaintInfo(), snapped_rect);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 688d8ba..2b63218 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2220,9 +2220,7 @@
   InterpolationQuality GetInterpolationQuality() const;
 
   bool CanGeneratePseudoElement(PseudoId pseudo) const {
-    // The first letter pseudo element has to look up the tree and see if any
-    // of the ancestors are first letter.
-    if (pseudo != kPseudoIdFirstLetter && !HasPseudoStyle(pseudo))
+    if (!HasPseudoStyle(pseudo))
       return false;
     if (Display() == EDisplay::kNone)
       return false;
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.cc b/third_party/blink/renderer/core/svg/svg_image_element.cc
index 3a846fc5..e849c73 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_image_element.cc
@@ -154,8 +154,7 @@
 
 void SVGImageElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == SVGNames::decodingAttr &&
-      RuntimeEnabledFeatures::ImageDecodingAttributeEnabled()) {
+  if (params.name == SVGNames::decodingAttr) {
     UseCounter::Count(GetDocument(), WebFeature::kImageDecodingAttribute);
     decoding_mode_ = ParseImageDecodingMode(params.new_value);
   } else {
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.idl b/third_party/blink/renderer/core/svg/svg_image_element.idl
index 33f1d31..f8a393b 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.idl
+++ b/third_party/blink/renderer/core/svg/svg_image_element.idl
@@ -33,7 +33,7 @@
     [MeasureAs=SVG1DOMImageElement] readonly attribute SVGAnimatedLength width;
     [MeasureAs=SVG1DOMImageElement] readonly attribute SVGAnimatedLength height;
     [MeasureAs=SVG1DOMImageElement] readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
-    [RuntimeEnabled=ImageDecodingAttribute, CEReactions, Reflect, ReflectOnly=("async", "sync", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString decoding;
+    [CEReactions, Reflect, ReflectOnly=("async", "sync", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString decoding;
 
     [RuntimeEnabled=JSImageDecode, CallWith=ScriptState, RaisesException] Promise decode();
 };
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index cac8c17..d8971a25 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -936,7 +936,7 @@
 
   return node->GetDocument()
       .Markers()
-      .MarkersFor(node, marker_types.value())
+      .MarkersFor(ToText(node), marker_types.value())
       .size();
 }
 
@@ -945,7 +945,7 @@
 
   // Only TextMatch markers can be active.
   DocumentMarkerVector markers = node->GetDocument().Markers().MarkersFor(
-      node, DocumentMarker::MarkerTypes::TextMatch());
+      ToText(node), DocumentMarker::MarkerTypes::TextMatch());
 
   unsigned active_marker_count = 0;
   for (const auto& marker : markers) {
@@ -970,8 +970,8 @@
     return nullptr;
   }
 
-  DocumentMarkerVector markers =
-      node->GetDocument().Markers().MarkersFor(node, marker_types.value());
+  DocumentMarkerVector markers = node->GetDocument().Markers().MarkersFor(
+      ToText(node), marker_types.value());
   if (markers.size() <= index)
     return nullptr;
   return markers[index];
@@ -3446,4 +3446,9 @@
   }
   return performance_monitor->BypassLongCompileThresholdOnceForTesting();
 }
+
+unsigned Internals::LifecycleUpdateCount() const {
+  return document_->View()->LifecycleUpdateCountForTesting();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index 0a744c0..1f8fb709 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -588,6 +588,10 @@
 
   void BypassLongCompileThresholdOnce(ExceptionState&);
 
+  // The number of calls to update the blink lifecycle (see:
+  // LocalFrameView::UpdateLifecyclePhasesInternal).
+  unsigned LifecycleUpdateCount() const;
+
  private:
   explicit Internals(ExecutionContext*);
   Document* ContextDocument() const;
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index aaec0fa..b4d63f2 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -407,4 +407,8 @@
     // PerformanceMonitor for testing. "PerformanceObserver should be observing
     // 'longtask' while calling BypassLongCompileThresholdOnce.
     [RaisesException] void BypassLongCompileThresholdOnce();
+
+    // The number of calls to update the blink lifecycle (see:
+    // LocalFrameView::UpdateLifecyclePhasesInternal).
+    unsigned long LifecycleUpdateCount();
 };
diff --git a/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js b/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js
index ab71f33..a9a2beb 100644
--- a/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js
+++ b/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js
@@ -179,6 +179,8 @@
     async function validateStatus(status) {
       if (!status)
         return null;
+      if (networkSourceCode[Persistence.Automapping._processingPromise] !== createBindingPromise)
+        return null;
       if (status.network.contentType().isFromSourceMap() || !status.fileSystem.contentType().isTextType())
         return status;
 
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
index 4662fcb6..eb3f0fc2 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
+++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
@@ -57,8 +57,24 @@
     let text = `Sampling memory profile.\n\nDate/Time:       ${new Date()}\n` +
         `Report Version:  7\nNode weight:     1 KiB\n----\n\nCall graph:\n`;
     const sortedChildren = this.profile.root.children.sort((a, b) => b.total - a.total);
+    const modules = this.profile.modules.map(
+        m => Object.assign({address: BigInt(m.baseAddress), endAddress: BigInt(m.baseAddress) + BigInt(m.size)}, m));
+    modules.sort((m1, m2) => m1.address - m2.address);
     for (const child of sortedChildren)
       printTree('    ', child !== sortedChildren.peekLast(), child);
+
+    text += '\nBinary Images:\n';
+    for (const module of modules) {
+      const fileName = /[^/\\]*$/.exec(module.name)[0];
+      const version = '1.0';
+      const formattedUuid = module.uuid.includes('-') ?
+          module.uuid :
+          module.uuid.replace(/(.{8})(.{4})(.{4})(.{4})(.{12}).*/, '$1-$2-$3-$4-$5');
+      text += `${('0x' + module.address.toString(16)).padStart(18)} - `;
+      text += `${('0x' + (module.endAddress - BigInt(1)).toString(16)).padStart(18)}`;
+      text += `  ${fileName} (${version}) <${formattedUuid}> ${module.name}\n`;
+    }
+
     view.contentElement.createChild('pre', 'profile-text-view monospace').textContent = text;
 
     /**
@@ -67,10 +83,27 @@
      * @param {!SDK.ProfileNode} node
      */
     function printTree(padding, drawGuide, node) {
-      const isAddress = node.functionName.startsWith('0x');
-      const functionName = isAddress ? '???' : node.functionName;
-      const address = isAddress ? node.functionName : '???';
-      text += `${padding}${Math.round(node.total / 1024)}  ${functionName}  [${address}]\n`;
+      const addressText = /0x[0-9a-f]*|[0-9]*/.exec(node.functionName)[0] || '';
+      let module;
+      if (addressText) {
+        const address = BigInt(addressText);
+        const pos = modules.upperBound(address, (address, module) => address - module.address);
+        if (pos > 0 && address < modules[pos - 1].endAddress)
+          module = modules[pos - 1];
+      }
+      const functionName =
+          (addressText ? node.functionName.substr(addressText.length + 1) : node.functionName) || '???';
+      text += `${padding}${Math.round(node.total / 1024)}  ${functionName}  `;
+      if (module) {
+        const fileName = /[^/\\]*$/.exec(module.name);
+        if (fileName)
+          text += `(in ${fileName})  `;
+        const offset = BigInt(addressText) - module.address;
+        text += `load address ${module.baseAddress} + 0x${offset.toString(16)}  `;
+      }
+      if (addressText)
+        text += `[${addressText}]`;
+      text += '\n';
       const guideChar = drawGuide ? guides[padding.length / 2 % guides.length] : ' ';
       const nextPadding = padding + guideChar + ' ';
       const sortedChildren = node.children.sort((a, b) => b.total - a.total);
@@ -351,8 +384,8 @@
    * @param {!SDK.HeapProfilerModel} heapProfilerModel
    * @return {!Promise<!Protocol.HeapProfiler.SamplingHeapProfile>}
    */
-  _takeNativeSnapshot(heapProfilerModel) {
-    return heapProfilerModel.takeNativeBrowserSnapshot();
+  async _takeNativeSnapshot(heapProfilerModel) {
+    return await heapProfilerModel.takeNativeBrowserSnapshot();
   }
 };
 
@@ -442,6 +475,7 @@
   constructor(profile) {
     super();
     this.initialize(translateProfileTree(profile.head));
+    this.modules = profile.modules || [];
 
     /**
      * @param {!Protocol.HeapProfiler.SamplingHeapProfileNode} root
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/HeapProfilerModel.js b/third_party/blink/renderer/devtools/front_end/sdk/HeapProfilerModel.js
index f1330463..7de6630 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/HeapProfilerModel.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/HeapProfilerModel.js
@@ -55,7 +55,7 @@
   }
 
   /**
-   * @return {!Promise<!Protocol.HeapProfiler.SamplingHeapProfile>}
+   * @return {!Promise<!SDK.HeapProfilerModel.NativeHeapProfile>}
    */
   async stopNativeSampling() {
     const rawProfile = await this._memoryAgent.getSamplingProfile();
@@ -64,7 +64,7 @@
   }
 
   /**
-   * @return {!Promise<!Protocol.HeapProfiler.SamplingHeapProfile>}
+   * @return {!Promise<!SDK.HeapProfilerModel.NativeHeapProfile>}
    */
   async takeNativeSnapshot() {
     const rawProfile = await this._memoryAgent.getAllTimeSamplingProfile();
@@ -72,7 +72,7 @@
   }
 
   /**
-   * @return {!Promise<!Protocol.HeapProfiler.SamplingHeapProfile>}
+   * @return {!Promise<!SDK.HeapProfilerModel.NativeHeapProfile>}
    */
   async takeNativeBrowserSnapshot() {
     const rawProfile = await this._memoryAgent.getBrowserSamplingProfile();
@@ -81,10 +81,11 @@
 
   /**
    * @param {!Protocol.Memory.SamplingProfile} rawProfile
-   * @return {!Protocol.HeapProfiler.SamplingHeapProfile}
+   * @return {!SDK.HeapProfilerModel.NativeHeapProfile}
    */
   _convertNativeProfile(rawProfile) {
-    const head = {children: new Map(), selfSize: 0, callFrame: {functionName: '(root)', url: ''}};
+    const head = /** @type {!Protocol.HeapProfiler.SamplingHeapProfileNode} */
+        ({children: new Map(), selfSize: 0, callFrame: {functionName: '(root)', url: ''}});
     for (const sample of rawProfile.samples) {
       const node = sample.stack.reverse().reduce((node, name) => {
         let child = node.children.get(name);
@@ -108,7 +109,7 @@
     }
     convertChildren(head);
 
-    return /** @type {!Protocol.HeapProfiler.SamplingHeapProfile} */ ({head});
+    return new SDK.HeapProfilerModel.NativeHeapProfile(head, rawProfile.modules);
   }
 
   /**
@@ -218,6 +219,20 @@
 };
 
 /**
+ * @extends {Protocol.HeapProfiler.SamplingHeapProfile}
+ */
+SDK.HeapProfilerModel.NativeHeapProfile = class {
+  /**
+   * @param {!Protocol.HeapProfiler.SamplingHeapProfileNode} head
+   * @param {!Array<!Protocol.Memory.Module>} modules
+   */
+  constructor(head, modules) {
+    this.head = head;
+    this.modules = modules;
+  }
+};
+
+/**
  * @extends {Protocol.HeapProfilerDispatcher}
  * @unrestricted
  */
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 3a21108..6a99137 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -1179,7 +1179,8 @@
     return;
 
   DocumentMarkerController& marker_controller = GetDocument()->Markers();
-  DocumentMarkerVector markers = marker_controller.MarkersFor(GetNode());
+  DocumentMarkerVector markers =
+      marker_controller.MarkersFor(ToText(GetNode()));
   for (size_t i = 0; i < markers.size(); ++i) {
     DocumentMarker* marker = markers[i];
     if (MarkerTypeIsUsedForAccessibility(marker->GetType())) {
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index 64fdaf850..8f74995 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -4,11 +4,14 @@
 
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h"
 
+#include "base/memory/scoped_refptr.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/request_or_usv_string_or_request_or_usv_string_sequence.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/fetch/body.h"
+#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
 #include "third_party/blink/renderer/core/fetch/request.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
@@ -22,6 +25,7 @@
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
 #include "third_party/blink/renderer/platform/network/network_utils.h"
@@ -156,6 +160,31 @@
   return false;
 }
 
+scoped_refptr<BlobDataHandle> ExtractBlobHandle(
+    Request* request,
+    ExceptionState& exception_state) {
+  DCHECK(request);
+
+  if (request->IsBodyLocked(exception_state) == Body::BodyLocked::kLocked ||
+      request->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) {
+    DCHECK(!exception_state.HadException());
+    exception_state.ThrowTypeError("Request body is already used");
+    return nullptr;
+  }
+
+  BodyStreamBuffer* buffer = request->BodyBuffer();
+  if (!buffer)
+    return nullptr;
+
+  auto blob_handle = buffer->DrainAsBlobDataHandle(
+      BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize,
+      exception_state);
+  if (exception_state.HadException())
+    return nullptr;
+
+  return blob_handle;
+}
+
 }  // namespace
 
 BackgroundFetchManager::BackgroundFetchManager(
@@ -383,11 +412,15 @@
 
       DCHECK(request);
       request->PopulateWebServiceWorkerRequest(web_requests[i]);
+      web_requests[i].SetBlobDataHandle(
+          ExtractBlobHandle(request, exception_state));
     }
   } else if (requests.IsRequest()) {
     DCHECK(requests.GetAsRequest());
     web_requests.resize(1);
     requests.GetAsRequest()->PopulateWebServiceWorkerRequest(web_requests[0]);
+    web_requests[0].SetBlobDataHandle(
+        ExtractBlobHandle(requests.GetAsRequest(), exception_state));
   } else if (requests.IsUSVString()) {
     Request* request = Request::Create(script_state, requests.GetAsUSVString(),
                                        exception_state);
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc
index c962f63..063d42f 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/core/fetch/request_init.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/blob/blob_data.h"
 
 namespace blink {
 
@@ -175,4 +176,48 @@
             ESErrorType::kTypeError);
 }
 
+TEST_F(BackgroundFetchManagerTest, BlobsExtracted) {
+  V8TestingScope scope;
+
+  KURL image_url("https://www.example.com/my_image.png");
+  KURL icon_url("https://www.example.com/my_icon.jpg");
+
+  // Create first request with a body.
+  String body_text = "cat_pic";
+  RequestInit request_init;
+  request_init.setMethod("POST");
+  request_init.setBody(blink::ScriptValue(
+      scope.GetScriptState(), ToV8(body_text, scope.GetScriptState())));
+  Request* image_request =
+      Request::Create(scope.GetScriptState(), image_url.GetString(),
+                      request_init, scope.GetExceptionState());
+  ASSERT_FALSE(scope.GetExceptionState().HadException());
+  ASSERT_TRUE(image_request);
+  ASSERT_TRUE(image_request->HasBody());
+
+  // Create second request without a body.
+  RequestOrUSVString icon_request =
+      RequestOrUSVString::FromUSVString(icon_url.GetString());
+
+  // Create a request sequence with both requests.
+  HeapVector<RequestOrUSVString> request_sequence;
+  request_sequence.push_back(RequestOrUSVString::FromRequest(image_request));
+  request_sequence.push_back(icon_request);
+
+  RequestOrUSVStringOrRequestOrUSVStringSequence requests =
+      RequestOrUSVStringOrRequestOrUSVStringSequence::
+          FromRequestOrUSVStringSequence(request_sequence);
+
+  // Extract the blobs.
+  auto web_requests = CreateWebRequestVector(scope, requests);
+  ASSERT_FALSE(scope.GetExceptionState().HadException());
+
+  ASSERT_EQ(web_requests.size(), 2u);
+
+  ASSERT_TRUE(web_requests[0].GetBlobDataHandle());
+  EXPECT_EQ(web_requests[0].GetBlobDataHandle()->size(), body_text.length());
+
+  EXPECT_FALSE(web_requests[1].GetBlobDataHandle());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
index 2e48b960..7a4a0ef 100644
--- a/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
+++ b/third_party/blink/renderer/modules/broadcastchannel/broadcast_channel.cc
@@ -107,7 +107,7 @@
     event = MessageEvent::CreateError(
         GetExecutionContext()->GetSecurityOrigin()->ToString());
   }
-  EnqueueEvent(event, TaskType::kPostedMessage);
+  EnqueueEvent(*event, TaskType::kPostedMessage);
 }
 
 void BroadcastChannel::OnError() {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 5c8de91..d8a74b25 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -168,6 +168,12 @@
   return layer_bridge->IsAccelerated();
 }
 
+bool CanvasRenderingContext2D::IsOriginTopLeft() const {
+  // Accelerated 2D contexts have the origin of coordinates on the bottom left,
+  // except if they are single buffered (needed for front buffer rendering).
+  return !IsAccelerated() || canvas()->ResourceProvider()->IsSingleBuffered();
+}
+
 bool CanvasRenderingContext2D::IsComposited() const {
   return IsAccelerated();
 }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 093d6c34..ca5ab3b 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -244,6 +244,7 @@
   bool Is2d() const override { return true; }
   bool IsComposited() const override;
   bool IsAccelerated() const override;
+  bool IsOriginTopLeft() const override;
   bool HasAlpha() const override { return CreationAttributes().alpha; }
   void SetIsHidden(bool) override;
   void Stop() final;
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc b/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
index 05b5a3fe..482abd90 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
@@ -900,7 +900,7 @@
   MediaKeyMessageEvent* event =
       MediaKeyMessageEvent::Create(EventTypeNames::message, init);
   event->SetTarget(this);
-  async_event_queue_->EnqueueEvent(FROM_HERE, event);
+  async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 void MediaKeySession::Close() {
@@ -985,7 +985,7 @@
   //    at the session.
   Event* event = Event::Create(EventTypeNames::keystatuseschange);
   event->SetTarget(this);
-  async_event_queue_->EnqueueEvent(FROM_HERE, event);
+  async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 
   // 6. Queue a task to run the attempt to resume playback if necessary
   //    algorithm on each of the media element(s) whose mediaKeys attribute
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index 313725c..9a0acee7 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -301,24 +301,19 @@
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   Document* document = ToDocument(execution_context);
 
-  if (RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-    if (!document->GetFrame() ||
-        !document->GetFrame()->IsFeatureEnabled(
-            mojom::FeaturePolicyFeature::kEncryptedMedia)) {
-      UseCounter::Count(document,
-                        WebFeature::kEncryptedMediaDisabledByFeaturePolicy);
-      document->AddConsoleMessage(
-          ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
-                                 kEncryptedMediaFeaturePolicyConsoleWarning));
-      return ScriptPromise::RejectWithDOMException(
-          script_state,
-          DOMException::Create(
-              DOMExceptionCode::kSecurityError,
-              "requestMediaKeySystemAccess is disabled by feature policy."));
-    }
-  } else {
-    Deprecation::CountDeprecationFeaturePolicy(
-        *document, mojom::FeaturePolicyFeature::kEncryptedMedia);
+  if (!document->GetFrame() ||
+      !document->GetFrame()->IsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kEncryptedMedia)) {
+    UseCounter::Count(document,
+                      WebFeature::kEncryptedMediaDisabledByFeaturePolicy);
+    document->AddConsoleMessage(
+        ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
+                               kEncryptedMediaFeaturePolicyConsoleWarning));
+    return ScriptPromise::RejectWithDOMException(
+        script_state,
+        DOMException::Create(
+            DOMExceptionCode::kSecurityError,
+            "requestMediaKeySystemAccess is disabled by feature policy."));
   }
 
   // From https://w3c.github.io/encrypted-media/#requestMediaKeySystemAccess
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
index 20abe6a..f3771a1 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
@@ -26,7 +26,7 @@
 }
 
 void GamepadDispatcher::PlayVibrationEffectOnce(
-    int pad_index,
+    uint32_t pad_index,
     device::mojom::blink::GamepadHapticEffectType type,
     device::mojom::blink::GamepadEffectParametersPtr params,
     GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
@@ -36,7 +36,7 @@
 }
 
 void GamepadDispatcher::ResetVibrationActuator(
-    int pad_index,
+    uint32_t pad_index,
     GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
   InitializeHaptics();
   gamepad_haptics_manager_->ResetVibrationActuator(pad_index,
@@ -58,21 +58,27 @@
   PlatformEventDispatcher::Trace(visitor);
 }
 
-void GamepadDispatcher::DidConnectGamepad(unsigned index,
+void GamepadDispatcher::DidConnectGamepad(uint32_t index,
                                           const device::Gamepad& gamepad) {
   DispatchDidConnectOrDisconnectGamepad(index, gamepad, true);
 }
 
-void GamepadDispatcher::DidDisconnectGamepad(unsigned index,
+void GamepadDispatcher::DidDisconnectGamepad(uint32_t index,
                                              const device::Gamepad& gamepad) {
   DispatchDidConnectOrDisconnectGamepad(index, gamepad, false);
 }
 
+void GamepadDispatcher::ButtonOrAxisDidChange(uint32_t index,
+                                              const device::Gamepad& gamepad) {
+  DCHECK_LT(index, device::Gamepads::kItemsLengthCap);
+  NotifyControllers();
+}
+
 void GamepadDispatcher::DispatchDidConnectOrDisconnectGamepad(
-    unsigned index,
+    uint32_t index,
     const device::Gamepad& gamepad,
     bool connected) {
-  DCHECK(index < device::Gamepads::kItemsLengthCap);
+  DCHECK_LT(index, device::Gamepads::kItemsLengthCap);
   DCHECK_EQ(connected, gamepad.connected);
 
   NotifyControllers();
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
index 381b073..b809d7b 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
@@ -27,12 +27,12 @@
 
   void SampleGamepads(device::Gamepads&);
 
-  void PlayVibrationEffectOnce(int pad_index,
+  void PlayVibrationEffectOnce(uint32_t pad_index,
                                device::mojom::blink::GamepadHapticEffectType,
                                device::mojom::blink::GamepadEffectParametersPtr,
                                device::mojom::blink::GamepadHapticsManager::
                                    PlayVibrationEffectOnceCallback);
-  void ResetVibrationActuator(int pad_index,
+  void ResetVibrationActuator(uint32_t pad_index,
                               device::mojom::blink::GamepadHapticsManager::
                                   ResetVibrationActuatorCallback);
 
@@ -44,14 +44,15 @@
   void InitializeHaptics();
 
   // WebGamepadListener
-  void DidConnectGamepad(unsigned index, const device::Gamepad&) override;
-  void DidDisconnectGamepad(unsigned index, const device::Gamepad&) override;
+  void DidConnectGamepad(uint32_t index, const device::Gamepad&) override;
+  void DidDisconnectGamepad(uint32_t index, const device::Gamepad&) override;
+  void ButtonOrAxisDidChange(uint32_t index, const device::Gamepad&) override;
 
   // PlatformEventDispatcher
   void StartListening(LocalFrame* frame) override;
   void StopListening() override;
 
-  void DispatchDidConnectOrDisconnectGamepad(unsigned index,
+  void DispatchDidConnectOrDisconnectGamepad(uint32_t index,
                                              const device::Gamepad&,
                                              bool connected);
 
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc
index 5b8aac1..54491f6 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc
@@ -110,7 +110,7 @@
     // gamepads to prevent fingerprinting. The actual data is not cleared.
     // WebKit will only copy out data into the JS buffers for connected
     // gamepads so this is sufficient.
-    for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; i++)
+    for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; i++)
       gamepads.items[i].connected = false;
   }
 }
@@ -121,7 +121,7 @@
 }
 
 void GamepadSharedMemoryReader::GamepadConnected(
-    int index,
+    uint32_t index,
     const device::Gamepad& gamepad) {
   // The browser already checks if the user actually interacted with a device.
   ever_interacted_with_ = true;
@@ -131,10 +131,17 @@
 }
 
 void GamepadSharedMemoryReader::GamepadDisconnected(
-    int index,
+    uint32_t index,
     const device::Gamepad& gamepad) {
   if (listener_)
     listener_->DidDisconnectGamepad(index, gamepad);
 }
 
+void GamepadSharedMemoryReader::GamepadButtonOrAxisChanged(
+    uint32_t index,
+    const device::Gamepad& gamepad) {
+  if (listener_)
+    listener_->ButtonOrAxisDidChange(index, gamepad);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h
index f1342cc..f102292 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h
@@ -37,8 +37,12 @@
 
  private:
   // device::mojom::blink::GamepadObserver methods.
-  void GamepadConnected(int index, const device::Gamepad& gamepad) override;
-  void GamepadDisconnected(int index, const device::Gamepad& gamepad) override;
+  void GamepadConnected(uint32_t index,
+                        const device::Gamepad& gamepad) override;
+  void GamepadDisconnected(uint32_t index,
+                           const device::Gamepad& gamepad) override;
+  void GamepadButtonOrAxisChanged(uint32_t index,
+                                  const device::Gamepad& gamepad) override;
 
   base::ReadOnlySharedMemoryRegion renderer_shared_buffer_region_;
   base::ReadOnlySharedMemoryMapping renderer_shared_buffer_mapping_;
diff --git a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
index a43eaf46..4dc1204 100644
--- a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -88,7 +88,7 @@
 }  // namespace
 
 template <typename T>
-static void SampleGamepad(unsigned index,
+static void SampleGamepad(size_t index,
                           T& gamepad,
                           const device::Gamepad& device_gamepad,
                           const TimeTicks& navigation_start) {
@@ -138,7 +138,7 @@
 
   GamepadDispatcher::Instance().SampleGamepads(gamepads);
 
-  for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
+  for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
     device::Gamepad& web_gamepad = gamepads.items[i];
 
     bool hide_xr_gamepad = false;
@@ -384,7 +384,7 @@
 bool NavigatorGamepad::CheckConnectedGamepads(GamepadList* old_gamepads,
                                               GamepadList* new_gamepads) {
   int disconnection_count = 0;
-  for (unsigned i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
+  for (size_t i = 0; i < device::Gamepads::kItemsLengthCap; ++i) {
     Gamepad* old_gamepad = old_gamepads ? old_gamepads->item(i) : nullptr;
     Gamepad* new_gamepad = new_gamepads->item(i);
     bool connected, disconnected;
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc
index 35b8ad0d..80f84e5 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -151,10 +151,6 @@
     UseCounter::Count(document, WebFeature::kGeolocationSecureOrigin);
     UseCounter::CountCrossOriginIframe(
         *document, WebFeature::kGeolocationSecureOriginIframe);
-    if (!RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-      Deprecation::CountDeprecationFeaturePolicy(
-          *document, mojom::FeaturePolicyFeature::kGeolocation);
-    }
   } else if (GetFrame()
                  ->GetSettings()
                  ->GetAllowGeolocationOnInsecureOrigins()) {
@@ -169,10 +165,6 @@
         WebFeature::kGeolocationInsecureOriginIframeDeprecatedNotRemoved);
     HostsUsingFeatures::CountAnyWorld(
         *document, HostsUsingFeatures::Feature::kGeolocationInsecureHost);
-    if (!RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-      Deprecation::CountDeprecationFeaturePolicy(
-          *document, mojom::FeaturePolicyFeature::kGeolocation);
-    }
   } else {
     Deprecation::CountDeprecation(document,
                                   WebFeature::kGeolocationInsecureOrigin);
@@ -232,18 +224,15 @@
     return;
   }
 
-  if (RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-    if (!GetFrame()->IsFeatureEnabled(
-            mojom::FeaturePolicyFeature::kGeolocation)) {
-      UseCounter::Count(GetDocument(),
-                        WebFeature::kGeolocationDisabledByFeaturePolicy);
-      GetDocument()->AddConsoleMessage(
-          ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel,
-                                 kFeaturePolicyConsoleWarning));
-      notifier->SetFatalError(PositionError::Create(
-          PositionError::kPermissionDenied, kFeaturePolicyErrorMessage));
-      return;
-    }
+  if (!GetFrame()->IsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kGeolocation)) {
+    UseCounter::Count(GetDocument(),
+                      WebFeature::kGeolocationDisabledByFeaturePolicy);
+    GetDocument()->AddConsoleMessage(ConsoleMessage::Create(
+        kJSMessageSource, kErrorMessageLevel, kFeaturePolicyConsoleWarning));
+    notifier->SetFatalError(PositionError::Create(
+        PositionError::kPermissionDenied, kFeaturePolicyErrorMessage));
+    return;
   }
 
   ReportGeolocationViolation(GetDocument());
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_database.cc b/third_party/blink/renderer/modules/indexeddb/idb_database.cc
index 6b8fc330..d3921b0 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_database.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_database.cc
@@ -497,7 +497,7 @@
 void IDBDatabase::EnqueueEvent(Event* event) {
   DCHECK(GetExecutionContext());
   event->SetTarget(this);
-  event_queue_->EnqueueEvent(FROM_HERE, event);
+  event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 DispatchEventResult IDBDatabase::DispatchEventInternal(Event& event) {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request.cc b/third_party/blink/renderer/modules/indexeddb/idb_request.cc
index 50acf9ca..1015ee1f 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_request.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_request.cc
@@ -762,7 +762,7 @@
 
   event->SetTarget(this);
 
-  event_queue_->EnqueueEvent(FROM_HERE, event);
+  event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
index 969a80d..588891f3 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_transaction.cc
@@ -558,7 +558,7 @@
     return;
 
   event->SetTarget(this);
-  event_queue_->EnqueueEvent(FROM_HERE, event);
+  event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 void IDBTransaction::AbortOutstandingRequests() {
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.cc
index 7c21b9a..c58efc14 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.cc
@@ -15,7 +15,7 @@
   SetShadowPseudoId(AtomicString("-internal-media-controls-button-panel"));
 }
 
-bool MediaControlButtonPanelElement::KeepEventInNode(Event* event) {
+bool MediaControlButtonPanelElement::KeepEventInNode(const Event& event) const {
   return MediaControlElementsHelper::IsUserInteractionEvent(event);
 }
 
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h
index d8bb310..5807f54 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h
@@ -20,7 +20,7 @@
   explicit MediaControlButtonPanelElement(MediaControlsImpl&);
 
  private:
-  bool KeepEventInNode(Event*) override;
+  bool KeepEventInNode(const Event&) const override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
index 6fd6c47..67ea8c32 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.cc
@@ -114,7 +114,7 @@
   MediaControlInputElement::DefaultEventHandler(event);
 }
 
-bool MediaControlCastButtonElement::KeepEventInNode(Event* event) {
+bool MediaControlCastButtonElement::KeepEventInNode(const Event& event) const {
   return MediaControlElementsHelper::IsUserInteractionEvent(event);
 }
 
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h
index 4e9375ef..d692354 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h
@@ -34,7 +34,7 @@
 
  private:
   void DefaultEventHandler(Event*) final;
-  bool KeepEventInNode(Event*) final;
+  bool KeepEventInNode(const Event&) const final;
 
   bool IsPlayingRemotely() const;
 
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc
index 699db2a..088518d 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.cc
@@ -17,18 +17,18 @@
 namespace blink {
 
 // static
-bool MediaControlElementsHelper::IsUserInteractionEvent(Event* event) {
-  const AtomicString& type = event->type();
+bool MediaControlElementsHelper::IsUserInteractionEvent(const Event& event) {
+  const AtomicString& type = event.type();
   return type == EventTypeNames::pointerdown ||
          type == EventTypeNames::pointerup ||
          type == EventTypeNames::mousedown || type == EventTypeNames::mouseup ||
          type == EventTypeNames::click || type == EventTypeNames::dblclick ||
-         event->IsKeyboardEvent() || event->IsTouchEvent();
+         event.IsKeyboardEvent() || event.IsTouchEvent();
 }
 
 // static
 bool MediaControlElementsHelper::IsUserInteractionEventForSlider(
-    Event* event,
+    const Event& event,
     LayoutObject* layout_object) {
   // It is unclear if this can be converted to isUserInteractionEvent(), since
   // mouse* events seem to be eaten during a drag anyway, see
@@ -45,7 +45,7 @@
   if (slider && !slider->InDragMode())
     return false;
 
-  const AtomicString& type = event->type();
+  const AtomicString& type = event.type();
   return type == EventTypeNames::mouseover ||
          type == EventTypeNames::mouseout ||
          type == EventTypeNames::mousemove ||
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h
index e3d04ee..adc67d95 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_elements_helper.h
@@ -30,11 +30,11 @@
   STATIC_ONLY(MediaControlElementsHelper);
 
  public:
-  static bool IsUserInteractionEvent(Event*);
+  static bool IsUserInteractionEvent(const Event&);
 
   // Sliders (the volume control and timeline) need to capture some additional
   // events used when dragging the thumb.
-  static bool IsUserInteractionEventForSlider(Event*, LayoutObject*);
+  static bool IsUserInteractionEventForSlider(const Event&, LayoutObject*);
 
   // Returns the MediaControlElementType associated with a given |Node|. The
   // |node| _must_ be a media control element.
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
index f65966e..bffcec96 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.cc
@@ -217,7 +217,7 @@
 }
 
 void MediaControlOverlayPlayButtonElement::DefaultEventHandler(Event* event) {
-  if (ShouldCausePlayPause(event)) {
+  if (ShouldCausePlayPause(*event)) {
     event->SetDefaultHandled();
     MaybePlayPause();
   } else if (event->type() == EventTypeNames::click) {
@@ -267,26 +267,27 @@
   MediaControlInputElement::DefaultEventHandler(event);
 }
 
-bool MediaControlOverlayPlayButtonElement::KeepEventInNode(Event* event) {
+bool MediaControlOverlayPlayButtonElement::KeepEventInNode(
+    const Event& event) const {
   // We only care about user interaction events.
   if (!MediaControlElementsHelper::IsUserInteractionEvent(event))
     return false;
 
   // For mouse events, only keep in node if they're on the internal button.
-  if (event->IsMouseEvent() && MediaControlsImpl::IsModern())
+  if (event.IsMouseEvent() && MediaControlsImpl::IsModern())
     return IsMouseEventOnInternalButton(ToMouseEvent(event));
 
   return true;
 }
 
 bool MediaControlOverlayPlayButtonElement::ShouldCausePlayPause(
-    Event* event) const {
+    const Event& event) const {
   // Only click events cause a play/pause.
-  if (event->type() != EventTypeNames::click)
+  if (event.type() != EventTypeNames::click)
     return false;
 
   // Double tap to navigate should only be available on modern controls.
-  if (!MediaControlsImpl::IsModern() || !event->IsMouseEvent())
+  if (!MediaControlsImpl::IsModern() || !event.IsMouseEvent())
     return true;
 
   // TODO(beccahughes): Move to PointerEvent.
@@ -294,9 +295,9 @@
 }
 
 bool MediaControlOverlayPlayButtonElement::IsMouseEventOnInternalButton(
-    MouseEvent* mouse_event) const {
+    const MouseEvent& mouse_event) const {
   // If no position data available, default to yes.
-  if (!mouse_event->HasPosition())
+  if (!mouse_event.HasPosition())
     return true;
 
   // Find the zoom-adjusted internal button bounding box.
@@ -310,7 +311,7 @@
 
   // Check the button and a margin around it.
   return IsPointInRect(*box, kInnerButtonTouchPaddingSize,
-                       mouse_event->clientX(), mouse_event->clientY());
+                       mouse_event.clientX(), mouse_event.clientY());
 }
 
 WebSize MediaControlOverlayPlayButtonElement::GetSizeOrDefault() const {
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h
index 144654c..377ed4f 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_overlay_play_button_element.h
@@ -80,10 +80,10 @@
   void TapTimerFired(TimerBase*);
 
   void DefaultEventHandler(Event*) override;
-  bool KeepEventInNode(Event*) override;
+  bool KeepEventInNode(const Event&) const override;
 
-  bool ShouldCausePlayPause(Event*) const;
-  bool IsMouseEventOnInternalButton(MouseEvent*) const;
+  bool ShouldCausePlayPause(const Event&) const;
+  bool IsMouseEventOnInternalButton(const MouseEvent&) const;
   void MaybePlayPause();
   void MaybeJump(int);
 
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc
index 6445c87..0240bca 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.cc
@@ -175,7 +175,7 @@
   HTMLDivElement::DefaultEventHandler(event);
 }
 
-bool MediaControlPanelElement::KeepEventInNode(Event* event) {
+bool MediaControlPanelElement::KeepEventInNode(const Event& event) const {
   return !MediaControlsImpl::IsModern() &&
          MediaControlElementsHelper::IsUserInteractionEvent(event);
 }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h
index aed4691..cfa0e58 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_panel_element.h
@@ -45,7 +45,7 @@
   void DetachTransitionEventListener();
 
   void DefaultEventHandler(Event*) override;
-  bool KeepEventInNode(Event*) override;
+  bool KeepEventInNode(const Event&) const override;
 
   void DidBecomeVisible();
   void HandleTransitionEndEvent();
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
index 62ef007e..de4110fd 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.cc
@@ -172,7 +172,7 @@
   GetMediaControls().UpdateCurrentTimeDisplay();
 }
 
-bool MediaControlTimelineElement::KeepEventInNode(Event* event) {
+bool MediaControlTimelineElement::KeepEventInNode(const Event& event) const {
   return MediaControlElementsHelper::IsUserInteractionEventForSlider(
       event, GetLayoutObject());
 }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h
index bed9237..4c8d58dc 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_timeline_element.h
@@ -44,7 +44,7 @@
 
  private:
   void DefaultEventHandler(Event*) override;
-  bool KeepEventInNode(Event*) override;
+  bool KeepEventInNode(const Event&) const override;
 
   // Checks if we can begin or end a scrubbing event. If the event is a pointer
   // event then it needs to start and end with valid pointer events. If the
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
index 8c4b29a..33024aa 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.cc
@@ -82,7 +82,8 @@
   SetAfterSegmentPosition(MediaControlSliderElement::Position(0, volume));
 }
 
-bool MediaControlVolumeSliderElement::KeepEventInNode(Event* event) {
+bool MediaControlVolumeSliderElement::KeepEventInNode(
+    const Event& event) const {
   return MediaControlElementsHelper::IsUserInteractionEventForSlider(
       event, GetLayoutObject());
 }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h
index afaa5ff3..4a950ccaf 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_volume_slider_element.h
@@ -30,7 +30,7 @@
 
  private:
   void DefaultEventHandler(Event*) override;
-  bool KeepEventInNode(Event*) override;
+  bool KeepEventInNode(const Event&) const override;
   void SetVolumeInternal(double);
 };
 
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc
index 4852e55..1fba87a 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -851,7 +851,7 @@
   Event* event = Event::Create(event_name);
   event->SetTarget(this);
 
-  async_event_queue_->EnqueueEvent(FROM_HERE, event);
+  async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 URLRegistry& MediaSource::Registry() const {
diff --git a/third_party/blink/renderer/modules/mediasource/source_buffer.cc b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
index 6aaa0b9..8007d2c 100644
--- a/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -1188,7 +1188,7 @@
   Event* event = Event::Create(event_name);
   event->SetTarget(this);
 
-  async_event_queue_->EnqueueEvent(FROM_HERE, event);
+  async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 bool SourceBuffer::PrepareAppend(double media_time,
diff --git a/third_party/blink/renderer/modules/mediasource/source_buffer_list.cc b/third_party/blink/renderer/modules/mediasource/source_buffer_list.cc
index 7c86cfe..44ceda9 100644
--- a/third_party/blink/renderer/modules/mediasource/source_buffer_list.cc
+++ b/third_party/blink/renderer/modules/mediasource/source_buffer_list.cc
@@ -71,7 +71,7 @@
   Event* event = Event::Create(event_name);
   event->SetTarget(this);
 
-  async_event_queue_->EnqueueEvent(FROM_HERE, event);
+  async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
 const AtomicString& SourceBufferList::InterfaceName() const {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index d145864..48d1491 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -480,27 +480,17 @@
 
     // Feature policy deprecation messages.
     if (Audio()) {
-      if (RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-        if (!document->GetFrame()->IsFeatureEnabled(
-                mojom::FeaturePolicyFeature::kMicrophone)) {
-          UseCounter::Count(
-              document, WebFeature::kMicrophoneDisabledByFeaturePolicyEstimate);
-        }
-      } else {
-        Deprecation::CountDeprecationFeaturePolicy(
-            *document, mojom::FeaturePolicyFeature::kMicrophone);
+      if (!document->GetFrame()->IsFeatureEnabled(
+              mojom::FeaturePolicyFeature::kMicrophone)) {
+        UseCounter::Count(
+            document, WebFeature::kMicrophoneDisabledByFeaturePolicyEstimate);
       }
     }
     if (Video()) {
-      if (RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-        if (!document->GetFrame()->IsFeatureEnabled(
-                mojom::FeaturePolicyFeature::kCamera)) {
-          UseCounter::Count(document,
-                            WebFeature::kCameraDisabledByFeaturePolicyEstimate);
-        }
-      } else {
-        Deprecation::CountDeprecationFeaturePolicy(
-            *document, mojom::FeaturePolicyFeature::kCamera);
+      if (!document->GetFrame()->IsFeatureEnabled(
+              mojom::FeaturePolicyFeature::kCamera)) {
+        UseCounter::Count(document,
+                          WebFeature::kCameraDisabledByFeaturePolicyEstimate);
       }
     }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_details_modifier.idl b/third_party/blink/renderer/modules/payments/payment_details_modifier.idl
index 9eb9208..b59f2e2a 100644
--- a/third_party/blink/renderer/modules/payments/payment_details_modifier.idl
+++ b/third_party/blink/renderer/modules/payments/payment_details_modifier.idl
@@ -8,5 +8,5 @@
     [ImplementedAs=supportedMethod] required DOMString supportedMethods;
     PaymentItem total;
     sequence<PaymentItem> additionalDisplayItems;
-    [RuntimeEnabled=PaymentDetailsModifierData] object data;
+    object data;
 };
diff --git a/third_party/blink/renderer/modules/storage/storage_area.cc b/third_party/blink/renderer/modules/storage/storage_area.cc
index 36f73d3..15d3103 100644
--- a/third_party/blink/renderer/modules/storage/storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/storage_area.cc
@@ -224,8 +224,8 @@
           !IsEventSource(storage, source_area_instance)) {
         // https://www.w3.org/TR/webstorage/#the-storage-event
         local_frame->DomWindow()->EnqueueWindowEvent(
-            StorageEvent::Create(EventTypeNames::storage, key, old_value,
-                                 new_value, page_url, storage),
+            *StorageEvent::Create(EventTypeNames::storage, key, old_value,
+                                  new_value, page_url, storage),
             TaskType::kDOMManipulation);
       }
     }
@@ -265,8 +265,8 @@
         !IsEventSource(storage, source_area_instance)) {
       // https://www.w3.org/TR/webstorage/#the-storage-event
       local_frame->DomWindow()->EnqueueWindowEvent(
-          StorageEvent::Create(EventTypeNames::storage, key, old_value,
-                               new_value, page_url, storage),
+          *StorageEvent::Create(EventTypeNames::storage, key, old_value,
+                                new_value, page_url, storage),
           TaskType::kDOMManipulation);
     }
   }
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.cc b/third_party/blink/renderer/modules/vr/navigator_vr.cc
index 3a5c107..ad15980 100644
--- a/third_party/blink/renderer/modules/vr/navigator_vr.cc
+++ b/third_party/blink/renderer/modules/vr/navigator_vr.cc
@@ -229,7 +229,7 @@
     return;
 
   GetSupplementable()->GetFrame()->DomWindow()->EnqueueWindowEvent(
-      event, TaskType::kMiscPlatformAPI);
+      *event, TaskType::kMiscPlatformAPI);
 }
 
 void NavigatorVR::DispatchVREvent(VRDisplayEvent* event) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet.h b/third_party/blink/renderer/modules/webaudio/audio_worklet.h
index dd82c71..ab36e530 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet.h
@@ -24,8 +24,6 @@
   WTF_MAKE_NONCOPYABLE(AudioWorklet);
 
  public:
-  // When the AudioWorklet runtime flag is not enabled, this constructor returns
-  // |nullptr|.
   static AudioWorklet* Create(BaseAudioContext*);
 
   ~AudioWorklet() override = default;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index ff46ff2..91625c5 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -797,7 +797,7 @@
           size, CanvasResourceProvider::kAcceleratedResourceUsage,
           SharedGpuContext::ContextProviderWrapper(), 0, ColorParams(),
           CanvasResourceProvider::kDefaultPresentationMode,
-          nullptr);  // canvas_resource_dispatcher
+          nullptr /* canvas_resource_dispatcher */, is_origin_top_left_);
   if (!resource_provider || !resource_provider->IsValid())
     return nullptr;
   if (!CopyRenderingResultsFromDrawingBuffer(resource_provider.get(),
@@ -5467,10 +5467,9 @@
             IntSize(video->videoWidth(), video->videoHeight()),
             CanvasResourceProvider::kAcceleratedResourceUsage,
             SharedGpuContext::ContextProviderWrapper(),
-            0,  // msaa_sample_count
-            CanvasColorParams(),
+            0 /* msaa_sample_count */, CanvasColorParams(),
             CanvasResourceProvider::kDefaultPresentationMode,
-            nullptr);  // canvas_resource_dispatcher
+            nullptr /* canvas_resource_dispatcher */, is_origin_top_left_);
     if (resource_provider && resource_provider->IsValid()) {
       // The video element paints an RGBA frame into our surface here. By
       // using an AcceleratedImageBufferSurface, we enable the WebMediaPlayer
diff --git a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
index 4185a353..67cc7636 100644
--- a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
+++ b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -102,20 +102,14 @@
   UseCounter::CountCrossOriginIframe(
       document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting);
 
-  if (RuntimeEnabledFeatures::FeaturePolicyForPermissionsEnabled()) {
-    if (!document.GetFrame()->IsFeatureEnabled(
-            mojom::FeaturePolicyFeature::kMidiFeature)) {
-      UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy);
-      document.AddConsoleMessage(
-          ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel,
-                                 kFeaturePolicyConsoleWarning));
-      return ScriptPromise::RejectWithDOMException(
-          script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
-                                             kFeaturePolicyErrorMessage));
-    }
-  } else {
-    Deprecation::CountDeprecationFeaturePolicy(
-        document, mojom::FeaturePolicyFeature::kMidiFeature);
+  if (!document.GetFrame()->IsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kMidiFeature)) {
+    UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy);
+    document.AddConsoleMessage(ConsoleMessage::Create(
+        kJSMessageSource, kWarningMessageLevel, kFeaturePolicyConsoleWarning));
+    return ScriptPromise::RejectWithDOMException(
+        script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
+                                           kFeaturePolicyErrorMessage));
   }
 
   return MIDIAccessInitializer::Start(script_state, options);
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 c7755b7..393ad3b3 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.cc
@@ -130,18 +130,19 @@
 
 void WebSocketChannelImpl::BlobLoader::Cancel() {
   loader_->Cancel();
-  loader_ = nullptr;
+  // DidFail will be called immediately.
+  // |this| is deleted here.
 }
 
 void WebSocketChannelImpl::BlobLoader::DidFinishLoading() {
   channel_->DidFinishLoadingBlob(loader_->ArrayBufferResult());
-  loader_ = nullptr;
+  // |this| is deleted here.
 }
 
 void WebSocketChannelImpl::BlobLoader::DidFail(
     FileError::ErrorCode error_code) {
   channel_->DidFailLoadingBlob(error_code);
-  loader_ = nullptr;
+  // |this| is deleted here.
 }
 
 struct WebSocketChannelImpl::ConnectInfo {
@@ -544,6 +545,7 @@
       was_clean ? WebSocketChannelClient::kClosingHandshakeComplete
                 : WebSocketChannelClient::kClosingHandshakeIncomplete;
   client->DidClose(status, code, reason);
+  // client->DidClose may delete this object.
 }
 
 void WebSocketChannelImpl::DidConnect(WebSocketHandle* handle,
@@ -619,6 +621,7 @@
   // WebSocketConnection. Hence we fail this channel by calling
   // |this->failAsError| function.
   FailAsError(message);
+  // |this| may be deleted.
 }
 
 void WebSocketChannelImpl::DidReceiveData(WebSocketHandle* handle,
@@ -672,6 +675,7 @@
     receiving_message_data_.clear();
     if (message.IsNull()) {
       FailAsError("Could not decode a text frame as UTF-8.");
+      // failAsError may delete this object.
     } else {
       client_->DidReceiveTextMessage(message);
     }
@@ -706,6 +710,7 @@
   }
 
   HandleDidClose(was_clean, code, reason);
+  // HandleDidClose may delete this object.
 }
 
 void WebSocketChannelImpl::DidReceiveFlowControl(WebSocketHandle* handle,
@@ -774,6 +779,7 @@
   // FIXME: Generate human-friendly reason message.
   FailAsError("Failed to load Blob: error code = " +
               String::Number(error_code));
+  // |this| can be deleted here.
 }
 
 void WebSocketChannelImpl::TearDownFailedConnection() {
@@ -785,6 +791,7 @@
     client_->DidError();
 
   HandleDidClose(false, kCloseEventCodeAbnormalClosure, String());
+  // HandleDidClose may delete this object.
 }
 
 bool WebSocketChannelImpl::ShouldDisallowConnection(const KURL& url) {
diff --git a/third_party/blink/renderer/modules/xr/xr.idl b/third_party/blink/renderer/modules/xr/xr.idl
index 49fdec21..de578ac 100644
--- a/third_party/blink/renderer/modules/xr/xr.idl
+++ b/third_party/blink/renderer/modules/xr/xr.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xr-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XR : EventTarget {
   attribute EventHandler ondevicechange;
diff --git a/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl b/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
index 3bb482b..42e5a9b 100644
--- a/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
+++ b/third_party/blink/renderer/modules/xr/xr_coordinate_system.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrcoordinatesystem-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRCoordinateSystem {
   Float32Array? getTransformTo(XRCoordinateSystem other);
diff --git a/third_party/blink/renderer/modules/xr/xr_device.idl b/third_party/blink/renderer/modules/xr/xr_device.idl
index f8da225..5d5a879 100644
--- a/third_party/blink/renderer/modules/xr/xr_device.idl
+++ b/third_party/blink/renderer/modules/xr/xr_device.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrdevice-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRDevice {
   [CallWith=ScriptState, MeasureAs=XRSupportsSession] Promise<void> supportsSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
diff --git a/third_party/blink/renderer/modules/xr/xr_device_pose.idl b/third_party/blink/renderer/modules/xr/xr_device_pose.idl
index 8b7053c..f71be26d 100644
--- a/third_party/blink/renderer/modules/xr/xr_device_pose.idl
+++ b/third_party/blink/renderer/modules/xr/xr_device_pose.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrdevicepose-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRDevicePose {
   readonly attribute Float32Array poseModelMatrix;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame.idl b/third_party/blink/renderer/modules/xr/xr_frame.idl
index bfa5a79..5b3a9df 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame.idl
+++ b/third_party/blink/renderer/modules/xr/xr_frame.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrframe
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRFrame {
   readonly attribute XRSession session;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl b/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
index e5e797d..b1b3856 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
+++ b/third_party/blink/renderer/modules/xr/xr_frame_of_reference.idl
@@ -12,6 +12,7 @@
 
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRFrameOfReference : XRCoordinateSystem {
   readonly attribute XRStageBounds? bounds;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
index 3ec12a2..2e59b0b 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
+++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -399,12 +399,12 @@
     // In the process of fulfilling the frame requests for each session they are
     // extremely likely to request another frame. Work off of a separate list
     // from the requests to prevent infinite loops.
-    HeapVector<Member<XRSession>> processing_sessions;
-    swap(requesting_sessions_, processing_sessions);
+    DCHECK(processing_sessions_.IsEmpty());
+    swap(requesting_sessions_, processing_sessions_);
 
     // Inform sessions with a pending request of the new frame
-    for (unsigned i = 0; i < processing_sessions.size(); ++i) {
-      XRSession* session = processing_sessions.at(i).Get();
+    for (unsigned i = 0; i < processing_sessions_.size(); ++i) {
+      XRSession* session = processing_sessions_.at(i).Get();
 
       if (frame_pose_ && frame_pose_->input_state.has_value()) {
         session->OnInputStateChange(frame_id_,
@@ -432,6 +432,8 @@
                          base::nullopt, base::nullopt);
       }
     }
+
+    processing_sessions_.clear();
   }
 }
 
@@ -544,6 +546,7 @@
   visitor->Trace(frame_transport_);
   visitor->Trace(immersive_session_);
   visitor->Trace(requesting_sessions_);
+  visitor->Trace(processing_sessions_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
index c483e03..945283d 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_provider.h
+++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -64,6 +64,7 @@
 
   // Non-immersive Sessions which have requested a frame update.
   HeapVector<Member<XRSession>> requesting_sessions_;
+  HeapVector<Member<XRSession>> processing_sessions_;
 
   device::mojom::blink::XRPresentationProviderPtr presentation_provider_;
   device::mojom::blink::XRFrameDataProviderPtr immersive_data_provider_;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc b/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc
index 0de1f34..8f799cd 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc
+++ b/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.cc
@@ -30,6 +30,7 @@
 void XRFrameRequestCallbackCollection::CancelCallback(CallbackId id) {
   if (IsValidCallbackId(id)) {
     callbacks_.erase(id);
+    current_callbacks_.erase(id);
   }
 }
 
@@ -38,26 +39,36 @@
                                                         XRFrame* frame) {
   // First, generate a list of callbacks to consider.  Callbacks registered from
   // this point on are considered only for the "next" frame, not this one.
-  DCHECK(callbacks_to_invoke_.IsEmpty());
-  callbacks_to_invoke_.swap(pending_callbacks_);
 
-  for (const auto& id : callbacks_to_invoke_) {
-    V8XRFrameRequestCallback* callback = callbacks_.Take(id);
+  // Conceptually we are just going to iterate through current_callbacks_, and
+  // call each callback.  However, if we had multiple callbacks, subsequent ones
+  // could be removed while we are iterating.  HeapHashMap iterators aren't
+  // valid after collection modifications, so we also store a corresponding set
+  // of ids for iteration purposes.  current_callback_ids is the set of ids for
+  // callbacks we will call, and is kept in sync with current_callbacks_ but
+  // safe to iterate over.
+  DCHECK(current_callbacks_.IsEmpty());
+  current_callbacks_.swap(callbacks_);
 
-    // Callback won't be found if it was cancelled.
-    if (!callback)
+  Vector<CallbackId> current_callback_ids;
+  current_callback_ids.swap(pending_callbacks_);
+
+  for (const auto& id : current_callback_ids) {
+    auto it = current_callbacks_.find(id);
+    if (it == current_callbacks_.end())
       continue;
 
-    probe::AsyncTask async_task(context_, callback);
+    probe::AsyncTask async_task(context_, it->value);
     probe::UserCallback probe(context_, "XRRequestFrame", AtomicString(), true);
-    callback->InvokeAndReportException(session, timestamp, frame);
+    it->value->InvokeAndReportException(session, timestamp, frame);
   }
 
-  callbacks_to_invoke_.clear();
+  current_callbacks_.clear();
 }
 
 void XRFrameRequestCallbackCollection::Trace(blink::Visitor* visitor) {
   visitor->Trace(callbacks_);
+  visitor->Trace(current_callbacks_);
   visitor->Trace(context_);
 }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h b/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
index 28b79e9..28ff06d 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
+++ b/third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h
@@ -45,8 +45,9 @@
       HeapHashMap<CallbackId, TraceWrapperMember<V8XRFrameRequestCallback>>;
   CallbackMap callbacks_;
   Vector<CallbackId> pending_callbacks_;
+
   // Only non-empty while inside executeCallbacks.
-  Vector<CallbackId> callbacks_to_invoke_;
+  CallbackMap current_callbacks_;
 
   CallbackId next_callback_id_ = 0;
 
diff --git a/third_party/blink/renderer/modules/xr/xr_input_pose.idl b/third_party/blink/renderer/modules/xr/xr_input_pose.idl
index 377ee58a..0359c6a 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_pose.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_pose.idl
@@ -4,9 +4,10 @@
 
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRInputPose {
   readonly attribute XRRay targetRay;
   readonly attribute Float32Array? gripMatrix;
   readonly attribute boolean emulatedPosition;
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.idl b/third_party/blink/renderer/modules/xr/xr_input_source.idl
index f290e72..bd3a7bf 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -15,8 +15,9 @@
 
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRInputSource {
   readonly attribute XRHandedness handedness;
   readonly attribute XRTargetRayMode targetRayMode;
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source_event.idl b/third_party/blink/renderer/modules/xr/xr_input_source_event.idl
index 0c8fe9f3..1eb733b 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source_event.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_source_event.idl
@@ -4,6 +4,7 @@
 
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR,
     Constructor(DOMString type, XRInputSourceEventInit eventInitDict)
 ] interface XRInputSourceEvent : Event {
diff --git a/third_party/blink/renderer/modules/xr/xr_layer.idl b/third_party/blink/renderer/modules/xr/xr_layer.idl
index 3b30353..26ceefed 100644
--- a/third_party/blink/renderer/modules/xr/xr_layer.idl
+++ b/third_party/blink/renderer/modules/xr/xr_layer.idl
@@ -5,5 +5,6 @@
 // https://immersive-web.github.io/webxr/#xrlayer-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRLayer {};
diff --git a/third_party/blink/renderer/modules/xr/xr_presentation_context.idl b/third_party/blink/renderer/modules/xr/xr_presentation_context.idl
index 4f457b4..2ecd316 100644
--- a/third_party/blink/renderer/modules/xr/xr_presentation_context.idl
+++ b/third_party/blink/renderer/modules/xr/xr_presentation_context.idl
@@ -5,8 +5,9 @@
 // https://immersive-web.github.io/webxr/#xrpresentationcontext-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRPresentationContext {
     // back-reference to the canvas
     readonly attribute HTMLCanvasElement canvas;
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/renderer/modules/xr/xr_ray.idl b/third_party/blink/renderer/modules/xr/xr_ray.idl
index b9ca32e3..4054519 100644
--- a/third_party/blink/renderer/modules/xr/xr_ray.idl
+++ b/third_party/blink/renderer/modules/xr/xr_ray.idl
@@ -3,8 +3,12 @@
 // found in the LICENSE file.
 
 // https://immersive-web.github.io/webxr/#xrray-interface
-[SecureContext, OriginTrialEnabled=WebXR] interface XRRay {
+[
+    SecureContext,
+    Exposed=Window,
+    OriginTrialEnabled=WebXR
+] interface XRRay {
   readonly attribute DOMPointReadOnly origin;
   readonly attribute DOMPointReadOnly direction;
   readonly attribute Float32Array transformMatrix;
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index 65b97408..cc13acf 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -782,6 +782,10 @@
   return views_;
 }
 
+bool XRSession::HasPendingActivity() const {
+  return !callback_collection_->IsEmpty() && !ended_;
+}
+
 void XRSession::Trace(blink::Visitor* visitor) {
   visitor->Trace(device_);
   visitor->Trace(output_context_);
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h
index c71429b..09df7b1 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -19,6 +19,8 @@
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
+#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
+
 namespace blink {
 
 class Element;
@@ -34,8 +36,10 @@
 class XRPresentationContext;
 class XRView;
 
-class XRSession final : public EventTargetWithInlineData {
+class XRSession final : public EventTargetWithInlineData,
+                        public ActiveScriptWrappable<XRSession> {
   DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(XRSession);
 
  public:
   enum EnvironmentBlendMode {
@@ -143,6 +147,9 @@
 
   void Trace(blink::Visitor*) override;
 
+  // ScriptWrappable
+  bool HasPendingActivity() const override;
+
  private:
   class XRSessionResizeObserverDelegate;
 
diff --git a/third_party/blink/renderer/modules/xr/xr_session.idl b/third_party/blink/renderer/modules/xr/xr_session.idl
index a34084b75..01b791d5 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -10,7 +10,9 @@
 };
 
 [
+    ActiveScriptWrappable,
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRSession : EventTarget {
   readonly attribute XRDevice device;
diff --git a/third_party/blink/renderer/modules/xr/xr_session_event.idl b/third_party/blink/renderer/modules/xr/xr_session_event.idl
index 1f5c66d..7bf08de 100644
--- a/third_party/blink/renderer/modules/xr/xr_session_event.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session_event.idl
@@ -5,8 +5,9 @@
 // https://immersive-web.github.io/webxr/#xrsessionevent-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR,
     Constructor(DOMString type, XRSessionEventInit eventInitDict)
 ] interface XRSessionEvent : Event {
   readonly attribute XRSession session;
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl b/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl
index 7a83043..60b89208 100644
--- a/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl
+++ b/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrstagebounds-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRStageBounds {
   readonly attribute FrozenArray<XRStageBoundsPoint> geometry;
diff --git a/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl b/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl
index c00acb1..5d3275dd 100644
--- a/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl
+++ b/third_party/blink/renderer/modules/xr/xr_stage_bounds_point.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrstageboundspoint-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRStageBoundsPoint {
   readonly attribute double x;
diff --git a/third_party/blink/renderer/modules/xr/xr_view.idl b/third_party/blink/renderer/modules/xr/xr_view.idl
index a4cb6a12..8a7df8c 100644
--- a/third_party/blink/renderer/modules/xr/xr_view.idl
+++ b/third_party/blink/renderer/modules/xr/xr_view.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrview-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRView {
   readonly attribute VREye? eye;
diff --git a/third_party/blink/renderer/modules/xr/xr_viewport.idl b/third_party/blink/renderer/modules/xr/xr_viewport.idl
index 7888d590..8c51f30 100644
--- a/third_party/blink/renderer/modules/xr/xr_viewport.idl
+++ b/third_party/blink/renderer/modules/xr/xr_viewport.idl
@@ -5,6 +5,7 @@
 // https://immersive-web.github.io/webxr/#xrviewport-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR
 ] interface XRViewport {
   readonly attribute long x;
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl b/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
index 56db1739..f5d7a6f 100644
--- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
+++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
@@ -7,6 +7,7 @@
 // https://immersive-web.github.io/webxr/#xrwebgllayer-interface
 [
     SecureContext,
+    Exposed=Window,
     OriginTrialEnabled=WebXR,
     Constructor(XRSession session, XRWebGLRenderingContext context, optional XRWebGLLayerInit layerInit),
     RaisesException=Constructor
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.h b/third_party/blink/renderer/platform/bindings/callback_function_base.h
index b46b253f..d96e431 100644
--- a/third_party/blink/renderer/platform/bindings/callback_function_base.h
+++ b/third_party/blink/renderer/platform/bindings/callback_function_base.h
@@ -57,6 +57,9 @@
   Member<ScriptState> incumbent_script_state_;
 
   friend class V8PersistentCallbackFunctionBase;
+  friend v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback,
+                                   v8::Local<v8::Object> creation_context,
+                                   v8::Isolate*);
 };
 
 // V8PersistentCallbackFunctionBase retains the underlying v8::Function of a
diff --git a/third_party/blink/renderer/platform/bindings/to_v8.h b/third_party/blink/renderer/platform/bindings/to_v8.h
index a2999de..3746e29 100644
--- a/third_party/blink/renderer/platform/bindings/to_v8.h
+++ b/third_party/blink/renderer/platform/bindings/to_v8.h
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/optional.h"
+#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
 #include "third_party/blink/renderer/platform/bindings/callback_interface_base.h"
 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -37,6 +38,20 @@
   return wrapper;
 }
 
+// Callback function
+
+inline v8::Local<v8::Value> ToV8(CallbackFunctionBase* callback,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  // |creation_context| is intentionally ignored. Callback functions are not
+  // wrappers nor clonable. ToV8 on a callback function must be used only when
+  // it's the same origin-domain in the same world.
+  DCHECK(!callback || (callback->CallbackRelevantScriptState()->GetContext() ==
+                       creation_context->CreationContext()));
+  return callback ? callback->CallbackFunction().As<v8::Value>()
+                  : v8::Null(isolate).As<v8::Value>();
+}
+
 // Callback interface
 
 inline v8::Local<v8::Value> ToV8(CallbackInterfaceBase* callback,
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
index 0b55dda..45c8cc6 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
@@ -27,7 +27,7 @@
   stats_collector->IncreaseCollectedWrapperCount(1);
 }
 
-void WrapperTypeInfo::Trace(Visitor* visitor, void* impl) {
+void WrapperTypeInfo::Trace(Visitor* visitor, void* impl) const {
   switch (wrapper_class_id) {
     case WrapperTypeInfo::kNodeClassId:
     case WrapperTypeInfo::kObjectClassId:
@@ -41,7 +41,7 @@
   }
 }
 
-void WrapperTypeInfo::TraceWithWrappers(Visitor* visitor, void* impl) {
+void WrapperTypeInfo::TraceWithWrappers(Visitor* visitor, void* impl) const {
   switch (wrapper_class_id) {
     case WrapperTypeInfo::kNodeClassId:
     case WrapperTypeInfo::kObjectClassId:
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
index 6df6dfff..1a913f2be 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
@@ -148,8 +148,8 @@
 
   // Garbage collection support for when the type depends the WrapperTypeInfo
   // object.
-  PLATFORM_EXPORT void Trace(Visitor*, void*);
-  PLATFORM_EXPORT void TraceWithWrappers(Visitor*, void*);
+  PLATFORM_EXPORT void Trace(Visitor*, void*) const;
+  PLATFORM_EXPORT void TraceWithWrappers(Visitor*, void*) const;
 
   // This field must be the first member of the struct WrapperTypeInfo.
   // See also static_assert() in .cpp file.
diff --git a/third_party/blink/renderer/platform/exported/web_cors.cc b/third_party/blink/renderer/platform/exported/web_cors.cc
index eab6b54..8e0a3c5f9 100644
--- a/third_party/blink/renderer/platform/exported/web_cors.cc
+++ b/third_party/blink/renderer/platform/exported/web_cors.cc
@@ -129,53 +129,6 @@
 
 }  // namespace
 
-base::Optional<network::CORSErrorStatus> HandleRedirect(
-    WebSecurityOrigin& current_security_origin,
-    WebURLRequest& new_request,
-    const WebURL redirect_response_url,
-    const int redirect_response_status_code,
-    const WebHTTPHeaderMap& redirect_response_header,
-    network::mojom::FetchCredentialsMode credentials_mode,
-    ResourceLoaderOptions& options) {
-  const KURL& last_url = redirect_response_url;
-  const KURL& new_url = new_request.Url();
-
-  WebSecurityOrigin& new_security_origin = current_security_origin;
-
-  // TODO(tyoshino): This should be fixed to check not only the last one but
-  // all redirect responses.
-  if (!current_security_origin.CanRequest(last_url)) {
-    base::Optional<CORSError> redirect_error =
-        CORS::CheckRedirectLocation(new_url);
-    if (redirect_error)
-      return network::CORSErrorStatus(*redirect_error);
-
-    KURL redirect_response_kurl = redirect_response_url;
-    base::Optional<network::CORSErrorStatus> access_error =
-        CORS::CheckAccess(redirect_response_kurl, redirect_response_status_code,
-                          redirect_response_header.GetHTTPHeaderMap(),
-                          credentials_mode, *current_security_origin.Get());
-    if (access_error)
-      return access_error;
-
-    scoped_refptr<const SecurityOrigin> last_origin =
-        SecurityOrigin::Create(last_url);
-    // Set request's origin to a globally unique identifier as specified in
-    // the step 10 in https://fetch.spec.whatwg.org/#http-redirect-fetch.
-    if (!last_origin->CanRequest(new_url)) {
-      options.security_origin = SecurityOrigin::CreateUniqueOpaque();
-      new_security_origin = options.security_origin;
-    }
-  }
-
-  if (!current_security_origin.CanRequest(new_url)) {
-    new_request.SetHTTPHeaderField(WebString(HTTPNames::Origin),
-                                   new_security_origin.ToString());
-    options.cors_flag = true;
-  }
-  return base::nullopt;
-}
-
 WebHTTPHeaderSet ExtractCorsExposedHeaderNamesList(
     network::mojom::FetchCredentialsMode credentials_mode,
     const WebURLResponse& response) {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 74bad6a4..0b204d5 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -876,13 +876,6 @@
   float total_advance = 0.0f;
   bool has_vertical_offsets = !is_horizontal_run;
 
-#if !defined(OS_MACOSX)
-  // Allocate and populate vector for BoundsForGlyphs call in ComputeGlyphBounds
-  // here to avoid having to iterate over all glyphs an extra time.
-  Vector<Glyph> glyphs(
-      std::min(num_glyphs, HarfBuzzRunGlyphData::kMaxCharacterIndex));
-#endif
-
   // HarfBuzz returns result in visual order, no need to flip for RTL.
   for (unsigned i = 0; i < num_glyphs; ++i) {
     uint16_t glyph = glyph_infos[start_glyph + i].codepoint;
@@ -913,67 +906,49 @@
         IsSafeToBreakBefore(glyph_infos + start_glyph, num_glyphs, i));
     total_advance += advance;
     has_vertical_offsets |= (offset.Height() != 0);
-
-#if !defined(OS_MACOSX)
-    // See comment in ShapeResult::ComputeGlyphBounds.
-    glyphs[i] = run->glyph_data_[i].glyph;
-#endif
   }
 
   run->width_ = std::max(0.0f, total_advance);
   has_vertical_offsets_ |= has_vertical_offsets;
-#if defined(OS_MACOSX)
+
   ComputeGlyphBounds<is_horizontal_run>(*run);
-#else
-  ComputeGlyphBounds<is_horizontal_run>(*run, glyphs);
-#endif
 }
 
-// TODO(kojii): MacOS does not benefit from batching the Skia request due to
-// https://bugs.chromium.org/p/skia/issues/detail?id=5328 , and the cost to
-// prepare batching, which is normally much less than the benefit of batching,
-// is not ignorable unfortunately.
-#if defined(OS_MACOSX)
 template <bool is_horizontal_run>
 void ShapeResult::ComputeGlyphBounds(const ShapeResult::RunInfo& run) {
+  // Skia runs much faster if we give a list of glyph ID rather than calling it
+  // on each glyph.
   const SimpleFontData& current_font_data = *run.font_data_;
-
+#if defined(OS_MACOSX)
+  // TODO(kojii): MacOS does not benefit from batching the Skia request due to
+  // https://bugs.chromium.org/p/skia/issues/detail?id=5328 , and the cost to
+  // prepare batching, which is normally much less than the benefit of batching,
+  // is not ignorable unfortunately.
   GlyphBoundsAccumulator bounds(width_);
   for (const HarfBuzzRunGlyphData& glyph_data : run.glyph_data_) {
     bounds.Unite<is_horizontal_run>(
         glyph_data, current_font_data.BoundsForGlyph(glyph_data.glyph));
     bounds.origin += glyph_data.advance;
   }
-
-  if (!is_horizontal_run)
-    bounds.ConvertVerticalRunToLogical(current_font_data.GetFontMetrics());
-  glyph_bounding_box_.Unite(bounds.bounds);
-}
-
-#else   // !OS_MACOSX
-template <bool is_horizontal_run>
-void ShapeResult::ComputeGlyphBounds(const ShapeResult::RunInfo& run,
-                                     const Vector<Glyph>& glyphs) {
-  const SimpleFontData& current_font_data = *run.font_data_;
-
-  // Skia runs much faster if we give a list of glyph ID rather than calling it
-  // on each glyph.
+#else
   unsigned num_glyphs = run.glyph_data_.size();
-  Vector<SkRect> bounds_list(num_glyphs);
+  Vector<Glyph, 256> glyphs(num_glyphs);
+  for (unsigned i = 0; i < num_glyphs; i++)
+    glyphs[i] = run.glyph_data_[i].glyph;
+  Vector<FloatRect, 256> bounds_list(num_glyphs);
   current_font_data.BoundsForGlyphs(glyphs, &bounds_list);
 
   GlyphBoundsAccumulator bounds(width_);
   for (unsigned i = 0; i < num_glyphs; i++) {
     const HarfBuzzRunGlyphData& glyph_data = run.glyph_data_[i];
-    bounds.Unite<is_horizontal_run>(glyph_data, FloatRect(bounds_list[i]));
+    bounds.Unite<is_horizontal_run>(glyph_data, bounds_list[i]);
     bounds.origin += glyph_data.advance;
   }
-
+#endif
   if (!is_horizontal_run)
     bounds.ConvertVerticalRunToLogical(current_font_data.GetFontMetrics());
   glyph_bounding_box_.Unite(bounds.bounds);
 }
-#endif  // !OS_MACOSX
 
 void ShapeResult::InsertRun(std::unique_ptr<ShapeResult::RunInfo> run_to_insert,
                             unsigned start_glyph,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 314bbf51..58dd8c3 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -32,9 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_H_
 
 #include <memory>
-#include "build/build_config.h"
 #include "third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h"
-#include "third_party/blink/renderer/platform/fonts/glyph.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/layout_unit.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -324,15 +322,8 @@
                              unsigned start_glyph,
                              unsigned num_glyphs,
                              hb_buffer_t*);
-
-#if defined(OS_MACOSX)
   template <bool is_horizontal_run>
   void ComputeGlyphBounds(const ShapeResult::RunInfo&);
-#else
-  template <bool is_horizontal_run>
-  void ComputeGlyphBounds(const ShapeResult::RunInfo&, const Vector<Glyph>&);
-#endif
-
   void InsertRun(std::unique_ptr<ShapeResult::RunInfo>,
                  unsigned start_glyph,
                  unsigned num_glyphs,
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index 4d1ceec..811beb0 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -354,14 +354,18 @@
   return FloatRect(bounds);
 }
 
-void SimpleFontData::BoundsForGlyphs(const Vector<Glyph> glyphs,
-                                     Vector<SkRect>* bounds) const {
+void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256> glyphs,
+                                     Vector<FloatRect, 256>* bounds) const {
   DCHECK_EQ(glyphs.size(), bounds->size());
 
   if (!platform_data_.size())
     return;
 
-  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, bounds->data());
+  Vector<SkRect, 256> skia_bounds(glyphs.size());
+  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, skia_bounds.data());
+
+  for (unsigned i = 0; i < skia_bounds.size(); i++)
+    (*bounds)[i] = FloatRect(skia_bounds[i]);
 }
 
 float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const {
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h
index a1e85e7..ea751f5 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.h
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -112,7 +112,7 @@
   }
 
   FloatRect BoundsForGlyph(Glyph) const;
-  void BoundsForGlyphs(const Vector<Glyph>, Vector<SkRect>*) const;
+  void BoundsForGlyphs(const Vector<Glyph, 256>, Vector<FloatRect, 256>*) const;
   FloatRect PlatformBoundsForGlyph(Glyph) const;
   float WidthForGlyph(Glyph) const;
   float PlatformWidthForGlyph(Glyph) const;
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
index 8c198b30..ea9fdbc6 100644
--- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
@@ -72,7 +72,7 @@
   }
 }
 
-void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph> glyphs,
+void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256> glyphs,
                                              SkRect* bounds) {
 #if defined(OS_MACOSX)
   for (unsigned i = 0; i < glyphs.size(); i++) {
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
index cad80134..e49ccee 100644
--- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
@@ -21,7 +21,7 @@
   void GetGlyphExtentsForHarfBuzz(hb_codepoint_t, hb_glyph_extents_t*);
 
   void GetSkiaBoundsForGlyph(Glyph, SkRect* bounds);
-  void GetSkiaBoundsForGlyphs(const Vector<Glyph>, SkRect*);
+  void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>, SkRect*);
   float GetSkiaWidthForGlyph(Glyph);
 
   static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 8d951cd..9cea6be 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -41,12 +41,14 @@
       const CanvasColorParams color_params,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper>
           context_provider_wrapper,
-      base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
+      base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
+      bool is_origin_top_left)
       : CanvasResourceProvider(size,
                                color_params,
                                std::move(context_provider_wrapper),
                                std::move(resource_dispatcher)),
-        msaa_sample_count_(msaa_sample_count) {}
+        msaa_sample_count_(msaa_sample_count),
+        is_origin_top_left_(is_origin_top_left) {}
 
   ~CanvasResourceProviderTexture() override = default;
 
@@ -116,15 +118,21 @@
     auto* gr = GetGrContext();
     DCHECK(gr);
 
-    SkImageInfo info = SkImageInfo::Make(
+    const SkImageInfo info = SkImageInfo::Make(
         Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
         kPremul_SkAlphaType, ColorParams().GetSkColorSpaceForSkSurfaces());
+
+    const enum GrSurfaceOrigin surface_origin =
+        is_origin_top_left_ ? kTopLeft_GrSurfaceOrigin
+                            : kBottomLeft_GrSurfaceOrigin;
+
     return SkSurface::MakeRenderTarget(gr, SkBudgeted::kNo, info,
-                                       msaa_sample_count_,
+                                       msaa_sample_count_, surface_origin,
                                        ColorParams().GetSkSurfaceProps());
   }
 
   const unsigned msaa_sample_count_;
+  const bool is_origin_top_left_;
 };
 
 // CanvasResourceProviderTextureGpuMemoryBuffer
@@ -143,12 +151,14 @@
       const CanvasColorParams color_params,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper>
           context_provider_wrapper,
-      base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher)
+      base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
+      bool is_origin_top_left)
       : CanvasResourceProviderTexture(size,
                                       msaa_sample_count,
                                       color_params,
                                       std::move(context_provider_wrapper),
-                                      std::move(resource_dispatcher)) {}
+                                      std::move(resource_dispatcher),
+                                      is_origin_top_left) {}
 
   ~CanvasResourceProviderTextureGpuMemoryBuffer() override = default;
   bool SupportsDirectCompositing() const override { return true; }
@@ -396,7 +406,8 @@
     unsigned msaa_sample_count,
     const CanvasColorParams& color_params,
     PresentationMode presentation_mode,
-    base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher) {
+    base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher,
+    bool is_origin_top_left) {
   const ResourceType* resource_type_fallback_list = nullptr;
   size_t list_length = 0;
 
@@ -449,7 +460,7 @@
         provider =
             std::make_unique<CanvasResourceProviderTextureGpuMemoryBuffer>(
                 size, msaa_sample_count, color_params, context_provider_wrapper,
-                resource_dispatcher);
+                resource_dispatcher, is_origin_top_left);
         break;
       case kRamGpuMemoryBufferResourceType:
         if (!SharedGpuContext::IsGpuCompositingEnabled())
@@ -478,7 +489,7 @@
           continue;
         provider = std::make_unique<CanvasResourceProviderTexture>(
             size, msaa_sample_count, color_params, context_provider_wrapper,
-            resource_dispatcher);
+            resource_dispatcher, is_origin_top_left);
         break;
       case kBitmapResourceType:
         provider = std::make_unique<CanvasResourceProviderBitmap>(
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 12866715..bdae01b 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -80,7 +80,8 @@
       unsigned msaa_sample_count,
       const CanvasColorParams&,
       PresentationMode,
-      base::WeakPtr<CanvasResourceDispatcher>);
+      base::WeakPtr<CanvasResourceDispatcher>,
+      bool is_origin_top_left = true);
 
   // Use this method for capturing a frame that is intended to be displayed via
   // the compositor. Cases that need to acquire a snaptshot that is not destined
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h
index 710bc400..f8c442d 100644
--- a/third_party/blink/renderer/platform/heap/heap.h
+++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -679,11 +679,17 @@
 template <typename T>
 void Visitor::HandleWeakCell(Visitor* self, void* object) {
   T** cell = reinterpret_cast<T**>(object);
-  // '-1' means deleted value. This can happen when weak fields are deleted
-  // while incremental marking is running.
-  if (*cell && (*cell == reinterpret_cast<T*>(-1) ||
-                !ObjectAliveTrait<T>::IsHeapObjectAlive(*cell)))
-    *cell = nullptr;
+  T* contents = *cell;
+  if (contents) {
+    if (contents == reinterpret_cast<T*>(-1)) {
+      // '-1' means deleted value. This can happen when weak fields are deleted
+      // while incremental marking is running. Deleted values need to be
+      // preserved to avoid reviving objects in containers.
+      return;
+    }
+    if (!ObjectAliveTrait<T>::IsHeapObjectAlive(contents))
+      *cell = nullptr;
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
index 1612347..3b0f678 100644
--- a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
@@ -1645,7 +1645,7 @@
 }
 
 TEST(IncrementalMarkingTest, DropBackingStore) {
-  // Regression test: crbug.com/828537
+  // Regression test: https://crbug.com/828537
   using WeakStore = HeapHashCountedSet<WeakMember<Object>>;
 
   Persistent<WeakStore> persistent(new WeakStore);
@@ -1659,6 +1659,42 @@
   driver.FinishGC();
 }
 
+TEST(IncrementalMarkingTest, WeakCallbackDoesNotReviveDeletedValue) {
+  // Regression test: https://crbug.com/870196
+
+  // std::pair avoids treating the hashset backing as weak backing.
+  using WeakStore = HeapHashCountedSet<std::pair<WeakMember<Object>, size_t>>;
+
+  Persistent<WeakStore> persistent(new WeakStore);
+  // Create at least two entries to avoid completely emptying out the data
+  // structure. The values for .second are chosen to be non-null as they
+  // would otherwise count as empty and be skipped during iteration after the
+  // first part died.
+  persistent->insert({Object::Create(), 1});
+  persistent->insert({Object::Create(), 2});
+  IncrementalMarkingTestDriver driver(ThreadState::Current());
+  driver.Start();
+  // The backing is not treated as weak backing and thus eagerly processed,
+  // effectively registering the slots of WeakMembers.
+  driver.FinishSteps();
+  // The following deletes the first found entry. The second entry is left
+  // untouched.
+  for (auto& entries : *persistent) {
+    persistent->erase(entries.key);
+    break;
+  }
+  driver.FinishGC();
+
+  size_t count = 0;
+  for (const auto& entry : *persistent) {
+    count++;
+    // Use the entry to keep compilers happy.
+    if (entry.key.second > 0) {
+    }
+  }
+  CHECK_EQ(1u, count);
+}
+
 }  // namespace incremental_marking_test
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.cc b/third_party/blink/renderer/platform/loader/cors/cors.cc
index cf4b5be..cf71063 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -104,18 +104,19 @@
       !privilege->block_local_access_from_local_origin_);
 }
 
-base::Optional<network::mojom::CORSError> CheckRedirectLocation(
-    const KURL& url) {
-  static const bool run_blink_side_scheme_check =
-      !RuntimeEnabledFeatures::OutOfBlinkCORSEnabled();
-  // TODO(toyoshim): Deprecate Blink side scheme check when we enable
-  // out-of-renderer CORS support. This will need to deprecate Blink APIs that
-  // are currently used by an embedder. See https://crbug.com/800669.
-  if (run_blink_side_scheme_check &&
-      !SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(url.Protocol())) {
-    return network::mojom::CORSError::kRedirectDisallowedScheme;
-  }
-  return network::cors::CheckRedirectLocation(url, run_blink_side_scheme_check);
+base::Optional<network::CORSErrorStatus> CheckRedirectLocation(
+    const KURL& url,
+    network::mojom::FetchRequestMode request_mode,
+    const SecurityOrigin* origin,
+    CORSFlag cors_flag) {
+  base::Optional<url::Origin> origin_to_pass;
+  if (origin)
+    origin_to_pass = origin->ToUrlOrigin();
+
+  // Blink-side implementations rewrite the origin instead of setting the
+  // tainted flag.
+  return network::cors::CheckRedirectLocation(
+      url, request_mode, origin_to_pass, cors_flag == CORSFlag::Set, false);
 }
 
 base::Optional<network::mojom::CORSError> CheckPreflight(
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.h b/third_party/blink/renderer/platform/loader/cors/cors.h
index 7d25995b..5a192c7 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.h
+++ b/third_party/blink/renderer/platform/loader/cors/cors.h
@@ -18,6 +18,11 @@
 class KURL;
 class SecurityOrigin;
 
+enum class CORSFlag : uint8_t {
+  Unset,
+  Set,
+};
+
 // CORS related utility functions.
 namespace CORS {
 
@@ -38,8 +43,11 @@
     network::mojom::FetchCredentialsMode,
     const SecurityOrigin&);
 
-PLATFORM_EXPORT base::Optional<network::mojom::CORSError> CheckRedirectLocation(
-    const KURL&);
+PLATFORM_EXPORT base::Optional<network::CORSErrorStatus> CheckRedirectLocation(
+    const KURL&,
+    network::mojom::FetchRequestMode,
+    const SecurityOrigin*,
+    CORSFlag);
 
 PLATFORM_EXPORT base::Optional<network::mojom::CORSError> CheckPreflight(
     const int preflight_response_status_code);
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
index 1b67826..ef29410 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
@@ -199,11 +199,6 @@
                        " is not allowed by "
                        "Access-Control-Allow-Headers in preflight response."});
       break;
-    case CORSError::kRedirectDisallowedScheme:
-      Append(builder, {"Redirect location '", hint,
-                       "' has a disallowed scheme for cross-origin "
-                       "requests."});
-      break;
     case CORSError::kRedirectContainsCredentials:
       Append(builder, {"Redirect location '", hint,
                        "' contains a username and password, which is "
diff --git a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
index 961f89d..20ef7e6 100644
--- a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
@@ -30,8 +30,7 @@
 
   enabled_hints.SetIsEnabled(
       mojom::WebClientHintsType::kDeviceMemory,
-      enabled_hints.IsEnabled(mojom::WebClientHintsType::kDeviceMemory) &&
-          RuntimeEnabledFeatures::DeviceMemoryHeaderEnabled());
+      enabled_hints.IsEnabled(mojom::WebClientHintsType::kDeviceMemory));
 
   enabled_hints.SetIsEnabled(
       mojom::WebClientHintsType::kRtt,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 5ab5d282..a7636e51 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/platform/instance_counters.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
+#include "third_party/blink/renderer/platform/loader/cors/cors.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
@@ -59,6 +60,7 @@
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/weborigin/known_ports.h"
+#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 #include "third_party/blink/renderer/platform/weborigin/security_violation_reporting_policy.h"
@@ -746,11 +748,23 @@
   if (!params.Url().IsValid())
     return ResourceRequestBlockedReason::kOther;
 
-  params.MutableOptions().cors_flag =
-      !origin || !origin->CanRequest(params.Url());
-
-  if (options.cors_handling_by_resource_fetcher ==
-      kEnableCORSHandlingByResourceFetcher) {
+  if (!RuntimeEnabledFeatures::OutOfBlinkCORSEnabled() &&
+      options.cors_handling_by_resource_fetcher ==
+          kEnableCORSHandlingByResourceFetcher) {
+    if (CORS::IsCORSEnabledRequestMode(
+            resource_request.GetFetchRequestMode())) {
+      DCHECK(origin);
+      if (!origin->CanRequest(params.Url())) {
+        params.MutableOptions().cors_flag = true;
+        // Cross-origin requests are only allowed certain registered schemes.
+        if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(
+                url.Protocol())) {
+          // This won't create a CORS related console error.
+          // TODO(yhirano): Fix this.
+          return ResourceRequestBlockedReason::kOther;
+        }
+      }
+    }
     bool allow_stored_credentials = false;
     switch (resource_request.GetFetchCredentialsMode()) {
       case network::mojom::FetchCredentialsMode::kOmit:
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index ba4068d..551c0a7 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -52,6 +52,7 @@
 #include "third_party/blink/renderer/platform/network/network_instrumentation.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
+#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_violation_reporting_policy.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -321,14 +322,16 @@
             kEnableCORSHandlingByResourceFetcher &&
         fetch_request_mode == network::mojom::FetchRequestMode::kCORS) {
       scoped_refptr<const SecurityOrigin> source_origin = GetSourceOrigin();
-      WebSecurityOrigin source_web_origin(source_origin.get());
-      WrappedResourceRequest new_request_wrapper(*new_request);
-      base::Optional<network::CORSErrorStatus> cors_error =
-          WebCORS::HandleRedirect(
-              source_web_origin, new_request_wrapper, redirect_response.Url(),
-              redirect_response.HttpStatusCode(),
-              redirect_response.HttpHeaderFields(), fetch_credentials_mode,
-              resource_->MutableOptions());
+      base::Optional<network::CORSErrorStatus> cors_error;
+      cors_error = CORS::CheckRedirectLocation(
+          new_url, fetch_request_mode, source_origin.get(),
+          GetCORSFlag() ? CORSFlag::Set : CORSFlag::Unset);
+      if (!cors_error && GetCORSFlag()) {
+        cors_error =
+            CORS::CheckAccess(new_url, redirect_response.HttpStatusCode(),
+                              redirect_response.HttpHeaderFields(),
+                              fetch_credentials_mode, *source_origin);
+      }
       if (cors_error) {
         resource_->SetCORSStatus(CORSStatus::kFailed);
 
@@ -345,8 +348,18 @@
                                           ResourceRequestBlockedReason::kOther);
         return false;
       }
-
-      source_origin = source_web_origin;
+      // If |actualResponse|’s location URL’s origin is not same origin with
+      // |request|’s current url’s origin and |request|’s origin is not same
+      // origin with |request|’s current url’s origin, then set |request|’s
+      // tainted origin flag.
+      if (resource_->Options().security_origin &&
+          !SecurityOrigin::AreSameSchemeHostPort(new_url,
+                                                 redirect_response.Url()) &&
+          !resource_->Options().security_origin->CanRequest(
+              redirect_response.Url())) {
+        resource_->MutableOptions().security_origin =
+            SecurityOrigin::CreateUniqueOpaque();
+      }
     }
     if (resource_type == Resource::kImage &&
         fetcher_->ShouldDeferImageLoad(new_url)) {
@@ -423,6 +436,24 @@
     return false;
   }
 
+  if (options.cors_handling_by_resource_fetcher ==
+          kEnableCORSHandlingByResourceFetcher &&
+      CORS::IsCORSEnabledRequestMode(fetch_request_mode)) {
+    const auto origin = GetSourceOrigin();
+    if (!origin->CanRequest(new_request->Url()))
+      resource_->MutableOptions().cors_flag = true;
+    if (GetCORSFlag()) {
+      // Cross-origin requests are only allowed certain registered schemes.
+      if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(
+              KURL(new_url).Protocol())) {
+        HandleError(ResourceError(
+            new_url, network::CORSErrorStatus(
+                         network::mojom::CORSError::kCORSDisabledScheme)));
+        return false;
+      }
+    }
+  }
+
   report_raw_headers = new_request->ReportRawHeaders();
 
   return true;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
index 0d10f6e6..cc9ddd3 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -174,6 +174,8 @@
   void OnProgress(uint64_t delta) override;
   void FinishedCreatingBlob(const scoped_refptr<BlobDataHandle>&);
 
+  bool GetCORSFlag() const { return resource_->Options().cors_flag; }
+
   base::Optional<ResourceRequestBlockedReason> CheckResponseNosniff(
       WebURLRequest::RequestContext,
       const ResourceResponse&) const;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index bc35aeb..f304eb12 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -104,10 +104,6 @@
       status: "experimental",
     },
     {
-      name: "AudioWorklet",
-      status: "stable",
-    },
-    {
       name: "AutomationControlled",
       settable_from_internals: true,
     },
@@ -309,10 +305,6 @@
       name: "CSSOMSmoothScroll",
       status: "stable",
     },
-    {
-      name: "CSSOverscrollBehavior",
-      status: "stable",
-    },
     // Do not ship CSSPaintAPIArguments without shipping CSSVariables2 first.
     //
     // CSSPaintAPIArguments depends on parts of the the 'CSS Properties and
@@ -377,10 +369,6 @@
       status: "experimental",
     },
     {
-      name: "DeviceMemoryHeader",
-      status: "stable",
-    },
-    {
       name: "DisableHardwareNoiseSuppression",
       origin_trial_feature_name: "DisableHardwareNoiseSuppression",
       status: "experimental",
@@ -481,10 +469,6 @@
       status: "stable"
     },
     {
-      name: "FeaturePolicyForPermissions",
-      status: "stable"
-    },
-    {
       name: "FeaturePolicyJavaScriptInterface",
       origin_trial_feature_name: "FeaturePolicyJSAPI",
       status: "experimental"
@@ -588,10 +572,6 @@
       status: "stable",
     },
     {
-      name: "ImageDecodingAttribute",
-      status: "stable",
-    },
-    {
       name: "ImageOrientation",
       status: "test",
     },
@@ -954,10 +934,6 @@
       name: "PaymentApp",
       status: "experimental",
     },
-    {
-      name: "PaymentDetailsModifierData",
-      status: "stable",
-    },
     // PaymentRequest is enabled by default on Android
     {
       name: "PaymentRequest",
@@ -1306,10 +1282,6 @@
       status: "experimental",
     },
     {
-      name: "VisualViewportAPI",
-      status: "stable",
-    },
-    {
       name: "WakeLock",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
index 9ca45e2..db69771 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
@@ -25,6 +25,9 @@
       : id_(++last_id_), track_(std::move(track)) {}
   ~DummyWebRTCRtpSender() override {}
 
+  std::unique_ptr<WebRTCRtpSender> ShallowCopy() const override {
+    return nullptr;
+  }
   uintptr_t Id() const override { return id_; }
   WebMediaStreamTrack Track() const override { return track_; }
   WebVector<WebString> StreamIds() const override {
diff --git a/third_party/blink/tools/audit_non_blink_usage.py b/third_party/blink/tools/audit_non_blink_usage.py
index a60c1da..f7d057c 100755
--- a/third_party/blink/tools/audit_non_blink_usage.py
+++ b/third_party/blink/tools/audit_non_blink_usage.py
@@ -307,6 +307,7 @@
     {
         'paths': ['third_party/blink/renderer/core/inspector/inspector_memory_agent.cc'],
         'allowed': [
+            'base::ModuleCache',
             'base::SamplingHeapProfiler',
         ],
     },
diff --git a/third_party/blink/tools/blinkpy/common/net/layout_test_results.py b/third_party/blink/tools/blinkpy/common/net/layout_test_results.py
index 25f79b0..b3e6bd7 100644
--- a/third_party/blink/tools/blinkpy/common/net/layout_test_results.py
+++ b/third_party/blink/tools/blinkpy/common/net/layout_test_results.py
@@ -68,12 +68,14 @@
     def expected_results(self):
         return self._result_dict['expected']
 
+    def last_retry_result(self):
+        return self.actual_results().split()[-1]
+
     def has_mismatch_result(self):
-        last_retry_result = self.actual_results().split()[-1]
-        return last_retry_result in ('TEXT', 'IMAGE', 'IMAGE+TEXT', 'AUDIO')
+        return self.last_retry_result() in ('TEXT', 'IMAGE', 'IMAGE+TEXT', 'AUDIO')
 
     def is_missing_baseline(self):
-        return self._result_dict['actual'] == 'MISSING'
+        return self.last_retry_result() == 'MISSING'
 
 
 # FIXME: This should be unified with ResultsSummary or other NRWT layout tests code
diff --git a/third_party/blink/tools/blinkpy/tool/blink_tool.py b/third_party/blink/tools/blinkpy/tool/blink_tool.py
index 4ce694bb..821990c 100644
--- a/third_party/blink/tools/blinkpy/tool/blink_tool.py
+++ b/third_party/blink/tools/blinkpy/tool/blink_tool.py
@@ -49,7 +49,6 @@
 from blinkpy.tool.commands.queries import PrintBaselines
 from blinkpy.tool.commands.queries import PrintExpectations
 from blinkpy.tool.commands.rebaseline import Rebaseline
-from blinkpy.tool.commands.rebaseline import RebaselineExpectations
 from blinkpy.tool.commands.rebaseline_cl import RebaselineCL
 from blinkpy.tool.commands.rebaseline_test import RebaselineTest
 
@@ -84,7 +83,6 @@
             PrintExpectations(),
             Rebaseline(),
             RebaselineCL(),
-            RebaselineExpectations(),
             RebaselineTest(),
         ]
         self.help_command = HelpCommand(tool=self)
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
index de9dede70..00547b94 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
@@ -509,53 +509,6 @@
         return test_result
 
 
-class RebaselineExpectations(AbstractParallelRebaselineCommand):
-    name = 'rebaseline-expectations'
-    help_text = 'Rebaselines the tests indicated in TestExpectations.'
-    show_in_main_help = True
-
-    def __init__(self):
-        super(RebaselineExpectations, self).__init__(options=[
-            self.no_optimize_option,
-        ] + self.platform_options)
-        self._test_baseline_set = None
-
-    @staticmethod
-    def _tests_to_rebaseline(port):
-        tests_to_rebaseline = []
-        for path, value in port.expectations_dict().items():
-            expectations = TestExpectations(port, include_overrides=False, expectations_dict={path: value})
-            for test in expectations.get_rebaselining_failures():
-                tests_to_rebaseline.append(test)
-        return tests_to_rebaseline
-
-    def _add_tests_to_rebaseline(self, port_name):
-        builder_name = self._tool.builders.builder_name_for_port_name(port_name)
-        if not builder_name:
-            return
-        tests = self._tests_to_rebaseline(self._tool.port_factory.get(port_name))
-
-        if tests:
-            _log.info('Retrieving results for %s from %s.', port_name, builder_name)
-
-        for test_name in tests:
-            _log.info('    %s', test_name)
-            self._test_baseline_set.add(test_name, Build(builder_name))
-
-    def execute(self, options, args, tool):
-        self._tool = tool
-        self._test_baseline_set = TestBaselineSet(tool)
-        options.results_directory = None
-        port_names = tool.port_factory.all_port_names(options.platform)
-        for port_name in port_names:
-            self._add_tests_to_rebaseline(port_name)
-        if not self._test_baseline_set:
-            _log.warning('Did not find any tests marked Rebaseline.')
-            return
-
-        self.rebaseline(options, self._test_baseline_set)
-
-
 class Rebaseline(AbstractParallelRebaselineCommand):
     name = 'rebaseline'
     help_text = 'Rebaseline tests with results from the continuous builders.'
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
index eee4e15..be4b1fc 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
@@ -10,8 +10,7 @@
 from blinkpy.common.net.layout_test_results import LayoutTestResults
 from blinkpy.common.system.executive_mock import MockExecutive
 from blinkpy.tool.commands.rebaseline import (
-    AbstractParallelRebaselineCommand, Rebaseline, RebaselineExpectations,
-    TestBaselineSet
+    AbstractParallelRebaselineCommand, Rebaseline, TestBaselineSet
 )
 from blinkpy.tool.mock_tool import MockBlinkTool
 from blinkpy.web_tests.builder_list import BuilderList
@@ -688,291 +687,6 @@
             ])
 
 
-class TestRebaselineExpectations(BaseTestCase):
-    """Tests for the blink_tool.py rebaseline-expectations command."""
-
-    command_constructor = RebaselineExpectations
-
-    def setUp(self):
-        super(TestRebaselineExpectations, self).setUp()
-        self.tool.executive = MockExecutive()
-        self._zero_out_test_expectations()
-
-    @staticmethod
-    def options():
-        return optparse.Values({
-            'optimize': False,
-            'builders': None,
-            'suffixes': ['txt'],
-            'verbose': False,
-            'platform': None,
-            'results_directory': None
-        })
-
-    def test_rebaseline_expectations(self):
-        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
-            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
-                'tests': {
-                    'userscripts': {
-                        'another-test.html': {
-                            'expected': 'PASS',
-                            'actual': 'PASS TEXT'
-                        },
-                        'images.svg': {
-                            'expected': 'FAIL',
-                            'actual': 'IMAGE+TEXT'
-                        }
-                    }
-                }
-            }))
-
-        self._write('userscripts/another-test.html', 'Dummy test contents')
-        self._write('userscripts/images.svg', 'Dummy test contents')
-        self.command._tests_to_rebaseline = lambda port: {
-            'userscripts/another-test.html',
-            'userscripts/images.svg',
-            'userscripts/not-actually-failing.html',
-        }
-
-        self.command.execute(self.options(), [], self.tool)
-
-        self.assertEqual(self.tool.executive.calls, [
-            [
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'userscripts/another-test.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.10',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'userscripts/another-test.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.11',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'userscripts/images.svg',
-                    '--suffixes', 'txt,png',
-                    '--port-name', 'test-mac-mac10.10',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'userscripts/images.svg',
-                    '--suffixes', 'txt,png',
-                    '--port-name', 'test-mac-mac10.11',
-                ],
-            ],
-            [
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'userscripts/another-test.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.10',
-                    '--builder', 'MOCK Mac10.10',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'userscripts/another-test.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.11',
-                    '--builder', 'MOCK Mac10.11',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'userscripts/images.svg',
-                    '--suffixes', 'txt,png',
-                    '--port-name', 'test-mac-mac10.10',
-                    '--builder', 'MOCK Mac10.10',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'userscripts/images.svg',
-                    '--suffixes', 'txt,png',
-                    '--port-name', 'test-mac-mac10.11',
-                    '--builder', 'MOCK Mac10.11',
-                ],
-            ],
-        ])
-
-    def test_rebaseline_expectations_reftests(self):
-        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
-            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
-                'tests': {
-                    'userscripts': {
-                        'reftest-text.html': {
-                            'expected': 'PASS',
-                            'actual': 'TEXT'
-                        },
-                        'reftest-image.html': {
-                            'expected': 'FAIL',
-                            'actual': 'IMAGE'
-                        },
-                        'reftest-image-text.html': {
-                            'expected': 'FAIL',
-                            'actual': 'IMAGE+TEXT'
-                        }
-                    }
-                }
-            }))
-
-        self._write('userscripts/reftest-text.html', 'Dummy test contents')
-        self._write('userscripts/reftest-text-expected.html', 'Dummy test contents')
-        self._write('userscripts/reftest-text-expected.html', 'Dummy test contents')
-        self.command._tests_to_rebaseline = lambda port: {
-            'userscripts/reftest-text.html': set(['txt']),
-            'userscripts/reftest-image.html': set(['png']),
-            'userscripts/reftest-image-text.html': set(['png', 'txt']),
-        }
-
-        self.command.execute(self.options(), [], self.tool)
-
-        self.assertEqual(self.tool.executive.calls, [
-            [
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'userscripts/reftest-text.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.10',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'userscripts/reftest-text.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.11',
-                ],
-            ],
-            [
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'userscripts/reftest-text.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.10',
-                    '--builder', 'MOCK Mac10.10',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'userscripts/reftest-text.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.11',
-                    '--builder', 'MOCK Mac10.11',
-                ],
-            ],
-        ])
-
-    def test_rebaseline_expectations_noop(self):
-        self.command.execute(self.options(), [], self.tool)
-        self.assertEqual(self.tool.filesystem.written_files, {})
-
-    def disabled_test_overrides_are_included_correctly(self):
-        # TODO(qyearsley): Fix or remove this test method.
-        # This tests that any tests marked as REBASELINE in the overrides are found, but
-        # that the overrides do not get written into the main file.
-
-        self._write(self.test_expectations_path, '')
-        self.mac_port.expectations_dict = lambda: {
-            self.test_expectations_path: '',
-            'overrides': ('Bug(x) userscripts/another-test.html [ Failure Rebaseline ]\n'
-                          'Bug(y) userscripts/test.html [ Crash ]\n')}
-        self._write('/userscripts/another-test.html', '')
-
-        self.assertDictEqual(self.command._tests_to_rebaseline(self.mac_port),
-                             {'userscripts/another-test.html': set(['png', 'txt', 'wav'])})
-        self.assertEqual(self._read(self.test_expectations_path), '')
-
-    def test_rebaseline_without_other_expectations(self):
-        self._write('userscripts/another-test.html', 'Dummy test contents')
-        self._write(self.test_expectations_path, 'Bug(x) userscripts/another-test.html [ Rebaseline ]\n')
-        self.assertEqual(self.command._tests_to_rebaseline(self.mac_port), ['userscripts/another-test.html'])
-
-    def test_rebaseline_missing(self):
-        self.tool.buildbot.set_results(Build('MOCK Mac10.10'), LayoutTestResults({
-            'tests': {
-                'fast': {
-                    'dom': {
-                        'missing-text.html': {
-                            'expected': 'PASS',
-                            'actual': 'MISSING',
-                            'is_unexpected': True,
-                            'is_missing_text': True
-                        },
-                        'missing-text-and-image.html': {
-                            'expected': 'PASS',
-                            'actual': 'MISSING',
-                            'is_unexpected': True,
-                            'is_missing_text': True,
-                            'is_missing_image': True
-                        },
-                        'missing-image.html': {
-                            'expected': 'PASS',
-                            'actual': 'MISSING',
-                            'is_unexpected': True,
-                            'is_missing_image': True
-                        }
-                    }
-                }
-            }
-        }))
-
-        self._write('fast/dom/missing-text.html', 'Dummy test contents')
-        self._write('fast/dom/missing-text-and-image.html', 'Dummy test contents')
-        self._write('fast/dom/missing-image.html', 'Dummy test contents')
-
-        self.command._tests_to_rebaseline = lambda port: {
-            'fast/dom/missing-text.html': set(['txt', 'png']),
-            'fast/dom/missing-text-and-image.html': set(['txt', 'png']),
-            'fast/dom/missing-image.html': set(['txt', 'png']),
-        }
-
-        self.command.execute(self.options(), [], self.tool)
-
-        self.assertEqual(self.tool.executive.calls, [
-            [
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'fast/dom/missing-text.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.10',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'fast/dom/missing-text-and-image.html',
-                    '--suffixes', 'txt,png',
-                    '--port-name', 'test-mac-mac10.10',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'fast/dom/missing-image.html',
-                    '--suffixes', 'png',
-                    '--port-name', 'test-mac-mac10.10',
-                ],
-            ],
-            [
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'fast/dom/missing-text.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.10',
-                    '--builder', 'MOCK Mac10.10',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'fast/dom/missing-text-and-image.html',
-                    '--suffixes', 'txt,png',
-                    '--port-name', 'test-mac-mac10.10',
-                    '--builder', 'MOCK Mac10.10',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'fast/dom/missing-image.html',
-                    '--suffixes', 'png',
-                    '--port-name', 'test-mac-mac10.10',
-                    '--builder', 'MOCK Mac10.10',
-                ],
-            ]
-        ])
-
-
 class TestBaselineSetTest(unittest.TestCase):
 
     def setUp(self):
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer.py b/third_party/blink/tools/blinkpy/w3c/test_importer.py
index 04805ee..90cc6e3 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer.py
@@ -503,6 +503,9 @@
         if directory_owners:
             description += self._format_directory_owners(directory_owners) + '\n\n'
 
+        # Prevent FindIt from auto-reverting import CLs.
+        description += 'NOAUTOREVERT=true\n'
+
         # Move any No-Export tag to the end of the description.
         description = description.replace('No-Export: true', '')
         description = description.replace('\n\n\n\n', '\n\n')
diff --git a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
index b825383..ea073cd 100644
--- a/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/test_importer_unittest.py
@@ -308,6 +308,7 @@
             'lines to TestExpectations rather than reverting. See:\n'
             'https://chromium.googlesource.com'
             '/chromium/src/+/master/docs/testing/web_platform_tests.md\n\n'
+            'NOAUTOREVERT=true\n'
             'No-Export: true')
         self.assertEqual(host.executive.calls, [['git', 'log', '-1', '--format=%B']])
 
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
index 49ce28fa..5f1dac6 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -41,15 +41,19 @@
         self.finder = PathFinder(self.host.filesystem)
         self.ports_with_no_results = set()
         self.ports_with_all_pass = set()
+        self.patchset = None
 
     def run(self, args=None):
         parser = argparse.ArgumentParser(description=__doc__)
+        parser.add_argument('--patchset', default=None,
+                            help='Patchset number to fetch new baselines from.')
         parser.add_argument('-v', '--verbose', action='store_true', help='More verbose logging.')
         args = parser.parse_args(args)
 
         log_level = logging.DEBUG if args.verbose else logging.INFO
         configure_logging(logging_level=log_level, include_time=True)
 
+        self.patchset = args.patchset
         self.update_expectations()
 
         return 0
@@ -105,7 +109,7 @@
 
     def get_latest_try_jobs(self):
         """Returns the latest finished try jobs as Build objects."""
-        return self.git_cl.latest_try_jobs(self._get_try_bots())
+        return self.git_cl.latest_try_jobs(self._get_try_bots(), patchset=self.patchset)
 
     def get_failing_results_dict(self, build):
         """Returns a nested dict of failing test results.
@@ -255,21 +259,22 @@
 
         Returns:
             A set of one or more test expectation strings with the first letter
-            capitalized. Example: set(['Failure', 'Timeout']).
+            capitalized. Example: {'Failure', 'Timeout'}.
         """
+        actual_results = set(result.actual.split())
         # If the result is MISSING, this implies that the test was not
         # rebaselined and has an actual result but no baseline. We can't
         # add a Missing expectation (this is not allowed), but no other
         # expectation is correct.
         # We also want to skip any new manual tests that are not automated;
         # see crbug.com/708241 for context.
-        if (result.actual == 'MISSING' or
-                '-manual.' in test_name and result.actual == 'TIMEOUT'):
+        if ('MISSING' in actual_results or
+                '-manual.' in test_name and 'TIMEOUT' in actual_results):
             return {'Skip'}
         expectations = set()
-        failure_types = ('TEXT', 'IMAGE+TEXT', 'IMAGE', 'AUDIO')
-        other_types = ('TIMEOUT', 'CRASH', 'PASS')
-        for actual in result.actual.split():
+        failure_types = {'TEXT', 'IMAGE+TEXT', 'IMAGE', 'AUDIO'}
+        other_types = {'TIMEOUT', 'CRASH', 'PASS'}
+        for actual in actual_results:
             if actual in failure_types:
                 expectations.add('Failure')
             if actual in other_types:
@@ -496,14 +501,18 @@
             _log.info('  %s', test)
 
         blink_tool = self.finder.path_from_blink_tools('blink_tool.py')
-        self.host.executive.run_command([
+        command = [
             'python',
             blink_tool,
             'rebaseline-cl',
             '--verbose',
             '--no-trigger-jobs',
             '--fill-missing',
-        ] + tests_to_rebaseline)
+        ]
+        if self.patchset:
+            command.append('--patchset=' + str(self.patchset))
+        command += tests_to_rebaseline
+        self.host.executive.run_command(command)
         return tests_to_rebaseline, test_results
 
     def get_tests_to_rebaseline(self, test_results):
@@ -540,7 +549,7 @@
         """
         if self.is_reference_test(test_name):
             return False
-        if result.actual in ('CRASH', 'TIMEOUT', 'MISSING'):
+        if any(x in result.actual for x in ('CRASH', 'TIMEOUT', 'MISSING')):
             return False
         return True
 
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
index 9c84aa692..90c3733 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -257,12 +257,21 @@
             updater.get_expectations(SimpleTestResult('FAIL', 'PASS', 'bug')),
             {'Pass'})
         self.assertEqual(
+            updater.get_expectations(SimpleTestResult('FAIL', 'PASS PASS', 'bug')),
+            {'Pass'})
+        self.assertEqual(
             updater.get_expectations(SimpleTestResult('FAIL', 'TIMEOUT', 'bug')),
             {'Timeout'})
         self.assertEqual(
+            updater.get_expectations(SimpleTestResult('FAIL', 'TIMEOUT TIMEOUT', 'bug')),
+            {'Timeout'})
+        self.assertEqual(
             updater.get_expectations(SimpleTestResult('TIMEOUT', 'PASS', 'bug')),
             {'Pass'})
         self.assertEqual(
+            updater.get_expectations(SimpleTestResult('TIMEOUT', 'PASS PASS', 'bug')),
+            {'Pass'})
+        self.assertEqual(
             updater.get_expectations(SimpleTestResult('PASS', 'TEXT PASS', 'bug')),
             {'Pass', 'Failure'})
         self.assertEqual(
@@ -278,6 +287,9 @@
             updater.get_expectations(SimpleTestResult('Pass', 'MISSING', 'bug')),
             {'Skip'})
         self.assertEqual(
+            updater.get_expectations(SimpleTestResult('Pass', 'MISSING MISSING', 'bug')),
+            {'Skip'})
+        self.assertEqual(
             updater.get_expectations(SimpleTestResult('Pass', 'TIMEOUT', 'bug'), test_name='foo/bar-manual.html'),
             {'Skip'})
 
@@ -581,6 +593,26 @@
         # The original dict isn't modified.
         self.assertEqual(results, results_copy)
 
+    def test_get_tests_to_rebaseline_handles_retries(self):
+        host = self.mock_host()
+        results = {
+            'external/wpt/test/foo.html': {
+                'bot': SimpleTestResult(expected='PASS', actual='TEXT TEXT', bug='bug'),
+            },
+            'external/wpt/test/bar.html': {
+                'bot': SimpleTestResult(expected='PASS', actual='TIMEOUT TIMEOUT', bug='bug'),
+            },
+        }
+        updater = WPTExpectationsUpdater(host)
+        tests_to_rebaseline, modified_test_results = updater.get_tests_to_rebaseline(results)
+        self.assertEqual(tests_to_rebaseline, ['external/wpt/test/foo.html'])
+        self.assertEqual(modified_test_results, {
+            'external/wpt/test/foo.html': {},
+            'external/wpt/test/bar.html': {
+                'bot': SimpleTestResult(expected='PASS', actual='TIMEOUT TIMEOUT', bug='bug'),
+            },
+        })
+
     def test_run_no_issue_number(self):
         updater = WPTExpectationsUpdater(self.mock_host())
         updater.git_cl = MockGitCL(updater.host, issue_number='None')
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
index 594f481..fe8cfd8 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest.py
@@ -88,6 +88,17 @@
     def _get_extras_from_item(item):
         return item[-1]
 
+    @staticmethod
+    def _is_not_jsshell(item):
+        """Returns True if the manifest item isn't a jsshell test.
+
+        "jsshell" is one of the scopes automatically generated from .any.js
+        tests. It is intended to run in a thin JavaScript shell instead of a
+        full browser, so we simply ignore it in web tests. (crbug.com/871950)
+        """
+        extras = WPTManifest._get_extras_from_item(item)
+        return not extras.get('jsshell', False)
+
     @memoized
     def all_url_items(self):
         """Returns a dict mapping every URL in the manifest to its item."""
@@ -96,7 +107,7 @@
             return url_items
         for test_type in self.test_types:
             for records in self.raw_dict['items'][test_type].itervalues():
-                for item in records:
+                for item in filter(self._is_not_jsshell, records):
                     url_items[self._get_url_from_item(item)] = item
         return url_items
 
@@ -121,7 +132,8 @@
         manifest_items = self._items_for_file_path(path_in_wpt)
         assert manifest_items is not None
         # Remove the leading slashes when returning.
-        return [self._get_url_from_item(item)[1:] for item in manifest_items]
+        return [self._get_url_from_item(item)[1:]
+                for item in manifest_items if self._is_not_jsshell(item)]
 
     def is_slow_test(self, url):
         """Checks if a WPT is slow (long timeout) according to the manifest.
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
index 28a6362..5e7eb10 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_manifest_unittest.py
@@ -66,3 +66,43 @@
 
         with self.assertRaises(ScriptError):
             WPTManifest.ensure_manifest(host)
+
+    def test_all_url_items_skips_jsshell_tests(self):
+        manifest_json = '''
+{
+    "items": {
+        "manual": {},
+        "reftest": {},
+        "testharness": {
+            "test.any.js": [
+                ["/test.any.html", {}],
+                ["/test.any.js", {"jsshell": true}]
+            ]
+        }
+    }
+}
+        '''
+        manifest = WPTManifest(manifest_json)
+        self.assertEqual(manifest.all_url_items(),
+                         {u'/test.any.html': [u'/test.any.html', {}]})
+
+    def test_file_path_to_url_paths(self):
+        manifest_json = '''
+{
+    "items": {
+        "manual": {},
+        "reftest": {},
+        "testharness": {
+            "test.any.js": [
+                ["/test.any.html", {}],
+                ["/test.any.js", {"jsshell": true}]
+            ]
+        }
+    }
+}
+        '''
+        manifest = WPTManifest(manifest_json)
+        # Leading slashes should be stripped; and jsshell tests shouldn't be
+        # included.
+        self.assertEqual(manifest.file_path_to_url_paths('test.any.js'),
+                         [u'test.any.html'])
diff --git a/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py
index f7ce07b..81d036eb 100644
--- a/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py
+++ b/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py
@@ -218,7 +218,7 @@
             # Distinct resulting expectations.
             result_exp = map(string_to_exp, result_strings)
 
-            expected = lambda e: TestExpectations.result_was_expected(e, expectations, False)
+            expected = lambda e: TestExpectations.result_was_expected(e, expectations)
 
             additional_expectations = set(e for e in result_exp if not expected(e))
 
@@ -328,7 +328,7 @@
                 # individual runs' full_results.json, which would be slow and more complicated.
                 # The only thing we lose by not fixing this is that a test that was flaky
                 # and got fixed will still get printed out until 100 runs have passed.
-                if not TestExpectations.result_was_expected(result_enum, latest_expectations, test_needs_rebaselining=False):
+                if not TestExpectations.result_was_expected(result_enum, latest_expectations):
                     has_unexpected_results = True
                     break
 
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
index 7bdc8c04..70f1267 100644
--- a/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
+++ b/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
@@ -44,7 +44,7 @@
 # FIXME: range() starts with 0 which makes if expectation checks harder
 # as PASS is 0.
 (PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, LEAK, SKIP, WONTFIX,
- SLOW, REBASELINE, NEEDS_REBASELINE_UNUSED, NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NOW, NONE) = range(19)
+ SLOW, MISSING, FLAKY, NOW, NONE) = range(16)
 
 WEBKIT_BUG_PREFIX = 'webkit.org/b/'
 CHROMIUM_BUG_PREFIX = 'crbug.com/'
@@ -73,7 +73,6 @@
 
     # FIXME: Rename these to *_KEYWORD as in MISSING_KEYWORD above, but make
     # the case studdly-caps to match the actual file contents.
-    REBASELINE_MODIFIER = 'rebaseline'
     PASS_EXPECTATION = 'pass'
     SKIP_MODIFIER = 'skip'
     SLOW_MODIFIER = 'slow'
@@ -160,12 +159,7 @@
         expectations = [expectation.lower() for expectation in expectation_line.expectations]
         if not expectation_line.bugs and self.WONTFIX_MODIFIER not in expectations:
             expectation_line.warnings.append(self.MISSING_BUG_WARNING)
-        if self.REBASELINE_MODIFIER in expectations:
-            expectation_line.warnings.append('REBASELINE should only be used for running rebaseline.py. Cannot be checked in.')
-
         specifiers = [specifier.lower() for specifier in expectation_line.specifiers]
-        if self.REBASELINE_MODIFIER in expectations and ('debug' in specifiers or 'release' in specifiers):
-            expectation_line.warnings.append('A test cannot be rebaselined for Debug/Release.')
 
     def _parse_expectations(self, expectation_line):
         result = set()
@@ -296,7 +290,6 @@
         'Failure': 'FAIL',
         MISSING_KEYWORD: 'MISSING',
         'Pass': 'PASS',
-        'Rebaseline': 'REBASELINE',
         'Skip': 'SKIP',
         'Slow': 'SLOW',
         'Timeout': 'TIMEOUT',
@@ -904,7 +897,6 @@
         TestExpectationParser.SKIP_MODIFIER: SKIP,
         TestExpectationParser.WONTFIX_MODIFIER: WONTFIX,
         TestExpectationParser.SLOW_MODIFIER: SLOW,
-        TestExpectationParser.REBASELINE_MODIFIER: REBASELINE,
     }
 
     EXPECTATIONS_TO_STRING = {k: v.upper() for (v, k) in EXPECTATIONS.iteritems()}
@@ -953,12 +945,11 @@
             raise ValueError(expectation)
 
     @staticmethod
-    def result_was_expected(result, expected_results, test_needs_rebaselining):
+    def result_was_expected(result, expected_results):
         """Returns whether we got a result we were expecting.
         Args:
             result: actual result of a test execution
             expected_results: set of results listed in test_expectations
-            test_needs_rebaselining: whether test was marked as REBASELINE
         """
         local_expected = set(expected_results)
         if WONTFIX in local_expected:
@@ -967,19 +958,14 @@
 
         # Make sure we have at least one result type that may actually happen.
         local_expected.discard(WONTFIX)
-        local_expected.discard(REBASELINE)
         local_expected.discard(SLOW)
         if not local_expected:
             local_expected = {PASS}
 
         if result in local_expected:
             return True
-        if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and NEEDS_MANUAL_REBASELINE in local_expected:
-            return True
         if result in (TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO) and FAIL in local_expected:
             return True
-        if result == MISSING and test_needs_rebaselining:
-            return True
         return False
 
     @staticmethod
@@ -1090,9 +1076,6 @@
     def expectations(self):
         return self._expectations
 
-    def get_rebaselining_failures(self):
-        return self._model.get_test_set(REBASELINE)
-
     # FIXME: Change the callsites to use TestExpectationsModel and remove.
     def get_expectations(self, test):
         return self._model.get_expectations(test)
@@ -1118,10 +1101,7 @@
             expected_results = self.remove_non_sanitizer_failures(expected_results)
         elif not pixel_tests_are_enabled:
             expected_results = self.remove_pixel_failures(expected_results)
-        return self.result_was_expected(result, expected_results, self.is_rebaselining(test))
-
-    def is_rebaselining(self, test):
-        return REBASELINE in self._model.get_expectations(test)
+        return self.result_was_expected(result, expected_results)
 
     def _shorten_filename(self, filename):
         finder = PathFinder(self._port.host.filesystem)
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py b/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py
index ce72aa0..ff92d5a1 100644
--- a/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/models/test_expectations_unittest.py
@@ -36,7 +36,7 @@
 from blinkpy.web_tests.models.test_expectations import (
     TestExpectationLine, TestExpectations, ParseError, TestExpectationParser,
     PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO,
-    TIMEOUT, CRASH, LEAK, SKIP, WONTFIX, NEEDS_MANUAL_REBASELINE, MISSING
+    TIMEOUT, CRASH, LEAK, SKIP, WONTFIX, MISSING
 )
 
 
@@ -121,35 +121,15 @@
 
     def test_result_was_expected(self):
         # test basics
-        self.assertEqual(TestExpectations.result_was_expected(PASS, set([PASS]), test_needs_rebaselining=False), True)
-        self.assertEqual(TestExpectations.result_was_expected(FAIL, set([PASS]), test_needs_rebaselining=False), False)
+        self.assertEqual(TestExpectations.result_was_expected(PASS, set([PASS])), True)
+        self.assertEqual(TestExpectations.result_was_expected(FAIL, set([PASS])), False)
 
         # test handling of SKIPped tests and results
-        self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False), False)
-        self.assertEqual(TestExpectations.result_was_expected(SKIP, set([LEAK]), test_needs_rebaselining=False), False)
+        self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH])), False)
+        self.assertEqual(TestExpectations.result_was_expected(SKIP, set([LEAK])), False)
 
-        # test handling of MISSING results and the REBASELINE specifier
-        self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=True), True)
-        self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=False), False)
-
-        self.assertTrue(TestExpectations.result_was_expected(
-            PASS, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(
-            MISSING, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(
-            TEXT, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(
-            IMAGE, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(
-            IMAGE_PLUS_TEXT, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(
-            AUDIO, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertFalse(TestExpectations.result_was_expected(
-            TIMEOUT, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertFalse(TestExpectations.result_was_expected(
-            CRASH, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
-        self.assertFalse(TestExpectations.result_was_expected(
-            LEAK, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        # test handling of MISSING results
+        self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS])), False)
 
     def test_remove_pixel_failures(self):
         self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL]))
@@ -776,17 +756,6 @@
 """, actual_expectations)
 
 
-class RebaseliningTest(Base):
-
-    def test_get_rebaselining_failures(self):
-        # Make sure we find a test as needing a rebaseline even if it is not marked as a failure.
-        self.parse_exp('Bug(x) failures/expected/text.html [ Rebaseline ]\n')
-        self.assertEqual(len(self._exp.get_rebaselining_failures()), 1)
-
-        self.parse_exp(self.get_basic_expectations())
-        self.assertEqual(len(self._exp.get_rebaselining_failures()), 0)
-
-
 class TestExpectationsParserTests(unittest.TestCase):
 
     def __init__(self, testFunc):
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/test_run_results_unittest.py b/third_party/blink/tools/blinkpy/web_tests/models/test_run_results_unittest.py
index 5b9689a..5c587d78 100644
--- a/third_party/blink/tools/blinkpy/web_tests/models/test_run_results_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/models/test_run_results_unittest.py
@@ -205,7 +205,6 @@
                 'TEXT': 1,
                 'IMAGE': 1,
                 'PASS': 0,
-                'REBASELINE': 0,
                 'SKIP': 0,
                 'SLOW': 0,
                 'TIMEOUT': 3,
@@ -225,7 +224,6 @@
                 'TEXT': 0,
                 'IMAGE': 0,
                 'PASS': 1,
-                'REBASELINE': 0,
                 'SKIP': 0,
                 'SLOW': 0,
                 'TIMEOUT': 1,
@@ -245,7 +243,6 @@
                 'TEXT': 0,
                 'IMAGE': 0,
                 'PASS': 5,
-                'REBASELINE': 0,
                 'SKIP': 1,
                 'SLOW': 0,
                 'TIMEOUT': 0,
diff --git a/third_party/blink/tools/blinkpy/web_tests/update_expectations.py b/third_party/blink/tools/blinkpy/web_tests/update_expectations.py
index 526f4b43..d40f91d1 100644
--- a/third_party/blink/tools/blinkpy/web_tests/update_expectations.py
+++ b/third_party/blink/tools/blinkpy/web_tests/update_expectations.py
@@ -230,8 +230,6 @@
             otherwise.
         """
         unstrippable_expectations = (
-            'NEEDSMANUALREBASELINE',
-            'REBASELINE',
             'SKIP',
             'SLOW',
         )
diff --git a/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py b/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py
index 0ab4ee3..3eba707 100644
--- a/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/update_expectations_unittest.py
@@ -172,8 +172,7 @@
             # expectations are flaky so we shouldn't remove any.
             Bug(test) test/a.html [ Pass ]
             Bug(test) test/b.html [ Timeout ]
-            Bug(test) test/c.html [ Failure Timeout ]
-            Bug(test) test/d.html [ Rebaseline ]"""
+            Bug(test) test/c.html [ Failure Timeout ]"""
 
         self._expectations_remover = (
             self._create_expectations_remover(self.FLAKE_TYPE))
@@ -213,8 +212,7 @@
             # expectations are failing so we shouldn't remove any.
             Bug(test) test/a.html [ Pass ]
             Bug(test) test/b.html [ Failure Pass ]
-            Bug(test) test/c.html [ Failure Pass Timeout ]
-            Bug(test) test/d.html [ Rebaseline ]"""
+            Bug(test) test/c.html [ Failure Pass Timeout ]"""
 
         self._expectations_remover = (
             self._create_expectations_remover(self.FAIL_TYPE))
@@ -344,36 +342,6 @@
         self._assert_expectations_match(
             updated_expectations, test_expectations_before)
 
-    def test_dont_remove_rebaselines(self):
-        """Tests that lines with rebaseline expectations are untouched."""
-        test_expectations_before = """
-            # Even though the results show all passing, none of the
-            # expectations are flaky or failing so we shouldn't remove any.
-            Bug(test) test/a.html [ Failure Pass Rebaseline ]
-            Bug(test) test/b.html [ Failure Rebaseline ]"""
-
-        self._expectations_remover = self._create_expectations_remover()
-        self._define_builders({
-            'WebKit Linux Trusty': {
-                'port_name': 'linux-trusty',
-                'specifiers': ['Trusty', 'Release']
-            },
-        })
-        self._port.all_build_types = ('release',)
-        self._port.all_systems = (('trusty', 'x86_64'),)
-
-        self._parse_expectations(test_expectations_before)
-        self._expectation_factory.all_results_by_builder = {
-            'WebKit Linux Trusty': {
-                'test/a.html': ['PASS', 'PASS'],
-                'test/b.html': ['PASS', 'PASS'],
-            }
-        }
-        updated_expectations = (
-            self._expectations_remover.get_updated_test_expectations())
-        self._assert_expectations_match(
-            updated_expectations, test_expectations_before)
-
     def test_all_failure_result_types(self):
         """Tests that all failure types are treated as failure."""
         test_expectations_before = (
diff --git a/third_party/deqp/LICENSE b/third_party/deqp/LICENSE
deleted file mode 100644
index 0a93ef7..0000000
--- a/third_party/deqp/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/third_party/deqp/OWNERS b/third_party/deqp/OWNERS
deleted file mode 100644
index 6661c1f..0000000
--- a/third_party/deqp/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jmadill@chromium.org
-kbr@chromium.org
diff --git a/third_party/deqp/README.chromium b/third_party/deqp/README.chromium
deleted file mode 100644
index ca6e5f23..0000000
--- a/third_party/deqp/README.chromium
+++ /dev/null
@@ -1,13 +0,0 @@
-Name: drawElements Quality Program
-Short Name: dEQP
-Version: 1.0
-URL: https://source.android.com/devices/graphics/testing.html
-SOURCE CODE: git clone -b deqp-dev https://android.googlesource.com/platform/external/deqp/
-Date: 16/06/2015
-Revision: 554adf152573fb579d0cbc68d3c1395e5ee94391
-Security Critical: no
-License: Apache 2.0
-License File: LICENSE
-
-Description:
-dEQP is a set of tests and testing tools for GPUs and their drivers. It currently supports OpenGL ES 2.0 - 3.1 & AEP and EGL. The dEQP has been part of the Android CTS since the L release.
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index bfb1124..d8a3088 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -2,9 +2,9 @@
 Short Name: libaom
 URL: https://aomedia.googlesource.com/aom/
 Version: 0
-Date: Tuesday July 31 2018
+Date: Monday August 06 2018
 Branch: master
-Commit: bc484c485277bc19c7a1b273c8cf5472f741b73a
+Commit: 7a76b645a08ce45ef52dfb7fd719a26c1af1da85
 License: BSD
 License File: source/libaom/LICENSE
 Security Critical: yes
diff --git a/third_party/libaom/cmake_update.sh b/third_party/libaom/cmake_update.sh
index d4e5653..8d8a25c0 100755
--- a/third_party/libaom/cmake_update.sh
+++ b/third_party/libaom/cmake_update.sh
@@ -12,17 +12,18 @@
 # Usage:
 # $ ./cmake_update.sh
 # Requirements:
+# Install the following Debian packages.
 # - cmake3
 # - yasm or nasm
 # Toolchain for armv7:
-#  -gcc-arm-linux-gnueabihf
-#  -g++-arm-linux-gnueabihf
+# - gcc-arm-linux-gnueabihf
+# - g++-arm-linux-gnueabihf
 # Toolchain for arm64:
-#  -gcc-aarch64-linux-gnu
-#  -g++-aarch64-linux-gnu
+# - gcc-aarch64-linux-gnu
+# - g++-aarch64-linux-gnu
 # 32bit build environment for cmake. Including but potentially not limited to:
-#  -lib32gcc-7-dev
-#  -lib32stdc++-7-dev
+# - lib32gcc-7-dev
+# - lib32stdc++-7-dev
 # Alternatively: treat 32bit builds like Windows and manually tweak aom_config.h
 
 set -eE
diff --git a/third_party/libaom/libaom_srcs.gni b/third_party/libaom/libaom_srcs.gni
index 89de9a5..78199e4d 100644
--- a/third_party/libaom/libaom_srcs.gni
+++ b/third_party/libaom/libaom_srcs.gni
@@ -293,6 +293,8 @@
   "//third_party/libaom/source/libaom/av1/encoder/rd.h",
   "//third_party/libaom/source/libaom/av1/encoder/rdopt.c",
   "//third_party/libaom/source/libaom/av1/encoder/rdopt.h",
+  "//third_party/libaom/source/libaom/av1/encoder/reconinter_enc.c",
+  "//third_party/libaom/source/libaom/av1/encoder/reconinter_enc.h",
   "//third_party/libaom/source/libaom/av1/encoder/segmentation.c",
   "//third_party/libaom/source/libaom/av1/encoder/segmentation.h",
   "//third_party/libaom/source/libaom/av1/encoder/speed_features.c",
@@ -403,7 +405,6 @@
 
 aom_dsp_common_sources = [
   "//third_party/libaom/source/libaom/aom_dsp/aom_convolve.c",
-  "//third_party/libaom/source/libaom/aom_dsp/aom_convolve.h",
   "//third_party/libaom/source/libaom/aom_dsp/aom_dsp_common.h",
   "//third_party/libaom/source/libaom/aom_dsp/aom_filter.h",
   "//third_party/libaom/source/libaom/aom_dsp/aom_simd.h",
@@ -467,7 +468,7 @@
   "//third_party/libaom/source/libaom/aom_scale/aom_scale_rtcd.c",
   "//third_party/libaom/source/libaom/av1/common/av1_rtcd_defs.pl",
   "//third_party/libaom/source/libaom/av1/common/av1_rtcd.c",
-  "//third_party/libaom/source/libaom/build/make/rtcd.pl",
+  "//third_party/libaom/source/libaom/build/cmake/rtcd.pl",
 ]
 
 aom_scale_intrin_dspr2 = [
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h
index d106138..c209ba8 100644
--- a/third_party/libaom/source/config/config/aom_version.h
+++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 0
 #define VERSION_PATCH 0
-#define VERSION_EXTRA "262-gbc484c485"
+#define VERSION_EXTRA "334-g7a76b645a"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "1.0.0-262-gbc484c485"
-#define VERSION_STRING " 1.0.0-262-gbc484c485"
+#define VERSION_STRING_NOSP "1.0.0-334-g7a76b645a"
+#define VERSION_STRING " 1.0.0-334-g7a76b645a"
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
index 062ba8b..8fcaa83e 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
@@ -13,62 +13,61 @@
 ARCH_PPC equ 0
 ARCH_X86 equ 0
 ARCH_X86_64 equ 0
-CONFIG_ACCOUNTING equ 0
-CONFIG_ANALYZER equ 0
-CONFIG_AV1_DECODER equ 1
-CONFIG_AV1_ENCODER equ 0
-CONFIG_BIG_ENDIAN equ 0
-CONFIG_BITSTREAM_DEBUG equ 0
-CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
-CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
-CONFIG_COLLECT_RD_STATS equ 0
-CONFIG_DEBUG equ 0
-CONFIG_DENOISE equ 0
-CONFIG_DIST_8X8 equ 1
-CONFIG_ENTROPY_STATS equ 0
-CONFIG_FILEOPTIONS equ 1
-CONFIG_FIX_GF_LENGTH equ 1
-CONFIG_FP_MB_STATS equ 0
-CONFIG_GCC equ 1
-CONFIG_GCOV equ 0
-CONFIG_GPROF equ 0
-CONFIG_INSPECTION equ 0
-CONFIG_INTERNAL_STATS equ 0
-CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
-CONFIG_LOWBITDEPTH equ 1
-CONFIG_MAX_DECODE_PROFILE equ 0
-CONFIG_MISMATCH_DEBUG equ 0
-CONFIG_MSVS equ 0
-CONFIG_MULTITHREAD equ 1
-CONFIG_NORMAL_TILE_MODE equ 1
-CONFIG_OS_SUPPORT equ 1
-CONFIG_PIC equ 0
-CONFIG_RD_DEBUG equ 0
-CONFIG_RUNTIME_CPU_DETECT equ 1
-CONFIG_SHARED equ 0
-CONFIG_SIZE_LIMIT equ 1
-CONFIG_SPATIAL_RESAMPLING equ 1
-CONFIG_STATIC equ 1
-CONFIG_WEBM_IO equ 1
-DECODE_HEIGHT_LIMIT equ 16384
-DECODE_WIDTH_LIMIT equ 16384
-HAVE_AVX equ 0
-HAVE_AVX2 equ 0
+HAVE_NEON equ 1
 HAVE_DSPR2 equ 0
-HAVE_FEXCEPT equ 1
 HAVE_MIPS32 equ 0
 HAVE_MIPS64 equ 0
-HAVE_MMX equ 0
 HAVE_MSA equ 0
-HAVE_NEON equ 1
-HAVE_PTHREAD_H equ 1
+HAVE_VSX equ 0
+HAVE_AVX equ 0
+HAVE_AVX2 equ 0
+HAVE_MMX equ 0
 HAVE_SSE equ 0
 HAVE_SSE2 equ 0
 HAVE_SSE3 equ 0
 HAVE_SSE4_1 equ 0
 HAVE_SSE4_2 equ 0
 HAVE_SSSE3 equ 0
+HAVE_FEXCEPT equ 1
+HAVE_PTHREAD_H equ 1
 HAVE_UNISTD_H equ 1
-HAVE_VSX equ 0
 HAVE_WXWIDGETS equ 0
+CONFIG_AV1_DECODER equ 1
+CONFIG_AV1_ENCODER equ 0
+CONFIG_BIG_ENDIAN equ 0
+CONFIG_GCC equ 1
+CONFIG_GCOV equ 0
+CONFIG_GPROF equ 0
+CONFIG_LIBYUV equ 1
+CONFIG_MULTITHREAD equ 1
+CONFIG_OS_SUPPORT equ 1
+CONFIG_PIC equ 0
+CONFIG_RUNTIME_CPU_DETECT equ 1
+CONFIG_SHARED equ 0
+CONFIG_STATIC equ 1
+CONFIG_WEBM_IO equ 1
+CONFIG_BITSTREAM_DEBUG equ 0
+CONFIG_DEBUG equ 0
+CONFIG_MISMATCH_DEBUG equ 0
+CONFIG_ACCOUNTING equ 0
+CONFIG_ANALYZER equ 0
+CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
+CONFIG_DENOISE equ 0
+CONFIG_FILEOPTIONS equ 1
+CONFIG_FIX_GF_LENGTH equ 1
+CONFIG_INSPECTION equ 0
+CONFIG_INTERNAL_STATS equ 0
+CONFIG_LOWBITDEPTH equ 1
+CONFIG_MAX_DECODE_PROFILE equ 0
+CONFIG_NORMAL_TILE_MODE equ 1
+CONFIG_SIZE_LIMIT equ 1
+CONFIG_SPATIAL_RESAMPLING equ 1
+DECODE_HEIGHT_LIMIT equ 16384
+DECODE_WIDTH_LIMIT equ 16384
+CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
+CONFIG_COLLECT_RD_STATS equ 0
+CONFIG_DIST_8X8 equ 1
+CONFIG_ENTROPY_STATS equ 0
+CONFIG_FP_MB_STATS equ 0
+CONFIG_INTER_STATS_ONLY equ 0
+CONFIG_RD_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c
index 29912ec..71e65edd 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/urvang/work/chromium/src/third_party/libaom/source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/wtc/chromium.2/src/third_party/libaom/source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
index 97336e82..e13f9d10 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 1
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 1
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 0
-#define HAVE_AVX2 0
+#define HAVE_NEON 1
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 0
 #define HAVE_MSA 0
-#define HAVE_NEON 1
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 0
+#define HAVE_AVX2 0
+#define HAVE_MMX 0
 #define HAVE_SSE 0
 #define HAVE_SSE2 0
 #define HAVE_SSE3 0
 #define HAVE_SSE4_1 0
 #define HAVE_SSE4_2 0
 #define HAVE_SSSE3 0
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 1
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
index 2874e91..e9cdd34 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
@@ -13,62 +13,61 @@
 ARCH_PPC equ 0
 ARCH_X86 equ 0
 ARCH_X86_64 equ 0
-CONFIG_ACCOUNTING equ 0
-CONFIG_ANALYZER equ 0
-CONFIG_AV1_DECODER equ 1
-CONFIG_AV1_ENCODER equ 0
-CONFIG_BIG_ENDIAN equ 0
-CONFIG_BITSTREAM_DEBUG equ 0
-CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
-CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
-CONFIG_COLLECT_RD_STATS equ 0
-CONFIG_DEBUG equ 0
-CONFIG_DENOISE equ 0
-CONFIG_DIST_8X8 equ 1
-CONFIG_ENTROPY_STATS equ 0
-CONFIG_FILEOPTIONS equ 1
-CONFIG_FIX_GF_LENGTH equ 1
-CONFIG_FP_MB_STATS equ 0
-CONFIG_GCC equ 1
-CONFIG_GCOV equ 0
-CONFIG_GPROF equ 0
-CONFIG_INSPECTION equ 0
-CONFIG_INTERNAL_STATS equ 0
-CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
-CONFIG_LOWBITDEPTH equ 1
-CONFIG_MAX_DECODE_PROFILE equ 0
-CONFIG_MISMATCH_DEBUG equ 0
-CONFIG_MSVS equ 0
-CONFIG_MULTITHREAD equ 1
-CONFIG_NORMAL_TILE_MODE equ 1
-CONFIG_OS_SUPPORT equ 1
-CONFIG_PIC equ 0
-CONFIG_RD_DEBUG equ 0
-CONFIG_RUNTIME_CPU_DETECT equ 0
-CONFIG_SHARED equ 0
-CONFIG_SIZE_LIMIT equ 1
-CONFIG_SPATIAL_RESAMPLING equ 1
-CONFIG_STATIC equ 1
-CONFIG_WEBM_IO equ 1
-DECODE_HEIGHT_LIMIT equ 16384
-DECODE_WIDTH_LIMIT equ 16384
-HAVE_AVX equ 0
-HAVE_AVX2 equ 0
+HAVE_NEON equ 1
 HAVE_DSPR2 equ 0
-HAVE_FEXCEPT equ 1
 HAVE_MIPS32 equ 0
 HAVE_MIPS64 equ 0
-HAVE_MMX equ 0
 HAVE_MSA equ 0
-HAVE_NEON equ 1
-HAVE_PTHREAD_H equ 1
+HAVE_VSX equ 0
+HAVE_AVX equ 0
+HAVE_AVX2 equ 0
+HAVE_MMX equ 0
 HAVE_SSE equ 0
 HAVE_SSE2 equ 0
 HAVE_SSE3 equ 0
 HAVE_SSE4_1 equ 0
 HAVE_SSE4_2 equ 0
 HAVE_SSSE3 equ 0
+HAVE_FEXCEPT equ 1
+HAVE_PTHREAD_H equ 1
 HAVE_UNISTD_H equ 1
-HAVE_VSX equ 0
 HAVE_WXWIDGETS equ 0
+CONFIG_AV1_DECODER equ 1
+CONFIG_AV1_ENCODER equ 0
+CONFIG_BIG_ENDIAN equ 0
+CONFIG_GCC equ 1
+CONFIG_GCOV equ 0
+CONFIG_GPROF equ 0
+CONFIG_LIBYUV equ 1
+CONFIG_MULTITHREAD equ 1
+CONFIG_OS_SUPPORT equ 1
+CONFIG_PIC equ 0
+CONFIG_RUNTIME_CPU_DETECT equ 0
+CONFIG_SHARED equ 0
+CONFIG_STATIC equ 1
+CONFIG_WEBM_IO equ 1
+CONFIG_BITSTREAM_DEBUG equ 0
+CONFIG_DEBUG equ 0
+CONFIG_MISMATCH_DEBUG equ 0
+CONFIG_ACCOUNTING equ 0
+CONFIG_ANALYZER equ 0
+CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
+CONFIG_DENOISE equ 0
+CONFIG_FILEOPTIONS equ 1
+CONFIG_FIX_GF_LENGTH equ 1
+CONFIG_INSPECTION equ 0
+CONFIG_INTERNAL_STATS equ 0
+CONFIG_LOWBITDEPTH equ 1
+CONFIG_MAX_DECODE_PROFILE equ 0
+CONFIG_NORMAL_TILE_MODE equ 1
+CONFIG_SIZE_LIMIT equ 1
+CONFIG_SPATIAL_RESAMPLING equ 1
+DECODE_HEIGHT_LIMIT equ 16384
+DECODE_WIDTH_LIMIT equ 16384
+CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
+CONFIG_COLLECT_RD_STATS equ 0
+CONFIG_DIST_8X8 equ 1
+CONFIG_ENTROPY_STATS equ 0
+CONFIG_FP_MB_STATS equ 0
+CONFIG_INTER_STATS_ONLY equ 0
+CONFIG_RD_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c
index 29912ec..71e65edd 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/urvang/work/chromium/src/third_party/libaom/source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/wtc/chromium.2/src/third_party/libaom/source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
index 0436ebe..bc574c1 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 1
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 0
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 0
-#define HAVE_AVX2 0
+#define HAVE_NEON 1
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 0
 #define HAVE_MSA 0
-#define HAVE_NEON 1
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 0
+#define HAVE_AVX2 0
+#define HAVE_MMX 0
 #define HAVE_SSE 0
 #define HAVE_SSE2 0
 #define HAVE_SSE3 0
 #define HAVE_SSE4_1 0
 #define HAVE_SSE4_2 0
 #define HAVE_SSSE3 0
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 0
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.asm b/third_party/libaom/source/config/linux/arm/config/aom_config.asm
index ba712ca..10494db 100644
--- a/third_party/libaom/source/config/linux/arm/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm/config/aom_config.asm
@@ -13,62 +13,61 @@
 ARCH_PPC equ 0
 ARCH_X86 equ 0
 ARCH_X86_64 equ 0
-CONFIG_ACCOUNTING equ 0
-CONFIG_ANALYZER equ 0
-CONFIG_AV1_DECODER equ 1
-CONFIG_AV1_ENCODER equ 0
-CONFIG_BIG_ENDIAN equ 0
-CONFIG_BITSTREAM_DEBUG equ 0
-CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
-CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
-CONFIG_COLLECT_RD_STATS equ 0
-CONFIG_DEBUG equ 0
-CONFIG_DENOISE equ 0
-CONFIG_DIST_8X8 equ 1
-CONFIG_ENTROPY_STATS equ 0
-CONFIG_FILEOPTIONS equ 1
-CONFIG_FIX_GF_LENGTH equ 1
-CONFIG_FP_MB_STATS equ 0
-CONFIG_GCC equ 1
-CONFIG_GCOV equ 0
-CONFIG_GPROF equ 0
-CONFIG_INSPECTION equ 0
-CONFIG_INTERNAL_STATS equ 0
-CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
-CONFIG_LOWBITDEPTH equ 1
-CONFIG_MAX_DECODE_PROFILE equ 0
-CONFIG_MISMATCH_DEBUG equ 0
-CONFIG_MSVS equ 0
-CONFIG_MULTITHREAD equ 1
-CONFIG_NORMAL_TILE_MODE equ 1
-CONFIG_OS_SUPPORT equ 1
-CONFIG_PIC equ 0
-CONFIG_RD_DEBUG equ 0
-CONFIG_RUNTIME_CPU_DETECT equ 0
-CONFIG_SHARED equ 0
-CONFIG_SIZE_LIMIT equ 1
-CONFIG_SPATIAL_RESAMPLING equ 1
-CONFIG_STATIC equ 1
-CONFIG_WEBM_IO equ 1
-DECODE_HEIGHT_LIMIT equ 16384
-DECODE_WIDTH_LIMIT equ 16384
-HAVE_AVX equ 0
-HAVE_AVX2 equ 0
+HAVE_NEON equ 0
 HAVE_DSPR2 equ 0
-HAVE_FEXCEPT equ 1
 HAVE_MIPS32 equ 0
 HAVE_MIPS64 equ 0
-HAVE_MMX equ 0
 HAVE_MSA equ 0
-HAVE_NEON equ 0
-HAVE_PTHREAD_H equ 1
+HAVE_VSX equ 0
+HAVE_AVX equ 0
+HAVE_AVX2 equ 0
+HAVE_MMX equ 0
 HAVE_SSE equ 0
 HAVE_SSE2 equ 0
 HAVE_SSE3 equ 0
 HAVE_SSE4_1 equ 0
 HAVE_SSE4_2 equ 0
 HAVE_SSSE3 equ 0
+HAVE_FEXCEPT equ 1
+HAVE_PTHREAD_H equ 1
 HAVE_UNISTD_H equ 1
-HAVE_VSX equ 0
 HAVE_WXWIDGETS equ 0
+CONFIG_AV1_DECODER equ 1
+CONFIG_AV1_ENCODER equ 0
+CONFIG_BIG_ENDIAN equ 0
+CONFIG_GCC equ 1
+CONFIG_GCOV equ 0
+CONFIG_GPROF equ 0
+CONFIG_LIBYUV equ 1
+CONFIG_MULTITHREAD equ 1
+CONFIG_OS_SUPPORT equ 1
+CONFIG_PIC equ 0
+CONFIG_RUNTIME_CPU_DETECT equ 0
+CONFIG_SHARED equ 0
+CONFIG_STATIC equ 1
+CONFIG_WEBM_IO equ 1
+CONFIG_BITSTREAM_DEBUG equ 0
+CONFIG_DEBUG equ 0
+CONFIG_MISMATCH_DEBUG equ 0
+CONFIG_ACCOUNTING equ 0
+CONFIG_ANALYZER equ 0
+CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
+CONFIG_DENOISE equ 0
+CONFIG_FILEOPTIONS equ 1
+CONFIG_FIX_GF_LENGTH equ 1
+CONFIG_INSPECTION equ 0
+CONFIG_INTERNAL_STATS equ 0
+CONFIG_LOWBITDEPTH equ 1
+CONFIG_MAX_DECODE_PROFILE equ 0
+CONFIG_NORMAL_TILE_MODE equ 1
+CONFIG_SIZE_LIMIT equ 1
+CONFIG_SPATIAL_RESAMPLING equ 1
+DECODE_HEIGHT_LIMIT equ 16384
+DECODE_WIDTH_LIMIT equ 16384
+CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
+CONFIG_COLLECT_RD_STATS equ 0
+CONFIG_DIST_8X8 equ 1
+CONFIG_ENTROPY_STATS equ 0
+CONFIG_FP_MB_STATS equ 0
+CONFIG_INTER_STATS_ONLY equ 0
+CONFIG_RD_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.c b/third_party/libaom/source/config/linux/arm/config/aom_config.c
index 29912ec..15f45c9 100644
--- a/third_party/libaom/source/config/linux/arm/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/urvang/work/chromium/src/third_party/libaom/source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/wtc/chromium.2/src/third_party/libaom/source/libaom/build/cmake/toolchains/armv7-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384 -DENABLE_NEON=0";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.h b/third_party/libaom/source/config/linux/arm/config/aom_config.h
index d0c5a79..bf2001e4 100644
--- a/third_party/libaom/source/config/linux/arm/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 1
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 0
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 0
-#define HAVE_AVX2 0
+#define HAVE_NEON 0
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 0
 #define HAVE_MSA 0
-#define HAVE_NEON 0
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 0
+#define HAVE_AVX2 0
+#define HAVE_MMX 0
 #define HAVE_SSE 0
 #define HAVE_SSE2 0
 #define HAVE_SSE3 0
 #define HAVE_SSE4_1 0
 #define HAVE_SSE4_2 0
 #define HAVE_SSSE3 0
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 0
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/linux/arm64/config/aom_config.asm b/third_party/libaom/source/config/linux/arm64/config/aom_config.asm
index 2874e91..e9cdd34 100644
--- a/third_party/libaom/source/config/linux/arm64/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/arm64/config/aom_config.asm
@@ -13,62 +13,61 @@
 ARCH_PPC equ 0
 ARCH_X86 equ 0
 ARCH_X86_64 equ 0
-CONFIG_ACCOUNTING equ 0
-CONFIG_ANALYZER equ 0
-CONFIG_AV1_DECODER equ 1
-CONFIG_AV1_ENCODER equ 0
-CONFIG_BIG_ENDIAN equ 0
-CONFIG_BITSTREAM_DEBUG equ 0
-CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
-CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
-CONFIG_COLLECT_RD_STATS equ 0
-CONFIG_DEBUG equ 0
-CONFIG_DENOISE equ 0
-CONFIG_DIST_8X8 equ 1
-CONFIG_ENTROPY_STATS equ 0
-CONFIG_FILEOPTIONS equ 1
-CONFIG_FIX_GF_LENGTH equ 1
-CONFIG_FP_MB_STATS equ 0
-CONFIG_GCC equ 1
-CONFIG_GCOV equ 0
-CONFIG_GPROF equ 0
-CONFIG_INSPECTION equ 0
-CONFIG_INTERNAL_STATS equ 0
-CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
-CONFIG_LOWBITDEPTH equ 1
-CONFIG_MAX_DECODE_PROFILE equ 0
-CONFIG_MISMATCH_DEBUG equ 0
-CONFIG_MSVS equ 0
-CONFIG_MULTITHREAD equ 1
-CONFIG_NORMAL_TILE_MODE equ 1
-CONFIG_OS_SUPPORT equ 1
-CONFIG_PIC equ 0
-CONFIG_RD_DEBUG equ 0
-CONFIG_RUNTIME_CPU_DETECT equ 0
-CONFIG_SHARED equ 0
-CONFIG_SIZE_LIMIT equ 1
-CONFIG_SPATIAL_RESAMPLING equ 1
-CONFIG_STATIC equ 1
-CONFIG_WEBM_IO equ 1
-DECODE_HEIGHT_LIMIT equ 16384
-DECODE_WIDTH_LIMIT equ 16384
-HAVE_AVX equ 0
-HAVE_AVX2 equ 0
+HAVE_NEON equ 1
 HAVE_DSPR2 equ 0
-HAVE_FEXCEPT equ 1
 HAVE_MIPS32 equ 0
 HAVE_MIPS64 equ 0
-HAVE_MMX equ 0
 HAVE_MSA equ 0
-HAVE_NEON equ 1
-HAVE_PTHREAD_H equ 1
+HAVE_VSX equ 0
+HAVE_AVX equ 0
+HAVE_AVX2 equ 0
+HAVE_MMX equ 0
 HAVE_SSE equ 0
 HAVE_SSE2 equ 0
 HAVE_SSE3 equ 0
 HAVE_SSE4_1 equ 0
 HAVE_SSE4_2 equ 0
 HAVE_SSSE3 equ 0
+HAVE_FEXCEPT equ 1
+HAVE_PTHREAD_H equ 1
 HAVE_UNISTD_H equ 1
-HAVE_VSX equ 0
 HAVE_WXWIDGETS equ 0
+CONFIG_AV1_DECODER equ 1
+CONFIG_AV1_ENCODER equ 0
+CONFIG_BIG_ENDIAN equ 0
+CONFIG_GCC equ 1
+CONFIG_GCOV equ 0
+CONFIG_GPROF equ 0
+CONFIG_LIBYUV equ 1
+CONFIG_MULTITHREAD equ 1
+CONFIG_OS_SUPPORT equ 1
+CONFIG_PIC equ 0
+CONFIG_RUNTIME_CPU_DETECT equ 0
+CONFIG_SHARED equ 0
+CONFIG_STATIC equ 1
+CONFIG_WEBM_IO equ 1
+CONFIG_BITSTREAM_DEBUG equ 0
+CONFIG_DEBUG equ 0
+CONFIG_MISMATCH_DEBUG equ 0
+CONFIG_ACCOUNTING equ 0
+CONFIG_ANALYZER equ 0
+CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
+CONFIG_DENOISE equ 0
+CONFIG_FILEOPTIONS equ 1
+CONFIG_FIX_GF_LENGTH equ 1
+CONFIG_INSPECTION equ 0
+CONFIG_INTERNAL_STATS equ 0
+CONFIG_LOWBITDEPTH equ 1
+CONFIG_MAX_DECODE_PROFILE equ 0
+CONFIG_NORMAL_TILE_MODE equ 1
+CONFIG_SIZE_LIMIT equ 1
+CONFIG_SPATIAL_RESAMPLING equ 1
+DECODE_HEIGHT_LIMIT equ 16384
+DECODE_WIDTH_LIMIT equ 16384
+CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
+CONFIG_COLLECT_RD_STATS equ 0
+CONFIG_DIST_8X8 equ 1
+CONFIG_ENTROPY_STATS equ 0
+CONFIG_FP_MB_STATS equ 0
+CONFIG_INTER_STATS_ONLY equ 0
+CONFIG_RD_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm64/config/aom_config.c b/third_party/libaom/source/config/linux/arm64/config/aom_config.c
index 57319a2..69a750a 100644
--- a/third_party/libaom/source/config/linux/arm64/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/arm64/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/urvang/work/chromium/src/third_party/libaom/source/libaom/build/cmake/toolchains/arm64-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/wtc/chromium.2/src/third_party/libaom/source/libaom/build/cmake/toolchains/arm64-linux-gcc.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/arm64/config/aom_config.h b/third_party/libaom/source/config/linux/arm64/config/aom_config.h
index 0436ebe..bc574c1 100644
--- a/third_party/libaom/source/config/linux/arm64/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/arm64/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 1
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 0
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 0
-#define HAVE_AVX2 0
+#define HAVE_NEON 1
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 0
 #define HAVE_MSA 0
-#define HAVE_NEON 1
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 0
+#define HAVE_AVX2 0
+#define HAVE_MMX 0
 #define HAVE_SSE 0
 #define HAVE_SSE2 0
 #define HAVE_SSE3 0
 #define HAVE_SSE4_1 0
 #define HAVE_SSE4_2 0
 #define HAVE_SSSE3 0
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 0
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.asm b/third_party/libaom/source/config/linux/generic/config/aom_config.asm
index b0995db..6df03e5 100644
--- a/third_party/libaom/source/config/linux/generic/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/generic/config/aom_config.asm
@@ -13,62 +13,61 @@
 ARCH_PPC equ 0
 ARCH_X86 equ 0
 ARCH_X86_64 equ 0
-CONFIG_ACCOUNTING equ 0
-CONFIG_ANALYZER equ 0
-CONFIG_AV1_DECODER equ 1
-CONFIG_AV1_ENCODER equ 0
-CONFIG_BIG_ENDIAN equ 0
-CONFIG_BITSTREAM_DEBUG equ 0
-CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
-CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
-CONFIG_COLLECT_RD_STATS equ 0
-CONFIG_DEBUG equ 0
-CONFIG_DENOISE equ 0
-CONFIG_DIST_8X8 equ 1
-CONFIG_ENTROPY_STATS equ 0
-CONFIG_FILEOPTIONS equ 1
-CONFIG_FIX_GF_LENGTH equ 1
-CONFIG_FP_MB_STATS equ 0
-CONFIG_GCC equ 1
-CONFIG_GCOV equ 0
-CONFIG_GPROF equ 0
-CONFIG_INSPECTION equ 0
-CONFIG_INTERNAL_STATS equ 0
-CONFIG_INTER_STATS_ONLY equ 0
-CONFIG_LIBYUV equ 1
-CONFIG_LOWBITDEPTH equ 1
-CONFIG_MAX_DECODE_PROFILE equ 0
-CONFIG_MISMATCH_DEBUG equ 0
-CONFIG_MSVS equ 0
-CONFIG_MULTITHREAD equ 1
-CONFIG_NORMAL_TILE_MODE equ 1
-CONFIG_OS_SUPPORT equ 1
-CONFIG_PIC equ 0
-CONFIG_RD_DEBUG equ 0
-CONFIG_RUNTIME_CPU_DETECT equ 1
-CONFIG_SHARED equ 0
-CONFIG_SIZE_LIMIT equ 1
-CONFIG_SPATIAL_RESAMPLING equ 1
-CONFIG_STATIC equ 1
-CONFIG_WEBM_IO equ 1
-DECODE_HEIGHT_LIMIT equ 16384
-DECODE_WIDTH_LIMIT equ 16384
-HAVE_AVX equ 0
-HAVE_AVX2 equ 0
+HAVE_NEON equ 0
 HAVE_DSPR2 equ 0
-HAVE_FEXCEPT equ 1
 HAVE_MIPS32 equ 0
 HAVE_MIPS64 equ 0
-HAVE_MMX equ 0
 HAVE_MSA equ 0
-HAVE_NEON equ 0
-HAVE_PTHREAD_H equ 1
+HAVE_VSX equ 0
+HAVE_AVX equ 0
+HAVE_AVX2 equ 0
+HAVE_MMX equ 0
 HAVE_SSE equ 0
 HAVE_SSE2 equ 0
 HAVE_SSE3 equ 0
 HAVE_SSE4_1 equ 0
 HAVE_SSE4_2 equ 0
 HAVE_SSSE3 equ 0
+HAVE_FEXCEPT equ 1
+HAVE_PTHREAD_H equ 1
 HAVE_UNISTD_H equ 1
-HAVE_VSX equ 0
 HAVE_WXWIDGETS equ 0
+CONFIG_AV1_DECODER equ 1
+CONFIG_AV1_ENCODER equ 0
+CONFIG_BIG_ENDIAN equ 0
+CONFIG_GCC equ 1
+CONFIG_GCOV equ 0
+CONFIG_GPROF equ 0
+CONFIG_LIBYUV equ 1
+CONFIG_MULTITHREAD equ 1
+CONFIG_OS_SUPPORT equ 1
+CONFIG_PIC equ 0
+CONFIG_RUNTIME_CPU_DETECT equ 1
+CONFIG_SHARED equ 0
+CONFIG_STATIC equ 1
+CONFIG_WEBM_IO equ 1
+CONFIG_BITSTREAM_DEBUG equ 0
+CONFIG_DEBUG equ 0
+CONFIG_MISMATCH_DEBUG equ 0
+CONFIG_ACCOUNTING equ 0
+CONFIG_ANALYZER equ 0
+CONFIG_COEFFICIENT_RANGE_CHECKING equ 0
+CONFIG_DENOISE equ 0
+CONFIG_FILEOPTIONS equ 1
+CONFIG_FIX_GF_LENGTH equ 1
+CONFIG_INSPECTION equ 0
+CONFIG_INTERNAL_STATS equ 0
+CONFIG_LOWBITDEPTH equ 1
+CONFIG_MAX_DECODE_PROFILE equ 0
+CONFIG_NORMAL_TILE_MODE equ 1
+CONFIG_SIZE_LIMIT equ 1
+CONFIG_SPATIAL_RESAMPLING equ 1
+DECODE_HEIGHT_LIMIT equ 16384
+DECODE_WIDTH_LIMIT equ 16384
+CONFIG_COLLECT_INTER_MODE_RD_STATS equ 1
+CONFIG_COLLECT_RD_STATS equ 0
+CONFIG_DIST_8X8 equ 1
+CONFIG_ENTROPY_STATS equ 0
+CONFIG_FP_MB_STATS equ 0
+CONFIG_INTER_STATS_ONLY equ 0
+CONFIG_RD_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.c b/third_party/libaom/source/config/linux/generic/config/aom_config.c
index bba2768e..66acfe1 100644
--- a/third_party/libaom/source/config/linux/generic/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/generic/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DAOM_TARGET_CPU=generic -DAOM_TARGET_CPU=generic -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DAOM_TARGET_CPU=generic -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.h b/third_party/libaom/source/config/linux/generic/config/aom_config.h
index b040729..04dc556 100644
--- a/third_party/libaom/source/config/linux/generic/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/generic/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 1
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 0
-#define HAVE_AVX2 0
+#define HAVE_NEON 0
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 0
 #define HAVE_MSA 0
-#define HAVE_NEON 0
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 0
+#define HAVE_AVX2 0
+#define HAVE_MMX 0
 #define HAVE_SSE 0
 #define HAVE_SSE2 0
 #define HAVE_SSE3 0
 #define HAVE_SSE4_1 0
 #define HAVE_SSE4_2 0
 #define HAVE_SSSE3 0
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 1
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.asm b/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
index c3ee8ab..5d7d22d 100644
--- a/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
@@ -3,62 +3,61 @@
 %define ARCH_PPC 0
 %define ARCH_X86 1
 %define ARCH_X86_64 0
-%define CONFIG_ACCOUNTING 0
-%define CONFIG_ANALYZER 0
-%define CONFIG_AV1_DECODER 1
-%define CONFIG_AV1_ENCODER 0
-%define CONFIG_BIG_ENDIAN 0
-%define CONFIG_BITSTREAM_DEBUG 0
-%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-%define CONFIG_COLLECT_RD_STATS 0
-%define CONFIG_DEBUG 0
-%define CONFIG_DENOISE 0
-%define CONFIG_DIST_8X8 1
-%define CONFIG_ENTROPY_STATS 0
-%define CONFIG_FILEOPTIONS 1
-%define CONFIG_FIX_GF_LENGTH 1
-%define CONFIG_FP_MB_STATS 0
-%define CONFIG_GCC 1
-%define CONFIG_GCOV 0
-%define CONFIG_GPROF 0
-%define CONFIG_INSPECTION 0
-%define CONFIG_INTERNAL_STATS 0
-%define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
-%define CONFIG_LOWBITDEPTH 1
-%define CONFIG_MAX_DECODE_PROFILE 0
-%define CONFIG_MISMATCH_DEBUG 0
-%define CONFIG_MSVS 0
-%define CONFIG_MULTITHREAD 1
-%define CONFIG_NORMAL_TILE_MODE 1
-%define CONFIG_OS_SUPPORT 1
-%define CONFIG_PIC 0
-%define CONFIG_RD_DEBUG 0
-%define CONFIG_RUNTIME_CPU_DETECT 1
-%define CONFIG_SHARED 0
-%define CONFIG_SIZE_LIMIT 1
-%define CONFIG_SPATIAL_RESAMPLING 1
-%define CONFIG_STATIC 1
-%define CONFIG_WEBM_IO 1
-%define DECODE_HEIGHT_LIMIT 16384
-%define DECODE_WIDTH_LIMIT 16384
-%define HAVE_AVX 1
-%define HAVE_AVX2 1
+%define HAVE_NEON 0
 %define HAVE_DSPR2 0
-%define HAVE_FEXCEPT 1
 %define HAVE_MIPS32 0
 %define HAVE_MIPS64 0
-%define HAVE_MMX 1
 %define HAVE_MSA 0
-%define HAVE_NEON 0
-%define HAVE_PTHREAD_H 1
+%define HAVE_VSX 0
+%define HAVE_AVX 1
+%define HAVE_AVX2 1
+%define HAVE_MMX 1
 %define HAVE_SSE 1
 %define HAVE_SSE2 1
 %define HAVE_SSE3 1
 %define HAVE_SSE4_1 1
 %define HAVE_SSE4_2 1
 %define HAVE_SSSE3 1
+%define HAVE_FEXCEPT 1
+%define HAVE_PTHREAD_H 1
 %define HAVE_UNISTD_H 1
-%define HAVE_VSX 0
 %define HAVE_WXWIDGETS 0
+%define CONFIG_AV1_DECODER 1
+%define CONFIG_AV1_ENCODER 0
+%define CONFIG_BIG_ENDIAN 0
+%define CONFIG_GCC 1
+%define CONFIG_GCOV 0
+%define CONFIG_GPROF 0
+%define CONFIG_LIBYUV 1
+%define CONFIG_MULTITHREAD 1
+%define CONFIG_OS_SUPPORT 1
+%define CONFIG_PIC 0
+%define CONFIG_RUNTIME_CPU_DETECT 1
+%define CONFIG_SHARED 0
+%define CONFIG_STATIC 1
+%define CONFIG_WEBM_IO 1
+%define CONFIG_BITSTREAM_DEBUG 0
+%define CONFIG_DEBUG 0
+%define CONFIG_MISMATCH_DEBUG 0
+%define CONFIG_ACCOUNTING 0
+%define CONFIG_ANALYZER 0
+%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+%define CONFIG_DENOISE 0
+%define CONFIG_FILEOPTIONS 1
+%define CONFIG_FIX_GF_LENGTH 1
+%define CONFIG_INSPECTION 0
+%define CONFIG_INTERNAL_STATS 0
+%define CONFIG_LOWBITDEPTH 1
+%define CONFIG_MAX_DECODE_PROFILE 0
+%define CONFIG_NORMAL_TILE_MODE 1
+%define CONFIG_SIZE_LIMIT 1
+%define CONFIG_SPATIAL_RESAMPLING 1
+%define DECODE_HEIGHT_LIMIT 16384
+%define DECODE_WIDTH_LIMIT 16384
+%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+%define CONFIG_COLLECT_RD_STATS 0
+%define CONFIG_DIST_8X8 1
+%define CONFIG_ENTROPY_STATS 0
+%define CONFIG_FP_MB_STATS 0
+%define CONFIG_INTER_STATS_ONLY 0
+%define CONFIG_RD_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.c b/third_party/libaom/source/config/linux/ia32/config/aom_config.c
index 9028a6b..ab01a869 100644
--- a/third_party/libaom/source/config/linux/ia32/config/aom_config.c
+++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/urvang/work/chromium/src/third_party/libaom/source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/wtc/chromium.2/src/third_party/libaom/source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.h b/third_party/libaom/source/config/linux/ia32/config/aom_config.h
index 1b0d11a1..c06c694 100644
--- a/third_party/libaom/source/config/linux/ia32/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 1
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 1
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 1
-#define HAVE_AVX2 1
+#define HAVE_NEON 0
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 1
 #define HAVE_MSA 0
-#define HAVE_NEON 0
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 1
+#define HAVE_AVX2 1
+#define HAVE_MMX 1
 #define HAVE_SSE 1
 #define HAVE_SSE2 1
 #define HAVE_SSE3 1
 #define HAVE_SSE4_1 1
 #define HAVE_SSE4_2 1
 #define HAVE_SSSE3 1
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 1
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.asm b/third_party/libaom/source/config/linux/x64/config/aom_config.asm
index 1e8816c..2ce1e7e 100644
--- a/third_party/libaom/source/config/linux/x64/config/aom_config.asm
+++ b/third_party/libaom/source/config/linux/x64/config/aom_config.asm
@@ -3,62 +3,61 @@
 %define ARCH_PPC 0
 %define ARCH_X86 0
 %define ARCH_X86_64 1
-%define CONFIG_ACCOUNTING 0
-%define CONFIG_ANALYZER 0
-%define CONFIG_AV1_DECODER 1
-%define CONFIG_AV1_ENCODER 0
-%define CONFIG_BIG_ENDIAN 0
-%define CONFIG_BITSTREAM_DEBUG 0
-%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-%define CONFIG_COLLECT_RD_STATS 0
-%define CONFIG_DEBUG 0
-%define CONFIG_DENOISE 0
-%define CONFIG_DIST_8X8 1
-%define CONFIG_ENTROPY_STATS 0
-%define CONFIG_FILEOPTIONS 1
-%define CONFIG_FIX_GF_LENGTH 1
-%define CONFIG_FP_MB_STATS 0
-%define CONFIG_GCC 1
-%define CONFIG_GCOV 0
-%define CONFIG_GPROF 0
-%define CONFIG_INSPECTION 0
-%define CONFIG_INTERNAL_STATS 0
-%define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
-%define CONFIG_LOWBITDEPTH 1
-%define CONFIG_MAX_DECODE_PROFILE 0
-%define CONFIG_MISMATCH_DEBUG 0
-%define CONFIG_MSVS 0
-%define CONFIG_MULTITHREAD 1
-%define CONFIG_NORMAL_TILE_MODE 1
-%define CONFIG_OS_SUPPORT 1
-%define CONFIG_PIC 0
-%define CONFIG_RD_DEBUG 0
-%define CONFIG_RUNTIME_CPU_DETECT 1
-%define CONFIG_SHARED 0
-%define CONFIG_SIZE_LIMIT 1
-%define CONFIG_SPATIAL_RESAMPLING 1
-%define CONFIG_STATIC 1
-%define CONFIG_WEBM_IO 1
-%define DECODE_HEIGHT_LIMIT 16384
-%define DECODE_WIDTH_LIMIT 16384
-%define HAVE_AVX 1
-%define HAVE_AVX2 1
+%define HAVE_NEON 0
 %define HAVE_DSPR2 0
-%define HAVE_FEXCEPT 1
 %define HAVE_MIPS32 0
 %define HAVE_MIPS64 0
-%define HAVE_MMX 1
 %define HAVE_MSA 0
-%define HAVE_NEON 0
-%define HAVE_PTHREAD_H 1
+%define HAVE_VSX 0
+%define HAVE_AVX 1
+%define HAVE_AVX2 1
+%define HAVE_MMX 1
 %define HAVE_SSE 1
 %define HAVE_SSE2 1
 %define HAVE_SSE3 1
 %define HAVE_SSE4_1 1
 %define HAVE_SSE4_2 1
 %define HAVE_SSSE3 1
+%define HAVE_FEXCEPT 1
+%define HAVE_PTHREAD_H 1
 %define HAVE_UNISTD_H 1
-%define HAVE_VSX 0
 %define HAVE_WXWIDGETS 0
+%define CONFIG_AV1_DECODER 1
+%define CONFIG_AV1_ENCODER 0
+%define CONFIG_BIG_ENDIAN 0
+%define CONFIG_GCC 1
+%define CONFIG_GCOV 0
+%define CONFIG_GPROF 0
+%define CONFIG_LIBYUV 1
+%define CONFIG_MULTITHREAD 1
+%define CONFIG_OS_SUPPORT 1
+%define CONFIG_PIC 0
+%define CONFIG_RUNTIME_CPU_DETECT 1
+%define CONFIG_SHARED 0
+%define CONFIG_STATIC 1
+%define CONFIG_WEBM_IO 1
+%define CONFIG_BITSTREAM_DEBUG 0
+%define CONFIG_DEBUG 0
+%define CONFIG_MISMATCH_DEBUG 0
+%define CONFIG_ACCOUNTING 0
+%define CONFIG_ANALYZER 0
+%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+%define CONFIG_DENOISE 0
+%define CONFIG_FILEOPTIONS 1
+%define CONFIG_FIX_GF_LENGTH 1
+%define CONFIG_INSPECTION 0
+%define CONFIG_INTERNAL_STATS 0
+%define CONFIG_LOWBITDEPTH 1
+%define CONFIG_MAX_DECODE_PROFILE 0
+%define CONFIG_NORMAL_TILE_MODE 1
+%define CONFIG_SIZE_LIMIT 1
+%define CONFIG_SPATIAL_RESAMPLING 1
+%define DECODE_HEIGHT_LIMIT 16384
+%define DECODE_WIDTH_LIMIT 16384
+%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+%define CONFIG_COLLECT_RD_STATS 0
+%define CONFIG_DIST_8X8 1
+%define CONFIG_ENTROPY_STATS 0
+%define CONFIG_FP_MB_STATS 0
+%define CONFIG_INTER_STATS_ONLY 0
+%define CONFIG_RD_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.h b/third_party/libaom/source/config/linux/x64/config/aom_config.h
index ece0782a..885f89f 100644
--- a/third_party/libaom/source/config/linux/x64/config/aom_config.h
+++ b/third_party/libaom/source/config/linux/x64/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE inline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 1
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 1
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 0
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 1
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 1
-#define HAVE_AVX2 1
+#define HAVE_NEON 0
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 1
 #define HAVE_MSA 0
-#define HAVE_NEON 0
-#define HAVE_PTHREAD_H 1
+#define HAVE_VSX 0
+#define HAVE_AVX 1
+#define HAVE_AVX2 1
+#define HAVE_MMX 1
 #define HAVE_SSE 1
 #define HAVE_SSE2 1
 #define HAVE_SSE3 1
 #define HAVE_SSE4_1 1
 #define HAVE_SSE4_2 1
 #define HAVE_SSSE3 1
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 1
 #define HAVE_UNISTD_H 1
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 1
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 1
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.asm b/third_party/libaom/source/config/win/ia32/config/aom_config.asm
index b2a1a8a..40b52ef 100644
--- a/third_party/libaom/source/config/win/ia32/config/aom_config.asm
+++ b/third_party/libaom/source/config/win/ia32/config/aom_config.asm
@@ -3,62 +3,61 @@
 %define ARCH_PPC 0
 %define ARCH_X86 1
 %define ARCH_X86_64 0
-%define CONFIG_ACCOUNTING 0
-%define CONFIG_ANALYZER 0
-%define CONFIG_AV1_DECODER 1
-%define CONFIG_AV1_ENCODER 0
-%define CONFIG_BIG_ENDIAN 0
-%define CONFIG_BITSTREAM_DEBUG 0
-%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-%define CONFIG_COLLECT_RD_STATS 0
-%define CONFIG_DEBUG 0
-%define CONFIG_DENOISE 0
-%define CONFIG_DIST_8X8 1
-%define CONFIG_ENTROPY_STATS 0
-%define CONFIG_FILEOPTIONS 1
-%define CONFIG_FIX_GF_LENGTH 1
-%define CONFIG_FP_MB_STATS 0
-%define CONFIG_GCC 0
-%define CONFIG_GCOV 0
-%define CONFIG_GPROF 0
-%define CONFIG_INSPECTION 0
-%define CONFIG_INTERNAL_STATS 0
-%define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
-%define CONFIG_LOWBITDEPTH 1
-%define CONFIG_MAX_DECODE_PROFILE 0
-%define CONFIG_MISMATCH_DEBUG 0
-%define CONFIG_MSVS 1
-%define CONFIG_MULTITHREAD 1
-%define CONFIG_NORMAL_TILE_MODE 1
-%define CONFIG_OS_SUPPORT 1
-%define CONFIG_PIC 0
-%define CONFIG_RD_DEBUG 0
-%define CONFIG_RUNTIME_CPU_DETECT 1
-%define CONFIG_SHARED 0
-%define CONFIG_SIZE_LIMIT 1
-%define CONFIG_SPATIAL_RESAMPLING 1
-%define CONFIG_STATIC 1
-%define CONFIG_WEBM_IO 1
-%define DECODE_HEIGHT_LIMIT 16384
-%define DECODE_WIDTH_LIMIT 16384
-%define HAVE_AVX 1
-%define HAVE_AVX2 1
+%define HAVE_NEON 0
 %define HAVE_DSPR2 0
-%define HAVE_FEXCEPT 1
 %define HAVE_MIPS32 0
 %define HAVE_MIPS64 0
-%define HAVE_MMX 1
 %define HAVE_MSA 0
-%define HAVE_NEON 0
-%define HAVE_PTHREAD_H 0
+%define HAVE_VSX 0
+%define HAVE_AVX 1
+%define HAVE_AVX2 1
+%define HAVE_MMX 1
 %define HAVE_SSE 1
 %define HAVE_SSE2 1
 %define HAVE_SSE3 1
 %define HAVE_SSE4_1 1
 %define HAVE_SSE4_2 1
 %define HAVE_SSSE3 1
+%define HAVE_FEXCEPT 1
+%define HAVE_PTHREAD_H 0
 %define HAVE_UNISTD_H 0
-%define HAVE_VSX 0
 %define HAVE_WXWIDGETS 0
+%define CONFIG_AV1_DECODER 1
+%define CONFIG_AV1_ENCODER 0
+%define CONFIG_BIG_ENDIAN 0
+%define CONFIG_GCC 0
+%define CONFIG_GCOV 0
+%define CONFIG_GPROF 0
+%define CONFIG_LIBYUV 1
+%define CONFIG_MULTITHREAD 1
+%define CONFIG_OS_SUPPORT 1
+%define CONFIG_PIC 0
+%define CONFIG_RUNTIME_CPU_DETECT 1
+%define CONFIG_SHARED 0
+%define CONFIG_STATIC 1
+%define CONFIG_WEBM_IO 1
+%define CONFIG_BITSTREAM_DEBUG 0
+%define CONFIG_DEBUG 0
+%define CONFIG_MISMATCH_DEBUG 0
+%define CONFIG_ACCOUNTING 0
+%define CONFIG_ANALYZER 0
+%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+%define CONFIG_DENOISE 0
+%define CONFIG_FILEOPTIONS 1
+%define CONFIG_FIX_GF_LENGTH 1
+%define CONFIG_INSPECTION 0
+%define CONFIG_INTERNAL_STATS 0
+%define CONFIG_LOWBITDEPTH 1
+%define CONFIG_MAX_DECODE_PROFILE 0
+%define CONFIG_NORMAL_TILE_MODE 1
+%define CONFIG_SIZE_LIMIT 1
+%define CONFIG_SPATIAL_RESAMPLING 1
+%define DECODE_HEIGHT_LIMIT 16384
+%define DECODE_WIDTH_LIMIT 16384
+%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+%define CONFIG_COLLECT_RD_STATS 0
+%define CONFIG_DIST_8X8 1
+%define CONFIG_ENTROPY_STATS 0
+%define CONFIG_FP_MB_STATS 0
+%define CONFIG_INTER_STATS_ONLY 0
+%define CONFIG_RD_DEBUG 0
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.c b/third_party/libaom/source/config/win/ia32/config/aom_config.c
index 9028a6b..ab01a869 100644
--- a/third_party/libaom/source/config/win/ia32/config/aom_config.c
+++ b/third_party/libaom/source/config/win/ia32/config/aom_config.c
@@ -9,5 +9,5 @@
  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  */
 #include "aom/aom_codec.h"
-static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/urvang/work/chromium/src/third_party/libaom/source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
+static const char* const cfg = "-G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=\"/usr/local/google/home/wtc/chromium.2/src/third_party/libaom/source/libaom/build/cmake/toolchains/x86-linux.cmake\" -DCONFIG_AV1_ENCODER=0 -DCONFIG_LOWBITDEPTH=1 -DCONFIG_MAX_DECODE_PROFILE=0 -DCONFIG_NORMAL_TILE_MODE=1 -DCONFIG_SIZE_LIMIT=1 -DDECODE_HEIGHT_LIMIT=16384 -DDECODE_WIDTH_LIMIT=16384";
 const char *aom_codec_build_config(void) {return cfg;}
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.h b/third_party/libaom/source/config/win/ia32/config/aom_config.h
index e2314ba..a396468 100644
--- a/third_party/libaom/source/config/win/ia32/config/aom_config.h
+++ b/third_party/libaom/source/config/win/ia32/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE __inline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 1
 #define ARCH_X86_64 0
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 0
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 1
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 1
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 1
-#define HAVE_AVX2 1
+#define HAVE_NEON 0
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 1
 #define HAVE_MSA 0
-#define HAVE_NEON 0
-#define HAVE_PTHREAD_H 0
+#define HAVE_VSX 0
+#define HAVE_AVX 1
+#define HAVE_AVX2 1
+#define HAVE_MMX 1
 #define HAVE_SSE 1
 #define HAVE_SSE2 1
 #define HAVE_SSE3 1
 #define HAVE_SSE4_1 1
 #define HAVE_SSE4_2 1
 #define HAVE_SSSE3 1
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 0
 #define HAVE_UNISTD_H 0
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE __inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 0
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 1
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.asm b/third_party/libaom/source/config/win/x64/config/aom_config.asm
index 5a9cfd8..ca2d5631 100644
--- a/third_party/libaom/source/config/win/x64/config/aom_config.asm
+++ b/third_party/libaom/source/config/win/x64/config/aom_config.asm
@@ -3,62 +3,61 @@
 %define ARCH_PPC 0
 %define ARCH_X86 0
 %define ARCH_X86_64 1
-%define CONFIG_ACCOUNTING 0
-%define CONFIG_ANALYZER 0
-%define CONFIG_AV1_DECODER 1
-%define CONFIG_AV1_ENCODER 0
-%define CONFIG_BIG_ENDIAN 0
-%define CONFIG_BITSTREAM_DEBUG 0
-%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-%define CONFIG_COLLECT_RD_STATS 0
-%define CONFIG_DEBUG 0
-%define CONFIG_DENOISE 0
-%define CONFIG_DIST_8X8 1
-%define CONFIG_ENTROPY_STATS 0
-%define CONFIG_FILEOPTIONS 1
-%define CONFIG_FIX_GF_LENGTH 1
-%define CONFIG_FP_MB_STATS 0
-%define CONFIG_GCC 0
-%define CONFIG_GCOV 0
-%define CONFIG_GPROF 0
-%define CONFIG_INSPECTION 0
-%define CONFIG_INTERNAL_STATS 0
-%define CONFIG_INTER_STATS_ONLY 0
-%define CONFIG_LIBYUV 1
-%define CONFIG_LOWBITDEPTH 1
-%define CONFIG_MAX_DECODE_PROFILE 0
-%define CONFIG_MISMATCH_DEBUG 0
-%define CONFIG_MSVS 1
-%define CONFIG_MULTITHREAD 1
-%define CONFIG_NORMAL_TILE_MODE 1
-%define CONFIG_OS_SUPPORT 1
-%define CONFIG_PIC 0
-%define CONFIG_RD_DEBUG 0
-%define CONFIG_RUNTIME_CPU_DETECT 1
-%define CONFIG_SHARED 0
-%define CONFIG_SIZE_LIMIT 1
-%define CONFIG_SPATIAL_RESAMPLING 1
-%define CONFIG_STATIC 1
-%define CONFIG_WEBM_IO 1
-%define DECODE_HEIGHT_LIMIT 16384
-%define DECODE_WIDTH_LIMIT 16384
-%define HAVE_AVX 1
-%define HAVE_AVX2 1
+%define HAVE_NEON 0
 %define HAVE_DSPR2 0
-%define HAVE_FEXCEPT 1
 %define HAVE_MIPS32 0
 %define HAVE_MIPS64 0
-%define HAVE_MMX 1
 %define HAVE_MSA 0
-%define HAVE_NEON 0
-%define HAVE_PTHREAD_H 0
+%define HAVE_VSX 0
+%define HAVE_AVX 1
+%define HAVE_AVX2 1
+%define HAVE_MMX 1
 %define HAVE_SSE 1
 %define HAVE_SSE2 1
 %define HAVE_SSE3 1
 %define HAVE_SSE4_1 1
 %define HAVE_SSE4_2 1
 %define HAVE_SSSE3 1
+%define HAVE_FEXCEPT 1
+%define HAVE_PTHREAD_H 0
 %define HAVE_UNISTD_H 0
-%define HAVE_VSX 0
 %define HAVE_WXWIDGETS 0
+%define CONFIG_AV1_DECODER 1
+%define CONFIG_AV1_ENCODER 0
+%define CONFIG_BIG_ENDIAN 0
+%define CONFIG_GCC 0
+%define CONFIG_GCOV 0
+%define CONFIG_GPROF 0
+%define CONFIG_LIBYUV 1
+%define CONFIG_MULTITHREAD 1
+%define CONFIG_OS_SUPPORT 1
+%define CONFIG_PIC 0
+%define CONFIG_RUNTIME_CPU_DETECT 1
+%define CONFIG_SHARED 0
+%define CONFIG_STATIC 1
+%define CONFIG_WEBM_IO 1
+%define CONFIG_BITSTREAM_DEBUG 0
+%define CONFIG_DEBUG 0
+%define CONFIG_MISMATCH_DEBUG 0
+%define CONFIG_ACCOUNTING 0
+%define CONFIG_ANALYZER 0
+%define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+%define CONFIG_DENOISE 0
+%define CONFIG_FILEOPTIONS 1
+%define CONFIG_FIX_GF_LENGTH 1
+%define CONFIG_INSPECTION 0
+%define CONFIG_INTERNAL_STATS 0
+%define CONFIG_LOWBITDEPTH 1
+%define CONFIG_MAX_DECODE_PROFILE 0
+%define CONFIG_NORMAL_TILE_MODE 1
+%define CONFIG_SIZE_LIMIT 1
+%define CONFIG_SPATIAL_RESAMPLING 1
+%define DECODE_HEIGHT_LIMIT 16384
+%define DECODE_WIDTH_LIMIT 16384
+%define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+%define CONFIG_COLLECT_RD_STATS 0
+%define CONFIG_DIST_8X8 1
+%define CONFIG_ENTROPY_STATS 0
+%define CONFIG_FP_MB_STATS 0
+%define CONFIG_INTER_STATS_ONLY 0
+%define CONFIG_RD_DEBUG 0
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.h b/third_party/libaom/source/config/win/x64/config/aom_config.h
index c3ad5e5..4ad2496 100644
--- a/third_party/libaom/source/config/win/x64/config/aom_config.h
+++ b/third_party/libaom/source/config/win/x64/config/aom_config.h
@@ -10,69 +10,68 @@
  */
 #ifndef AOM_CONFIG_H_
 #define AOM_CONFIG_H_
+#define INLINE __inline
 #define ARCH_ARM 0
 #define ARCH_MIPS 0
 #define ARCH_PPC 0
 #define ARCH_X86 0
 #define ARCH_X86_64 1
-#define CONFIG_ACCOUNTING 0
-#define CONFIG_ANALYZER 0
-#define CONFIG_AV1_DECODER 1
-#define CONFIG_AV1_ENCODER 0
-#define CONFIG_BIG_ENDIAN 0
-#define CONFIG_BITSTREAM_DEBUG 0
-#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
-#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
-#define CONFIG_COLLECT_RD_STATS 0
-#define CONFIG_DEBUG 0
-#define CONFIG_DENOISE 0
-#define CONFIG_DIST_8X8 1
-#define CONFIG_ENTROPY_STATS 0
-#define CONFIG_FILEOPTIONS 1
-#define CONFIG_FIX_GF_LENGTH 1
-#define CONFIG_FP_MB_STATS 0
-#define CONFIG_GCC 0
-#define CONFIG_GCOV 0
-#define CONFIG_GPROF 0
-#define CONFIG_INSPECTION 0
-#define CONFIG_INTERNAL_STATS 0
-#define CONFIG_INTER_STATS_ONLY 0
-#define CONFIG_LIBYUV 1
-#define CONFIG_LOWBITDEPTH 1
-#define CONFIG_MAX_DECODE_PROFILE 0
-#define CONFIG_MISMATCH_DEBUG 0
-#define CONFIG_MSVS 1
-#define CONFIG_MULTITHREAD 1
-#define CONFIG_NORMAL_TILE_MODE 1
-#define CONFIG_OS_SUPPORT 1
-#define CONFIG_PIC 0
-#define CONFIG_RD_DEBUG 0
-#define CONFIG_RUNTIME_CPU_DETECT 1
-#define CONFIG_SHARED 0
-#define CONFIG_SIZE_LIMIT 1
-#define CONFIG_SPATIAL_RESAMPLING 1
-#define CONFIG_STATIC 1
-#define CONFIG_WEBM_IO 1
-#define DECODE_HEIGHT_LIMIT 16384
-#define DECODE_WIDTH_LIMIT 16384
-#define HAVE_AVX 1
-#define HAVE_AVX2 1
+#define HAVE_NEON 0
 #define HAVE_DSPR2 0
-#define HAVE_FEXCEPT 1
 #define HAVE_MIPS32 0
 #define HAVE_MIPS64 0
-#define HAVE_MMX 1
 #define HAVE_MSA 0
-#define HAVE_NEON 0
-#define HAVE_PTHREAD_H 0
+#define HAVE_VSX 0
+#define HAVE_AVX 1
+#define HAVE_AVX2 1
+#define HAVE_MMX 1
 #define HAVE_SSE 1
 #define HAVE_SSE2 1
 #define HAVE_SSE3 1
 #define HAVE_SSE4_1 1
 #define HAVE_SSE4_2 1
 #define HAVE_SSSE3 1
+#define HAVE_FEXCEPT 1
+#define HAVE_PTHREAD_H 0
 #define HAVE_UNISTD_H 0
-#define HAVE_VSX 0
 #define HAVE_WXWIDGETS 0
-#define INLINE __inline
+#define CONFIG_AV1_DECODER 1
+#define CONFIG_AV1_ENCODER 0
+#define CONFIG_BIG_ENDIAN 0
+#define CONFIG_GCC 0
+#define CONFIG_GCOV 0
+#define CONFIG_GPROF 0
+#define CONFIG_LIBYUV 1
+#define CONFIG_MULTITHREAD 1
+#define CONFIG_OS_SUPPORT 1
+#define CONFIG_PIC 0
+#define CONFIG_RUNTIME_CPU_DETECT 1
+#define CONFIG_SHARED 0
+#define CONFIG_STATIC 1
+#define CONFIG_WEBM_IO 1
+#define CONFIG_BITSTREAM_DEBUG 0
+#define CONFIG_DEBUG 0
+#define CONFIG_MISMATCH_DEBUG 0
+#define CONFIG_ACCOUNTING 0
+#define CONFIG_ANALYZER 0
+#define CONFIG_COEFFICIENT_RANGE_CHECKING 0
+#define CONFIG_DENOISE 0
+#define CONFIG_FILEOPTIONS 1
+#define CONFIG_FIX_GF_LENGTH 1
+#define CONFIG_INSPECTION 0
+#define CONFIG_INTERNAL_STATS 0
+#define CONFIG_LOWBITDEPTH 1
+#define CONFIG_MAX_DECODE_PROFILE 0
+#define CONFIG_NORMAL_TILE_MODE 1
+#define CONFIG_SIZE_LIMIT 1
+#define CONFIG_SPATIAL_RESAMPLING 1
+#define DECODE_HEIGHT_LIMIT 16384
+#define DECODE_WIDTH_LIMIT 16384
+#define CONFIG_COLLECT_INTER_MODE_RD_STATS 1
+#define CONFIG_COLLECT_RD_STATS 0
+#define CONFIG_DIST_8X8 1
+#define CONFIG_ENTROPY_STATS 0
+#define CONFIG_FP_MB_STATS 0
+#define CONFIG_INTER_STATS_ONLY 0
+#define CONFIG_RD_DEBUG 0
 #endif /* AOM_CONFIG_H_ */
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index 902e287..69b49ba 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -283,6 +283,7 @@
 
       deps += [ ":zlib_inflate_chunk_simd" ]
       sources -= [ "inflate.c" ]
+      sources += [ "contrib/optimizations/slide_hash_neon.h" ]
     }
   }
 
diff --git a/third_party/zlib/contrib/optimizations/slide_hash_neon.h b/third_party/zlib/contrib/optimizations/slide_hash_neon.h
new file mode 100644
index 0000000..26995d7
--- /dev/null
+++ b/third_party/zlib/contrib/optimizations/slide_hash_neon.h
@@ -0,0 +1,65 @@
+/* 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 Chromium source repository LICENSE file.
+ */
+#ifndef __SLIDE_HASH__NEON__
+#define __SLIDE_HASH__NEON__
+
+#include "deflate.h"
+#include <arm_neon.h>
+
+inline static void ZLIB_INTERNAL neon_slide_hash_update(Posf *hash,
+                                                        const uInt hash_size,
+                                                        const ush w_size)
+{
+   /* NEON 'Q' registers allow to store 128 bits, so we can load 8x16-bits
+     * values. For further details, check:
+     * ARM DHT 0002A, section 1.3.2 NEON Registers.
+     */
+    const size_t chunk = sizeof(uint16x8_t) / sizeof(uint16_t);
+    /* Unrolling the operation yielded a compression performance boost in both
+     * ARMv7 (from 11.7% to 13.4%) and ARMv8 (from 3.7% to 7.5%) for HTML4
+     * content. For full benchmarking data, check: http://crbug.com/863257.
+     */
+    const size_t stride = 2*chunk;
+    const uint16x8_t v = vdupq_n_u16(w_size);
+
+    for (Posf *end = hash + hash_size; hash != end; hash += stride) {
+        uint16x8_t m_low = vld1q_u16(hash);
+        uint16x8_t m_high = vld1q_u16(hash + chunk);
+
+        /* The first 'q' in vqsubq_u16 makes these subtracts saturate to zero,
+         * replacing the ternary operator expression in the original code:
+         * (m >= wsize ? m - wsize : NIL).
+         */
+        m_low = vqsubq_u16(m_low, v);
+        m_high = vqsubq_u16(m_high, v);
+
+        vst1q_u16(hash, m_low);
+        vst1q_u16(hash + chunk, m_high);
+    }
+}
+
+
+inline static void ZLIB_INTERNAL neon_slide_hash(Posf *head, Posf *prev,
+                                                 const unsigned short w_size,
+                                                 const uInt hash_size)
+{
+    /*
+     * SIMD implementation for hash table rebase assumes:
+     * 1. hash chain offset (Pos) is 2 bytes.
+     * 2. hash table size is multiple of 32 bytes.
+     * #1 should be true as Pos is defined as "ush"
+     * #2 should be true as hash_bits are greater than 7
+     */
+    const size_t size = hash_size * sizeof(head[0]);
+    Assert(sizeof(Pos) == 2, "Wrong Pos size.");
+    Assert((size % sizeof(uint16x8_t) * 2) == 0, "Hash table size error.");
+
+    neon_slide_hash_update(head, hash_size, w_size);
+#ifndef FASTEST
+    neon_slide_hash_update(prev, w_size, w_size);
+#endif
+}
+
+#endif
diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
index 6fe9c7e..68d75b2 100644
--- a/third_party/zlib/deflate.c
+++ b/third_party/zlib/deflate.c
@@ -51,6 +51,9 @@
 #include <assert.h>
 #include "deflate.h"
 #include "x86.h"
+#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
+#include "contrib/optimizations/slide_hash_neon.h"
+#endif
 
 const char deflate_copyright[] =
    " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler ";
@@ -226,6 +229,10 @@
 local void slide_hash(s)
     deflate_state *s;
 {
+#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
+    /* NEON based hash table rebase. */
+    return neon_slide_hash(s->head, s->prev, s->w_size, s->hash_size);
+#endif
     unsigned n, m;
     Posf *p;
     uInt wsize = s->w_size;
diff --git a/tools/android/roll/android_deps/build.gradle b/tools/android/roll/android_deps/build.gradle
index 05c5629..a2d2fa7 100644
--- a/tools/android/roll/android_deps/build.gradle
+++ b/tools/android/roll/android_deps/build.gradle
@@ -37,6 +37,8 @@
     compile "com.google.android.gms:play-services-vision:${gmsVersion}"
     compile "com.google.android.gms:play-services-fido:${gmsVersion}"
 
+    compile "com.google.android.play:core:1.3.0"
+
     // Support v4 libraries
     def supportLibVersion = '27.0.0'
     compile "com.android.support:support-v4:${supportLibVersion}"
diff --git a/tools/code_coverage/test_suite.txt b/tools/code_coverage/test_suite.txt
index abe7e57..69ae9ab 100644
--- a/tools/code_coverage/test_suite.txt
+++ b/tools/code_coverage/test_suite.txt
@@ -4,7 +4,6 @@
 audio_unittests
 aura_unittests
 base_unittests
-battor_agent_unittests
 blink_common_unittests
 blink_heap_unittests
 blink_platform_unittests
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl
index 2516fb8..a62ac4c 100644
--- a/tools/determinism/deterministic_build_whitelist.pyl
+++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -27,6 +27,9 @@
     'remoting-webapp.v2.zip',
 
     'zucchini_apply_fuzzer_seed_corpus.zip',
+
+    # TODO(tikuta): Remove this when crbug.com/870584 is fixed.
+    'v8_context_snapshot.bin',
   ],
 
   # https://crbug.com/330262
@@ -159,6 +162,9 @@
     'viz_benchmark',
     'webkit_unit_tests',
     'wtf_unittests',
+
+    # TODO(tikuta): Remove this when crbug.com/870584 is fixed.
+    'v8_context_snapshot.bin',
   ],
 
   # https://crbug.com/330260
@@ -167,5 +173,8 @@
     'crashpad_snapshot_test_image_reader_module.dll',
     'mini_installer.exe',
     'previous_version_mini_installer.exe',
+
+    # TODO(tikuta): Remove this when crbug.com/870584 is fixed.
+    'v8_context_snapshot.bin',
   ],
 }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 06645d8..5cb86c2b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3078,6 +3078,13 @@
   <int value="3" label="Cannot dispatch the event"/>
 </enum>
 
+<enum name="BackgroundFetchStorageError">
+  <int value="0" label="None"/>
+  <int value="1" label="Service Worker Storage Error"/>
+  <int value="2" label="Cache Storage Error"/>
+  <int value="3" label="Storage Error"/>
+</enum>
+
 <enum name="BackgroundFetchTrigger">
   <int value="0" label="Wake-up of the persistent scheduler"/>
   <int value="1" label="Suggestions surface opened"/>
@@ -11139,6 +11146,17 @@
   <int value="3" label="Cancelled"/>
 </enum>
 
+<enum name="DownloadInProgressDBCountType">
+  <int value="0" label="In-progress DB initialization started"/>
+  <int value="1" label="In-progress DB successfully initialized"/>
+  <int value="2" label="In-progress DB failed to initialize"/>
+  <int value="3" label="In-progress DB successfully loaded"/>
+  <int value="4" label="In-progress DB failed to load"/>
+  <int value="5" label="Migration from in-progress cache required"/>
+  <int value="6" label="Migration from in-progress cache succeeded"/>
+  <int value="7" label="Migration from in-progress cache failed"/>
+</enum>
+
 <enum name="DownloadInterruptedUnknownSizeType">
   <int value="0" label="Size Known"/>
   <int value="1" label="Size Unknown"/>
@@ -14899,6 +14917,7 @@
   <int value="422" label="INPUT_METHOD_PRIVATE_ON_FOCUS"/>
   <int value="423" label="SYSTEM_POWER_SOURCE_ONPOWERCHANGED"/>
   <int value="424" label="WEB_REQUEST_ON_ACTION_IGNORED"/>
+  <int value="425" label="ARC_APPS_PRIVATE_ON_INSTALLED"/>
 </enum>
 
 <enum name="ExtensionFileWriteResult">
@@ -47974,6 +47993,7 @@
   <int value="3" label="High"/>
   <int value="4" label="(Obsolete) Severe"/>
   <int value="5" label="Critical"/>
+  <int value="6" label="Very Low (desktop canary and dev)"/>
 </enum>
 
 <enum name="UploadAcceptedCardOrigin">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a525dec..a59b097 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -18824,6 +18824,18 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="DisplayScheduler.ShouldNotDraw" enum="Boolean"
+    expires_after="M72">
+<!-- Name completed by histogram_suffixes
+     name="DisplaySchedulerNotDrawReason" -->
+
+  <owner>sadrul@chromium.org</owner>
+  <owner>sunnyps@chromium.org</owner>
+  <summary>
+    The reason for the DisplayScheduler to abort a draw operation.
+  </summary>
+</histogram>
+
 <histogram name="DNS.AttemptCancelled">
   <obsolete>
     Deprecated as of 6/2018.
@@ -21062,6 +21074,14 @@
   <summary>The count of HTTP Response codes for download requests.</summary>
 </histogram>
 
+<histogram name="Download.InProgressDB.Counts"
+    enum="DownloadInProgressDBCountType">
+  <owner>qinmin@chromium.org</owner>
+  <summary>
+    Various individual counts related to in-progress download DB.
+  </summary>
+</histogram>
+
 <histogram name="Download.InterruptedAtEndError" enum="NetErrorCodes">
   <owner>asanka@chromium.org</owner>
   <summary>
@@ -49641,6 +49661,17 @@
   </summary>
 </histogram>
 
+<histogram name="Net.CertificateTransparency.DnsQueryAuditProofRcode"
+    enum="AsyncDNSRcode">
+  <owner>robpercival@chromium.org</owner>
+  <summary>
+    Counts of specific DNS response codes returned by LogDnsClient at the end of
+    an attempt to obtain an inclusion proof for a certificate from a Certificate
+    Transparency log. The response codes (rcodes) and meanings are listed on
+    https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6.
+  </summary>
+</histogram>
+
 <histogram name="Net.CertificateTransparency.DnsQueryDuration" units="ms">
   <owner>robpercival@chromium.org</owner>
   <summary>
@@ -49670,6 +49701,17 @@
   </summary>
 </histogram>
 
+<histogram name="Net.CertificateTransparency.DnsQueryLeafIndexRcode"
+    enum="AsyncDNSRcode">
+  <owner>robpercival@chromium.org</owner>
+  <summary>
+    Counts of specific DNS response codes returned by LogDnsClient at the end of
+    an attempt to obtain a leaf index for a certificate from a Certificate
+    Transparency log. The response codes (rcodes) and meanings are listed on
+    https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6.
+  </summary>
+</histogram>
+
 <histogram name="Net.CertificateTransparency.DnsQueryStatus"
     enum="CertificateTransparencyDnsQueryStatus" expires_after="M67">
   <obsolete>
@@ -93018,7 +93060,8 @@
   </summary>
 </histogram>
 
-<histogram name="Settings.JsonDataReadSizeKilobytes" units="KB">
+<histogram name="Settings.JsonDataReadSizeKilobytes" units="KB"
+    expires_after="2018-07-30">
   <owner>gab@chromium.org</owner>
   <summary>
     The size (in kilobytes) of the JSON settings read from disk on startup.
@@ -95794,6 +95837,23 @@
   </summary>
 </histogram>
 
+<histogram name="SiteIsolation.XSD.Browser.Allowed.ContentScript"
+    enum="ContentResourceType2" expires_after="2018-12-11">
+  <owner>creis@chromium.org</owner>
+  <summary>
+    The total count of responses that were would be blocked by the cross-site
+    document blocking logic in the browser process, but were only allowed
+    because the request was initiated by a content script of an extension.
+    Sampled with a resource type (0-17) when the response is allowed.
+
+    Note that this histogram is not reimplemented in the NetworkService version
+    of Cross-Origin Read Blocking feature.  This should be okay since we hope to
+    gather enough data before NetworkService ships.
+
+    TODO(lukasza): Around Q4 2018: Remove code after we've gathered enough data.
+  </summary>
+</histogram>
+
 <histogram name="SiteIsolation.XSD.Browser.Blocked" enum="ContentResourceType2">
   <owner>creis@chromium.org</owner>
   <summary>
@@ -104717,6 +104777,14 @@
   </summary>
 </histogram>
 
+<histogram name="ThirdPartyModules.Modules.Unsigned" units="modules">
+  <owner>chrisha@chromium.org</owner>
+  <summary>
+    The total number of unsigned modules loaded (or potentially loaded) into the
+    browser process. Measured shortly after startup. Windows only.
+  </summary>
+</histogram>
+
 <histogram name="ThirdPartyModules.ShellExtensionsCount" units="counts">
   <owner>pmonette@chromium.org</owner>
   <summary>
@@ -118950,6 +119018,14 @@
   <affected-histogram name="Platform.DiskUsage.LeastUsedAccountDays"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="DisplaySchedulerNotDrawReason" separator=".">
+  <suffix name="DrawNotNeeded" label="DrawNotNeeded"/>
+  <suffix name="NotVisible" label="NotVisible"/>
+  <suffix name="OutputSurfaceLost" label="OutputSurfaceLost"/>
+  <suffix name="RootFrameMissing" label="RootFrameMissing"/>
+  <affected-histogram name="DisplayScheduler.ShouldNotDraw"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="DNS.HostCache.UpdateStale.AddressListDeltaType"
     separator="_">
   <suffix name="Disjoint" label="All different addresses."/>
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml
index f9b1fd5..56b76ba8 100644
--- a/tools/metrics/rappor/rappor.xml
+++ b/tools/metrics/rappor/rappor.xml
@@ -1178,6 +1178,23 @@
   </summary>
 </rappor-metric>
 
+<rappor-metric name="Extensions.CrossOriginFetchFromContentScript"
+    type="UMA_RAPPOR_TYPE">
+  <owner>lukasza@chromium.org</owner>
+  <summary>
+    The ID of an extension which triggers a cross-origin request from its
+    content script if such a request results in a non-empty, non-4xx response
+    that would have been blocked by CORB if the request didn't come from a
+    content script.
+
+    Note that gathering of this data is not reimplemented in the NetworkService
+    version of Cross-Origin Read Blocking feature.  This should be okay since we
+    hope to gather enough data before NetworkService ships.
+
+    TODO(lukasza): Around Q4 2018: Remove code after we've gathered enough data.
+  </summary>
+</rappor-metric>
+
 <rappor-metric name="Extensions.PossibleAdInjection2" type="ETLD_PLUS_ONE">
   <owner>rdevlin.cronin@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 2aa0b6d..03115809 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -450,16 +450,15 @@
     },
     'mac-10_12_laptop_low_end-perf': {
       'tests': [
-       # crbug.com/868675
-       # {
-       #   'isolate': 'performance_test_suite',
-       #   'num_shards': 26,
-       #   'extra_args': [
-       #       '--run-ref-build',
-       #       '--test-shard-map-filename=mac_1012_low_end_26_shard_map.json',
-       #       '--assert-gpu-compositing',
-       #   ],
-       # },
+        {
+          'isolate': 'performance_test_suite',
+          'num_shards': 26,
+          'extra_args': [
+              # '--run-ref-build', crbug.com/868675
+              '--test-shard-map-filename=mac_1012_low_end_26_shard_map.json',
+              '--assert-gpu-compositing',
+          ],
+        },
         {
           'isolate': 'load_library_perf_tests',
           'num_shards': 1,
@@ -520,16 +519,15 @@
     },
     'mac-10_13_laptop_high_end-perf': {
       'tests': [
-       # crbug.com/868675
-       # {
-       #   'isolate': 'performance_test_suite',
-       #   'extra_args': [
-       #     '--run-ref-build',
-       #     '--test-shard-map-filename=mac_1013_high_end_26_shard_map.json',
-       #       '--assert-gpu-compositing',
-       #   ],
-       #   'num_shards': 26
-       # },
+        {
+          'isolate': 'performance_test_suite',
+          'extra_args': [
+            # '--run-ref-build', crbug.com/868675
+            '--test-shard-map-filename=mac_1013_high_end_26_shard_map.json',
+              '--assert-gpu-compositing',
+          ],
+          'num_shards': 26
+        },
         {
           'isolate': 'net_perftests',
           'num_shards': 1,
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 9d2cca14..21c6830 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -191,12 +191,6 @@
 crbug.com/815193 [ Android ] rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html [ Skip ]
 crbug.com/842175 [ Android_One ] rasterize_and_record_micro.top_25/file://static_top_25/espn.html [ Skip ]
 
-# Benchmark: smoothness.gpu_rasterization.tough_pinch_zoom_cases
-crbug.com/822925 [ Android_Webview ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/yahoo_games_pinch [ Skip ]
-
-# Benchmark: smoothness.tough_pinch_zoom_cases
-crbug.com/822925 [ Android_Webview ] smoothness.tough_pinch_zoom_cases/yahoo_games_pinch [ Skip ]
-
 # Benchmark: system_health.common_desktop
 crbug.com/828917 [ Mac ] system_health.common_desktop/multitab:misc:typical24 [ Skip ]
 crbug.com/773084 [ Mac ] system_health.common_desktop/browse:tools:maps [ Skip ]
@@ -257,6 +251,7 @@
 crbug.com/843547 [ Android_Go ] system_health.memory_mobile/background:news:nytimes [ Skip ]
 crbug.com/852888 [ Nexus_5X ] system_health.memory_mobile/background:news:nytimes [ Skip ]
 crbug.com/859500 [ Nexus_5X ] system_health.memory_mobile/browse:social:tumblr_infinite_scroll [ Skip ]
+crbug.com/871708 [ Android_Go Android_Webview ] system_health.memory_mobile/browse:social:facebook_infinite_scroll [ Skip ]
 
 # Benchmark: tab_switching.typical_25
 crbug.com/747026 [ Mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
diff --git a/tools/perf/page_sets/data/rendering_desktop.json b/tools/perf/page_sets/data/rendering_desktop.json
index b433da8..d3c2477 100644
--- a/tools/perf/page_sets/data/rendering_desktop.json
+++ b/tools/perf/page_sets/data/rendering_desktop.json
@@ -204,108 +204,54 @@
         "accu_weather_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "amazon_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "amazon_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "blogspot_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "blogspot_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "booking_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "booking_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "cnn_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "cnn_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "ebay_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "ebay_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "espn_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "espn_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "facebook_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "facebook_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "gmail_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "gmail_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "google_calendar_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "google_calendar_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "google_image_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "google_image_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "google_search_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "google_search_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "linkedin_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "linkedin_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
         "twitch_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "twitter_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "twitter_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "weather_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "yahoo_games_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "yahoo_news_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "yahoo_news_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "yahoo_sports_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "yahoo_sports_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "youtube_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "youtube_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
diff --git a/tools/perf/page_sets/data/tough_pinch_zoom_cases.json b/tools/perf/page_sets/data/tough_pinch_zoom_cases.json
index e326ad1..eff55133 100644
--- a/tools/perf/page_sets/data/tough_pinch_zoom_cases.json
+++ b/tools/perf/page_sets/data/tough_pinch_zoom_cases.json
@@ -3,108 +3,54 @@
         "accu_weather_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "amazon_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "amazon_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "blogspot_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "blogspot_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "booking_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "booking_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "cnn_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "cnn_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "ebay_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "ebay_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "espn_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "espn_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "facebook_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "facebook_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "gmail_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "gmail_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "google_calendar_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "google_calendar_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "google_image_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "google_image_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "google_search_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "google_search_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "linkedin_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "linkedin_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
         "twitch_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "twitter_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "twitter_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "weather_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "yahoo_games_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "yahoo_news_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "yahoo_news_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "yahoo_sports_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "yahoo_sports_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "youtube_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
         "youtube_pinch_2018": {
             "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         }
diff --git a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
index 8dda6230..48f183c 100644
--- a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
+++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
@@ -51,17 +51,6 @@
         current_scale_factor *= 1/2.0
         self.RunPinchGesture(action_runner, scale_factor=1/2.0)
 
-class GoogleSearchPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: top google property; a google tab is often open. """
-
-  BASE_NAME = 'google_search_pinch'
-  URL = 'https://www.google.com/#hl=en&q=barack+obama'
-
-  def RunNavigateSteps(self, action_runner):
-    super(GoogleSearchPinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.WaitForElement(text='Next')
-
 
 class GoogleSearchPinchZoom2018Page(ToughPinchZoomPage):
 
@@ -76,20 +65,6 @@
     action_runner.WaitForElement(text='Next')
 
 
-class GmailPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: productivity, top google properties """
-
-  BASE_NAME = 'gmail_pinch'
-  URL = 'https://mail.google.com/mail/'
-
-  def RunNavigateSteps(self, action_runner):
-    super(GmailPinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.WaitForJavaScriptCondition(
-        'window.gmonkey !== undefined &&'
-        'document.getElementById("gb") !== null')
-
-
 class GmailPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: productivity, top google properties """
@@ -106,18 +81,6 @@
         'document.getElementById("gb") !== null')
 
 
-class GoogleCalendarPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: productivity, top google properties """
-
-  BASE_NAME = 'google_calendar_pinch'
-  URL = 'https://www.google.com/calendar/'
-
-  def RunNavigateSteps(self, action_runner):
-    super(GoogleCalendarPinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.Wait(2)
-
-
 class GoogleCalendarPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: productivity, top google properties """
@@ -133,14 +96,6 @@
     action_runner.WaitForElement('span[class~="sm8sCf"]')
 
 
-class GoogleImagePinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: tough image case; top google properties """
-
-  BASE_NAME = 'google_image_pinch'
-  URL = 'https://www.google.com/search?q=cats&tbm=isch'
-
-
 class GoogleImagePinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: tough image case; top google properties """
@@ -150,18 +105,6 @@
   URL = 'https://www.google.com/search?q=cats&tbm=isch'
 
 
-class YoutubePinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #3 (Alexa global) """
-
-  BASE_NAME = 'youtube_pinch'
-  URL = 'http://www.youtube.com'
-
-  def RunNavigateSteps(self, action_runner):
-    super(YoutubePinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.Wait(2)
-
-
 class YoutubePinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #3 (Alexa global) """
@@ -175,21 +118,6 @@
     action_runner.WaitForElement(selector='#buttons')
 
 
-class BlogSpotPinchZoomPage(ToughPinchZoomPage):
-
-  """
-  Why: #11 (Alexa global), google property; some blogger layouts have infinite
-  scroll but more interesting
-  """
-
-  BASE_NAME = 'blogspot_pinch'
-  URL = 'http://googlewebmastercentral.blogspot.com/'
-
-  def RunNavigateSteps(self, action_runner):
-    super(BlogSpotPinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.WaitForElement(text='accessibility')
-
-
 class BlogSpotPinchZoom2018Page(ToughPinchZoomPage):
 
   """
@@ -206,18 +134,6 @@
     action_runner.WaitForElement('div[class="searchBox"]')
 
 
-class FacebookPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: top social,Public profile """
-
-  BASE_NAME = 'facebook_pinch'
-  URL = 'http://www.facebook.com/barackobama'
-
-  def RunNavigateSteps(self, action_runner):
-    super(FacebookPinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.WaitForElement(text='About')
-
-
 class FacebookPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: top social,Public profile """
@@ -231,14 +147,6 @@
     action_runner.WaitForElement(text='Videos')
 
 
-class LinkedinPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #12 (Alexa global),Public profile """
-
-  BASE_NAME = 'linkedin_pinch'
-  URL = 'http://www.linkedin.com/in/linustorvalds'
-
-
 class LinkedinPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #12 (Alexa global),Public profile """
@@ -252,18 +160,6 @@
     super(LinkedinPinchZoom2018Page, self).RunNavigateSteps(action_runner)
 
 
-class TwitterPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #8 (Alexa global),Picked an interesting page """
-
-  BASE_NAME = 'twitter_pinch'
-  URL = 'https://twitter.com/katyperry'
-
-  def RunNavigateSteps(self, action_runner):
-    super(TwitterPinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.Wait(2)
-
-
 class TwitterPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #8 (Alexa global),Picked an interesting page """
@@ -277,14 +173,6 @@
     action_runner.WaitForElement(selector='.ProfileNav')
 
 
-class ESPNPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #1 sports """
-
-  BASE_NAME = 'espn_pinch'
-  URL = 'http://espn.go.com/nba'
-
-
 class ESPNPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #1 sports """
@@ -294,14 +182,6 @@
   URL = 'http://espn.go.com/nba'
 
 
-class WeatherDotComPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #7 (Alexa news); #27 total time spent,Picked interesting page """
-
-  BASE_NAME = 'weather_pinch'
-  URL = 'http://www.weather.com/weather/right-now/Mountain+View+CA+94043'
-
-
 class AccuWeatherPinchZoom2018Page(ToughPinchZoomPage):
   """ Why: #2 weather according to Alexa """
   BASE_NAME = 'accu_weather_pinch'
@@ -309,18 +189,6 @@
   URL = 'https://www.accuweather.com/en/us/new-york-ny/10017/weather-forecast/349727'
 
 
-class YahooGamePinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #1 games according to Alexa (with actual games in it) """
-
-  BASE_NAME = 'yahoo_games_pinch'
-  URL = 'http://games.yahoo.com'
-
-  def RunNavigateSteps(self, action_runner):
-    super(YahooGamePinchZoomPage, self).RunNavigateSteps(action_runner)
-    action_runner.Wait(2)
-
-
 class TwitchPinchZoom2018Page(ToughPinchZoomPage):
   """ Why: #1 games according to Alexa  """
   BASE_NAME = 'twitch_pinch'
@@ -328,14 +196,6 @@
   URL = 'https://www.twitch.tv'
 
 
-class YahooNewsPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #1 news worldwide (Alexa global) """
-
-  BASE_NAME = 'yahoo_news_pinch'
-  URL = 'http://news.yahoo.com'
-
-
 class YahooNewsPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #1 news worldwide (Alexa global) """
@@ -345,14 +205,6 @@
   URL = 'http://news.yahoo.com'
 
 
-class CnnPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #2 news worldwide """
-
-  BASE_NAME = 'cnn_pinch'
-  URL = 'http://www.cnn.com'
-
-
 class CnnPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #2 news worldwide """
@@ -362,17 +214,6 @@
   URL = 'http://www.cnn.com'
 
 
-class AmazonPinchZoomPage(ToughPinchZoomPage):
-
-  """
-  Why: #1 world commerce website by visits; #3 commerce in the US by
-  time spent
-  """
-
-  BASE_NAME = 'amazon_pinch'
-  URL = 'http://www.amazon.com'
-
-
 class AmazonPinchZoom2018Page(ToughPinchZoomPage):
 
   """
@@ -385,14 +226,6 @@
   URL = 'http://www.amazon.com'
 
 
-class EBayPinchZoomPage(ToughPinchZoomPage):
-
-  """  Why: #1 commerce website by time spent by users in US"""
-
-  BASE_NAME = 'ebay_pinch'
-  URL = 'http://www.ebay.com'
-
-
 class EBayPinchZoom2018Page(ToughPinchZoomPage):
 
   """  Why: #1 commerce website by time spent by users in US"""
@@ -402,14 +235,6 @@
   URL = 'http://www.ebay.com'
 
 
-class BookingPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #1 Alexa recreation"""
-
-  BASE_NAME = 'booking_pinch'
-  URL = 'http://booking.com'
-
-
 class BookingPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #1 Alexa recreation"""
@@ -419,13 +244,6 @@
   URL = 'http://booking.com'
 
 
-class YahooSportsPinchZoomPage(ToughPinchZoomPage):
-
-  """ Why: #1 Alexa sports"""
-  BASE_NAME = 'yahoo_sports_pinch'
-  URL = 'http://sports.yahoo.com/'
-
-
 class YahooSportsPinchZoom2018Page(ToughPinchZoomPage):
 
   """ Why: #1 Alexa sports"""
@@ -448,43 +266,6 @@
 
     self.target_scale_factor = target_scale_factor
 
-    self.AddStory(GoogleSearchPinchZoomPage(
-        page_set=self))
-    self.AddStory(GmailPinchZoomPage(
-        page_set=self))
-    self.AddStory(GoogleCalendarPinchZoomPage(
-        page_set=self))
-    self.AddStory(GoogleImagePinchZoomPage(
-        page_set=self))
-    self.AddStory(YoutubePinchZoomPage(
-        page_set=self))
-    self.AddStory(BlogSpotPinchZoomPage(
-        page_set=self))
-    self.AddStory(FacebookPinchZoomPage(
-        page_set=self))
-    self.AddStory(LinkedinPinchZoomPage(
-        page_set=self))
-    self.AddStory(TwitterPinchZoomPage(
-        page_set=self))
-    self.AddStory(ESPNPinchZoomPage(
-        page_set=self))
-    self.AddStory(YahooGamePinchZoomPage(
-        page_set=self))
-    self.AddStory(YahooNewsPinchZoomPage(
-        page_set=self))
-    self.AddStory(CnnPinchZoomPage(
-        page_set=self))
-    self.AddStory(AmazonPinchZoomPage(
-        page_set=self))
-    self.AddStory(EBayPinchZoomPage(
-        page_set=self))
-    self.AddStory(WeatherDotComPinchZoomPage(
-        page_set=self))
-    self.AddStory(YahooSportsPinchZoomPage(
-        page_set=self))
-    self.AddStory(BookingPinchZoomPage(
-        page_set=self))
-
     self.AddStory(GoogleSearchPinchZoom2018Page(
         page_set=self))
     self.AddStory(GmailPinchZoom2018Page(
diff --git a/tools/sublime/OWNERS b/tools/sublime/OWNERS
index 21010ce..1e6deee 100644
--- a/tools/sublime/OWNERS
+++ b/tools/sublime/OWNERS
@@ -1,2 +1 @@
 jkarlin@chromium.org
-sashab@chromium.org
diff --git a/tools/traffic_annotation/bin/README.md b/tools/traffic_annotation/bin/README.md
index e50b2885..55187d07 100644
--- a/tools/traffic_annotation/bin/README.md
+++ b/tools/traffic_annotation/bin/README.md
@@ -74,4 +74,4 @@
 README should be committed along with the updated .sha1 checksums.
 
 CLANG_REVISION = '338452'
-LASTCHANGE=d8fb3e8fd6e0b637be8af0180d96527541e6b69e-refs/heads/master@{#581194}
+LASTCHANGE=91de2a347a0372128c51c770e912097ce4c07a70-refs/heads/master@{#581211}
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
index 8a2b22ea..fae343b 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@
-d47388b3f429e16c8a4aa2a515894cd29aef6f8f
\ No newline at end of file
+3efcac84415fa69a73040bdf02080e66261dc245
\ No newline at end of file
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 2613f91..8320a4a 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -36,7 +36,6 @@
     "input_state_lookup.h",
     "input_state_lookup_win.h",
     "layout_manager.h",
-    "local/layer_tree_frame_sink_local.h",
     "local/window_port_local.h",
     "mus/capture_synchronizer.h",
     "mus/capture_synchronizer_delegate.h",
@@ -109,7 +108,6 @@
     "input_state_lookup.cc",
     "input_state_lookup_win.cc",
     "layout_manager.cc",
-    "local/layer_tree_frame_sink_local.cc",
     "local/window_port_local.cc",
     "mouse_location_manager.cc",
     "mouse_location_manager.h",
diff --git a/ui/aura/local/DEPS b/ui/aura/local/DEPS
index a9fb518..fa5942b1 100644
--- a/ui/aura/local/DEPS
+++ b/ui/aura/local/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+cc/mojo_embedder",
   "+cc/output",
   "+cc/scheduler",
   "+components/viz/service/frame_sinks",
diff --git a/ui/aura/local/layer_tree_frame_sink_local.cc b/ui/aura/local/layer_tree_frame_sink_local.cc
deleted file mode 100644
index dd997b5..0000000
--- a/ui/aura/local/layer_tree_frame_sink_local.cc
+++ /dev/null
@@ -1,164 +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 "ui/aura/local/layer_tree_frame_sink_local.h"
-
-#include "cc/trees/layer_tree_frame_sink_client.h"
-#include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/host/host_frame_sink_manager.h"
-#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
-#include "ui/aura/client/cursor_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-
-namespace aura {
-
-LayerTreeFrameSinkLocal::LayerTreeFrameSinkLocal(
-    const viz::FrameSinkId& frame_sink_id,
-    viz::HostFrameSinkManager* host_frame_sink_manager,
-    const std::string& debug_label)
-    : cc::LayerTreeFrameSink(nullptr, nullptr, nullptr, nullptr),
-      frame_sink_id_(frame_sink_id),
-      host_frame_sink_manager_(host_frame_sink_manager) {
-  host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
-  host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_, debug_label);
-}
-
-LayerTreeFrameSinkLocal::~LayerTreeFrameSinkLocal() {
-  host_frame_sink_manager_->InvalidateFrameSinkId(frame_sink_id_);
-}
-
-bool LayerTreeFrameSinkLocal::BindToClient(
-    cc::LayerTreeFrameSinkClient* client) {
-  if (!cc::LayerTreeFrameSink::BindToClient(client))
-    return false;
-  DCHECK(!thread_checker_);
-  thread_checker_ = std::make_unique<base::ThreadChecker>();
-
-  support_ = host_frame_sink_manager_->CreateCompositorFrameSinkSupport(
-      this, frame_sink_id_, false /* is_root */,
-      true /* needs_sync_points */);
-  begin_frame_source_ = std::make_unique<viz::ExternalBeginFrameSource>(this);
-  client->SetBeginFrameSource(begin_frame_source_.get());
-  return true;
-}
-
-void LayerTreeFrameSinkLocal::SetSurfaceChangedCallback(
-    const SurfaceChangedCallback& callback) {
-  DCHECK(!surface_changed_callback_);
-  surface_changed_callback_ = callback;
-}
-
-void LayerTreeFrameSinkLocal::DetachFromClient() {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  client_->SetBeginFrameSource(nullptr);
-  begin_frame_source_.reset();
-  support_.reset();
-  thread_checker_.reset();
-  cc::LayerTreeFrameSink::DetachFromClient();
-}
-
-void LayerTreeFrameSinkLocal::SetLocalSurfaceId(
-    const viz::LocalSurfaceId& local_surface_id) {
-  DCHECK(local_surface_id.is_valid());
-  local_surface_id_ = local_surface_id;
-}
-
-void LayerTreeFrameSinkLocal::SubmitCompositorFrame(
-    viz::CompositorFrame frame) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  DCHECK(frame.metadata.begin_frame_ack.has_damage);
-  DCHECK_LE(viz::BeginFrameArgs::kStartingFrameNumber,
-            frame.metadata.begin_frame_ack.sequence_number);
-
-  DCHECK(local_surface_id_.is_valid());
-
-  support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
-}
-
-void LayerTreeFrameSinkLocal::DidNotProduceFrame(
-    const viz::BeginFrameAck& ack) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  DCHECK(!ack.has_damage);
-  DCHECK_LE(viz::BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
-  support_->DidNotProduceFrame(ack);
-}
-
-void LayerTreeFrameSinkLocal::DidAllocateSharedBitmap(
-    mojo::ScopedSharedBufferHandle buffer,
-    const viz::SharedBitmapId& id) {
-  // No software compositing used with this implementation.
-  NOTIMPLEMENTED();
-}
-
-void LayerTreeFrameSinkLocal::DidDeleteSharedBitmap(
-    const viz::SharedBitmapId& id) {
-  // No software compositing used with this implementation.
-  NOTIMPLEMENTED();
-}
-
-void LayerTreeFrameSinkLocal::DidReceiveCompositorFrameAck(
-    const std::vector<viz::ReturnedResource>& resources) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  if (!client_)
-    return;
-  if (!resources.empty())
-    client_->ReclaimResources(resources);
-  client_->DidReceiveCompositorFrameAck();
-}
-
-void LayerTreeFrameSinkLocal::DidPresentCompositorFrame(
-    uint32_t presentation_token,
-    const gfx::PresentationFeedback& feedback) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  client_->DidPresentCompositorFrame(presentation_token, feedback);
-}
-
-void LayerTreeFrameSinkLocal::OnBeginFrame(const viz::BeginFrameArgs& args) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  begin_frame_source_->OnBeginFrame(args);
-}
-
-void LayerTreeFrameSinkLocal::OnBeginFramePausedChanged(bool paused) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  begin_frame_source_->OnSetBeginFrameSourcePaused(paused);
-}
-
-void LayerTreeFrameSinkLocal::ReclaimResources(
-    const std::vector<viz::ReturnedResource>& resources) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  if (!client_)
-    return;
-  client_->ReclaimResources(resources);
-}
-
-void LayerTreeFrameSinkLocal::OnNeedsBeginFrames(bool needs_begin_frames) {
-  DCHECK(thread_checker_);
-  DCHECK(thread_checker_->CalledOnValidThread());
-  support_->SetNeedsBeginFrame(needs_begin_frames);
-}
-
-void LayerTreeFrameSinkLocal::OnFirstSurfaceActivation(
-    const viz::SurfaceInfo& surface_info) {
-  surface_changed_callback_.Run(surface_info);
-}
-
-void LayerTreeFrameSinkLocal::OnFrameTokenChanged(uint32_t frame_token) {
-  // TODO(yiyix, fsamuel): Implement frame token propagation for
-  // LayerTreeFrameSinkLocal.
-  NOTREACHED();
-}
-
-}  // namespace aura
diff --git a/ui/aura/local/layer_tree_frame_sink_local.h b/ui/aura/local/layer_tree_frame_sink_local.h
deleted file mode 100644
index 0fa973a6..0000000
--- a/ui/aura/local/layer_tree_frame_sink_local.h
+++ /dev/null
@@ -1,92 +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 UI_AURA_LOCAL_LAYER_TREE_FRAME_SINK_LOCAL_H_
-#define UI_AURA_LOCAL_LAYER_TREE_FRAME_SINK_LOCAL_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "cc/trees/layer_tree_frame_sink.h"
-#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/common/surfaces/frame_sink_id.h"
-#include "components/viz/host/host_frame_sink_client.h"
-#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
-#include "ui/aura/window_port.h"
-#include "ui/base/property_data.h"
-
-namespace viz {
-class CompositorFrameSinkSupport;
-class HostFrameSinkManager;
-}
-
-namespace aura {
-
-// cc::LayerTreeFrameSink implementation for classic aura, e.g. not mus.
-// aura::Window::CreateLayerTreeFrameSink creates this class for a given
-// aura::Window, and then the sink can be used for submitting frames to the
-// aura::Window's ui::Layer.
-class LayerTreeFrameSinkLocal : public cc::LayerTreeFrameSink,
-                                public viz::mojom::CompositorFrameSinkClient,
-                                public viz::ExternalBeginFrameSourceClient,
-                                public viz::HostFrameSinkClient {
- public:
-  LayerTreeFrameSinkLocal(const viz::FrameSinkId& frame_sink_id,
-                          viz::HostFrameSinkManager* host_frame_sink_manager,
-                          const std::string& debug_label);
-  ~LayerTreeFrameSinkLocal() override;
-
-  using SurfaceChangedCallback = base::Callback<void(const viz::SurfaceInfo&)>;
-
-  // Set a callback which will be called when the surface is changed.
-  void SetSurfaceChangedCallback(const SurfaceChangedCallback& callback);
-
-  const viz::LocalSurfaceId& local_surface_id() const {
-    return local_surface_id_;
-  }
-
-  // cc::LayerTreeFrameSink:
-  bool BindToClient(cc::LayerTreeFrameSinkClient* client) override;
-  void DetachFromClient() override;
-  void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id) override;
-  void SubmitCompositorFrame(viz::CompositorFrame frame) override;
-  void DidNotProduceFrame(const viz::BeginFrameAck& ack) override;
-  void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
-                               const viz::SharedBitmapId& id) override;
-  void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override;
-
-  // viz::mojom::CompositorFrameSinkClient:
-  void DidReceiveCompositorFrameAck(
-      const std::vector<viz::ReturnedResource>& resources) override;
-  void DidPresentCompositorFrame(
-      uint32_t presentation_token,
-      const gfx::PresentationFeedback& feedback) override;
-  void OnBeginFrame(const viz::BeginFrameArgs& args) override;
-  void ReclaimResources(
-      const std::vector<viz::ReturnedResource>& resources) override;
-  void OnBeginFramePausedChanged(bool paused) override;
-
-  // viz::ExternalBeginFrameSourceClient:
-  void OnNeedsBeginFrames(bool needs_begin_frames) override;
-
- private:
-  // public viz::HostFrameSinkClient:
-  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
-  void OnFrameTokenChanged(uint32_t frame_token) override;
-
-  const viz::FrameSinkId frame_sink_id_;
-  viz::HostFrameSinkManager* const host_frame_sink_manager_;
-  std::unique_ptr<viz::CompositorFrameSinkSupport> support_;
-  gfx::Size surface_size_;
-  viz::LocalSurfaceId local_surface_id_;
-  std::unique_ptr<viz::ExternalBeginFrameSource> begin_frame_source_;
-  std::unique_ptr<base::ThreadChecker> thread_checker_;
-  SurfaceChangedCallback surface_changed_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(LayerTreeFrameSinkLocal);
-};
-
-}  // namespace aura
-
-#endif  // UI_AURA_LOCAL_LAYER_TREE_FRAME_SINK_LOCAL_H_
diff --git a/ui/aura/local/window_port_local.cc b/ui/aura/local/window_port_local.cc
index 8eb6804..7444e0b 100644
--- a/ui/aura/local/window_port_local.cc
+++ b/ui/aura/local/window_port_local.cc
@@ -4,10 +4,14 @@
 
 #include "ui/aura/local/window_port_local.h"
 
+#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
+#include "components/viz/client/hit_test_data_provider_draw_quad.h"
+#include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/features.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/env.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
+#include "ui/aura/hit_test_data_provider_aura.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/base/layout.h"
@@ -61,7 +65,15 @@
 WindowPortLocal::WindowPortLocal(Window* window)
     : window_(window), weak_factory_(this) {}
 
-WindowPortLocal::~WindowPortLocal() {}
+WindowPortLocal::~WindowPortLocal() {
+  if (frame_sink_id_.is_valid()) {
+    auto* context_factory_private =
+        aura::Env::GetInstance()->context_factory_private();
+    auto* host_frame_sink_manager =
+        context_factory_private->GetHostFrameSinkManager();
+    host_frame_sink_manager->InvalidateFrameSinkId(frame_sink_id_);
+  }
+}
 
 void WindowPortLocal::OnPreInit(Window* window) {}
 
@@ -120,15 +132,44 @@
 
 std::unique_ptr<cc::LayerTreeFrameSink>
 WindowPortLocal::CreateLayerTreeFrameSink() {
+  DCHECK(!frame_sink_id_.is_valid());
   auto* context_factory_private =
       aura::Env::GetInstance()->context_factory_private();
-  auto frame_sink_id = context_factory_private->AllocateFrameSinkId();
-  auto frame_sink = std::make_unique<LayerTreeFrameSinkLocal>(
-      frame_sink_id, context_factory_private->GetHostFrameSinkManager(),
-      window_->GetName());
-  window_->SetEmbedFrameSinkId(frame_sink_id);
-  frame_sink->SetSurfaceChangedCallback(base::Bind(
-      &WindowPortLocal::OnSurfaceChanged, weak_factory_.GetWeakPtr()));
+  auto* host_frame_sink_manager =
+      context_factory_private->GetHostFrameSinkManager();
+  frame_sink_id_ = context_factory_private->AllocateFrameSinkId();
+
+  // For creating a async frame sink which connects to the viz display
+  // compositor.
+  viz::mojom::CompositorFrameSinkPtrInfo sink_info;
+  viz::mojom::CompositorFrameSinkRequest sink_request =
+      mojo::MakeRequest(&sink_info);
+  viz::mojom::CompositorFrameSinkClientPtr client;
+  viz::mojom::CompositorFrameSinkClientRequest client_request =
+      mojo::MakeRequest(&client);
+  host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
+  window_->SetEmbedFrameSinkId(frame_sink_id_);
+  host_frame_sink_manager->CreateCompositorFrameSink(
+      frame_sink_id_, std::move(sink_request), std::move(client));
+
+  cc::mojo_embedder::AsyncLayerTreeFrameSink::InitParams params;
+  params.gpu_memory_buffer_manager =
+      aura::Env::GetInstance()->context_factory()->GetGpuMemoryBufferManager();
+  params.pipes.compositor_frame_sink_info = std::move(sink_info);
+  params.pipes.client_request = std::move(client_request);
+  params.enable_surface_synchronization = true;
+  if (features::IsVizHitTestingDrawQuadEnabled()) {
+    params.hit_test_data_provider =
+        std::make_unique<viz::HitTestDataProviderDrawQuad>(
+            true /* should_ask_for_child_region */);
+  } else {
+    params.hit_test_data_provider =
+        std::make_unique<HitTestDataProviderAura>(window_);
+  }
+  auto frame_sink =
+      std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>(
+          nullptr /* context_provider */, nullptr /* worker_context_provider */,
+          &params);
   frame_sink_ = frame_sink->GetWeakPtr();
   AllocateLocalSurfaceId();
   return std::move(frame_sink);
@@ -136,7 +177,7 @@
 
 void WindowPortLocal::AllocateLocalSurfaceId() {
   if (!parent_local_surface_id_allocator_)
-    parent_local_surface_id_allocator_ = viz::ParentLocalSurfaceIdAllocator();
+    parent_local_surface_id_allocator_.emplace();
   else
     parent_local_surface_id_allocator_->GenerateId();
   UpdateLocalSurfaceId();
@@ -168,9 +209,13 @@
 
 void WindowPortLocal::OnEventTargetingPolicyChanged() {}
 
-void WindowPortLocal::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
+bool WindowPortLocal::ShouldRestackTransientChildren() {
+  return true;
+}
+
+void WindowPortLocal::OnFirstSurfaceActivation(
+    const viz::SurfaceInfo& surface_info) {
   DCHECK_EQ(surface_info.id().frame_sink_id(), window_->GetFrameSinkId());
-  DCHECK_EQ(surface_info.id().local_surface_id(), GetCurrentLocalSurfaceId());
   window_->layer()->SetShowPrimarySurface(
       surface_info.id(), window_->bounds().size(), SK_ColorWHITE,
       cc::DeadlinePolicy::UseDefaultDeadline(),
@@ -178,9 +223,7 @@
   window_->layer()->SetFallbackSurfaceId(surface_info.id());
 }
 
-bool WindowPortLocal::ShouldRestackTransientChildren() {
-  return true;
-}
+void WindowPortLocal::OnFrameTokenChanged(uint32_t frame_token) {}
 
 void WindowPortLocal::UpdateLocalSurfaceId() {
   last_device_scale_factor_ = ui::GetScaleFactorForNativeView(window_);
diff --git a/ui/aura/local/window_port_local.h b/ui/aura/local/window_port_local.h
index ed0b839..7328450 100644
--- a/ui/aura/local/window_port_local.h
+++ b/ui/aura/local/window_port_local.h
@@ -10,7 +10,7 @@
 #include "base/optional.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
+#include "components/viz/host/host_frame_sink_client.h"
 #include "ui/aura/window_port.h"
 #include "ui/base/property_data.h"
 #include "ui/gfx/geometry/size.h"
@@ -24,7 +24,8 @@
 class Window;
 
 // WindowPort implementation for classic aura, e.g. not mus.
-class AURA_EXPORT WindowPortLocal : public WindowPort {
+class AURA_EXPORT WindowPortLocal : public WindowPort,
+                                    public viz::HostFrameSinkClient {
  public:
   explicit WindowPortLocal(Window* window);
   ~WindowPortLocal() override;
@@ -57,8 +58,11 @@
   void OnEventTargetingPolicyChanged() override;
   bool ShouldRestackTransientChildren() override;
 
+  // viz::HostFrameSinkClient:
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
+  void OnFrameTokenChanged(uint32_t frame_token) override;
+
  private:
-  void OnSurfaceChanged(const viz::SurfaceInfo& surface_info);
   void UpdateLocalSurfaceId();
   const viz::LocalSurfaceId& GetCurrentLocalSurfaceId() const;
   bool IsEmbeddingExternalContent() const;
@@ -69,6 +73,7 @@
   base::Optional<viz::ParentLocalSurfaceIdAllocator>
       parent_local_surface_id_allocator_;
   base::WeakPtr<cc::LayerTreeFrameSink> frame_sink_;
+  viz::FrameSinkId frame_sink_id_;
 
   base::WeakPtrFactory<WindowPortLocal> weak_factory_;
 
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index 336d3009..3576d1c 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -628,10 +628,4 @@
   client_surface_embedder_->SetFallbackSurfaceInfo(fallback_surface_info_);
 }
 
-void WindowPortMus::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
-  // TODO(fsamuel): Rename OnFirstSurfaceActivation() and set primary earlier
-  // based on feedback from LayerTreeFrameSinkLocal.
-  NOTREACHED();
-}
-
 }  // namespace aura
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h
index 4a5d977..1a4d0c5 100644
--- a/ui/aura/mus/window_port_mus.h
+++ b/ui/aura/mus/window_port_mus.h
@@ -20,7 +20,6 @@
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "services/ui/public/interfaces/window_tree_constants.mojom.h"
 #include "ui/aura/aura_export.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
 #include "ui/aura/mus/mus_types.h"
 #include "ui/aura/mus/window_mus.h"
 #include "ui/aura/window_port.h"
@@ -33,6 +32,14 @@
 }
 }
 
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
+namespace viz {
+class ContextProvider;
+}
+
 namespace aura {
 
 class ClientSurfaceEmbedder;
@@ -282,8 +289,6 @@
   void UpdatePrimarySurfaceId();
   void UpdateClientSurfaceEmbedder();
 
-  void OnSurfaceChanged(const viz::SurfaceInfo& surface_info);
-
   WindowTreeClient* window_tree_client_;
 
   Window* window_ = nullptr;
diff --git a/ui/aura/mus/window_port_mus_unittest.cc b/ui/aura/mus/window_port_mus_unittest.cc
index c6e5312..0e05b58 100644
--- a/ui/aura/mus/window_port_mus_unittest.cc
+++ b/ui/aura/mus/window_port_mus_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
 #include "ui/aura/mus/client_surface_embedder.h"
 #include "ui/aura/test/aura_test_base.h"
 #include "ui/aura/window.h"
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc
index ffc326c..a816ef39 100644
--- a/ui/aura/test/aura_test_helper.cc
+++ b/ui/aura/test/aura_test_helper.cc
@@ -10,7 +10,6 @@
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/input_state_lookup.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
 #include "ui/aura/mus/capture_synchronizer.h"
 #include "ui/aura/mus/focus_synchronizer.h"
 #include "ui/aura/mus/window_port_mus.h"
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index 47f55ce7..110eac9c 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -30,7 +30,6 @@
 #include "ui/aura/client/window_stacking_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/layout_manager.h"
-#include "ui/aura/local/layer_tree_frame_sink_local.h"
 #include "ui/aura/scoped_keyboard_hook.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher.h"
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
index 897248a21..7e9f6df 100644
--- a/ui/events/platform/x11/x11_event_source.cc
+++ b/ui/events/platform/x11/x11_event_source.cc
@@ -96,7 +96,8 @@
       display_(display),
       dispatching_event_(nullptr),
       dummy_initialized_(false),
-      continue_stream_(true) {
+      continue_stream_(true),
+      distribution_(0, 999) {
   DCHECK(!instance_);
   instance_ = this;
 
@@ -156,7 +157,13 @@
     dummy_initialized_ = true;
   }
 
-  base::TimeTicks start = base::TimeTicks::Now();
+  // No need to measure Linux.X11.ServerRTT on every call.
+  // base::TimeTicks::Now() itself has non-trivial overhead.
+  bool measure_rtt = distribution_(generator_) == 0;
+
+  base::TimeTicks start;
+  if (measure_rtt)
+    start = base::TimeTicks::Now();
 
   // Make a no-op property change on |dummy_window_|.
   XChangeProperty(display_, dummy_window_, dummy_atom_, XA_STRING, 8,
@@ -167,9 +174,12 @@
   XIfEvent(display_, &event, IsPropertyNotifyForTimestamp,
            reinterpret_cast<XPointer>(&dummy_window_));
 
-  UMA_HISTOGRAM_CUSTOM_COUNTS(
-      "Linux.X11.ServerRTT", (base::TimeTicks::Now() - start).InMicroseconds(),
-      1, base::TimeDelta::FromMilliseconds(50).InMicroseconds(), 50);
+  if (measure_rtt) {
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "Linux.X11.ServerRTT",
+        (base::TimeTicks::Now() - start).InMicroseconds(), 1,
+        base::TimeDelta::FromMilliseconds(50).InMicroseconds(), 50);
+  }
   return event.xproperty.time;
 }
 
diff --git a/ui/events/platform/x11/x11_event_source.h b/ui/events/platform/x11/x11_event_source.h
index 1df54b42..e818c4ac 100644
--- a/ui/events/platform/x11/x11_event_source.h
+++ b/ui/events/platform/x11/x11_event_source.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <random>
 
 #include "base/macros.h"
 #include "base/optional.h"
@@ -79,6 +80,10 @@
   void StopCurrentEventStream();
   void OnDispatcherListChanged();
 
+  // Explicitly asks the X11 server for the current timestamp, and updates
+  // |last_seen_server_time_| with this value.
+  Time GetCurrentServerTime();
+
  protected:
   // Extracts cookie data from |xevent| if it's of GenericType, and dispatches
   // the event. This function also frees up the cookie data after dispatch is
@@ -88,10 +93,6 @@
   // Handles updates after event has been dispatched.
   void PostDispatchEvent(XEvent* xevent);
 
-  // Explicitly asks the X11 server for the current timestamp, and updates
-  // |last_seen_server_time_| with this value.
-  Time GetCurrentServerTime();
-
  private:
   static X11EventSource* instance_;
 
@@ -115,6 +116,10 @@
 
   std::unique_ptr<X11HotplugEventHandler> hotplug_event_handler_;
 
+  // Used to sample RTT measurements, with frequency 1/1000.
+  std::default_random_engine generator_;
+  std::uniform_int_distribution<int> distribution_;
+
   DISALLOW_COPY_AND_ASSIGN(X11EventSource);
 };
 
diff --git a/ui/file_manager/OWNERS b/ui/file_manager/OWNERS
index 9feaadf4..70c20fc 100644
--- a/ui/file_manager/OWNERS
+++ b/ui/file_manager/OWNERS
@@ -3,5 +3,4 @@
 lucmult@chromium.org
 mtomasz@chromium.org
 noel@chromium.org
-sashab@chromium.org
 yamaguchi@chromium.org
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 9d1f274a4..9f6f68b7 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
@@ -409,7 +409,6 @@
  *     otherwise.
  */
 test.util.sync.fakeMouseRightClick = function(contentWindow, targetQuery) {
-  contentWindow.document.querySelector(targetQuery).focus();
   var mouseDownEvent = new MouseEvent('mousedown', {bubbles: true, button: 2});
   if (!test.util.sync.sendEvent(contentWindow, targetQuery, mouseDownEvent)) {
     return false;
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 7094c0d..ec78ae0 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -333,34 +333,24 @@
 MediaViewContentScanner.prototype.__proto__ = ContentScanner.prototype;
 
 /**
- * This scanner provides flattened view of media providers. In each view all
- * media-view files are located just under the root directory and the root
- * directory doesn't have any directories (i.e. Directories are ignored).
+ * This scanner provides flattened view of media providers.
  *
- * In FileSystem API level, the root directory contains only directories, and
- * all files are guaranteed to be located inside first-level directories.
- * For example, in Pictures view, we have directories in the first level and
- * files in the second level.
- *
- * Pictures/
- *     DCIM/
- *         a.jpg
- *     Snapsheed/
- *         foo.jpg
- *
- * We can retrieve all files by scanning directories up to one level.
- *
+ * In FileSystem API level, each media-view root directory has directory
+ * hierarchy. We need to list files under the root directory to provide flatten
+ * view. A file will not be shown in multiple directories in media-view
+ * hierarchy since no folders will be added in media documents provider. We can
+ * list all files without duplication by just retrieveing files in directories
+ * recursively.
  * @override
  */
 MediaViewContentScanner.prototype.scan = function(
     entriesCallback, successCallback, errorCallback) {
-  // To provide flatten view of files, it is enough to retrieve file recursively
-  // up to one level from the root.
-  const recursionLevel = 1;
+  // To provide flatten view of files, this media-view scanner retrieves files
+  // in directories inside the media's root entry recursively.
   util.readEntriesRecursively(
       this.rootEntry_,
       entries => entriesCallback(entries.filter(entry => !entry.isDirectory)),
-      successCallback, errorCallback, () => false, recursionLevel);
+      successCallback, errorCallback, () => false);
 };
 
 /**
diff --git a/ui/file_manager/integration_tests/file_manager/context_menu.js b/ui/file_manager/integration_tests/file_manager/context_menu.js
index aba40b4..f7364ca 100644
--- a/ui/file_manager/integration_tests/file_manager/context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/context_menu.js
@@ -29,15 +29,35 @@
 function checkContextMenu(commandId, path, expectedEnabledState) {
   let appId;
   StepsRunner.run([
-    // Set up Files App.
+    // Open Files App on Drive.
     function() {
       setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, BASIC_LOCAL_ENTRY_SET,
-          COMPLEX_DRIVE_ENTRY_SET);
+          null, RootPath.DRIVE, this.next, [], COMPLEX_DRIVE_ENTRY_SET);
     },
-    // Select the file.
+    // Optionally copy hello.txt into the clipboard if needed.
     function(results) {
       appId = results.windowId;
+
+      const needsClipboardCopy = /^paste/.test(commandId);
+      if (!needsClipboardCopy) {
+        this.next();
+        return;
+      }
+
+      const file = ['hello.txt'];
+      remoteCall.callRemoteTestUtil('selectFile', appId, file)
+          .then(result => {
+            chrome.test.assertTrue(!!result, 'selectFile failed');
+            return remoteCall.callRemoteTestUtil(
+                'execCommand', appId, ['copy']);
+          })
+          .then((result) => {
+            chrome.test.assertTrue(!!result, 'execCommand failed');
+            this.next();
+          });
+    },
+    // Select the file |path|.
+    function() {
       remoteCall.callRemoteTestUtil('selectFile', appId, [path], this.next);
     },
     // Wait for the file to be selected.
@@ -45,7 +65,7 @@
       chrome.test.assertTrue(!!result);
       remoteCall.waitForElement(appId, '.table-row[selected]').then(this.next);
     },
-    // Right-click on the file.
+    // Right-click the selected file.
     function() {
       remoteCall.callRemoteTestUtil(
           'fakeMouseRightClick', appId, ['.table-row[selected]'], this.next);
@@ -58,11 +78,11 @@
     },
     // Wait for the command option to appear.
     function() {
-      let query;
+      let query = '#file-context-menu:not([hidden])';
       if (expectedEnabledState) {
-        query = `[command="#${commandId}"]:not([hidden]):not([disabled])`;
+        query += ` [command="#${commandId}"]:not([hidden]):not([disabled])`;
       } else {
-        query = `[command="#${commandId}"][disabled]:not([hidden])`;
+        query += ` [command="#${commandId}"][disabled]:not([hidden])`;
       }
       remoteCall.waitForElement(appId, query).then(this.next);
     },
@@ -74,71 +94,6 @@
 }
 
 /**
- * Right-clicks on the specified item and selects "Copy".
- *
- * @param {string} path Path to the file or folder to copy.
- * @param {function()=} opt_callback Callback to call after the copy has
- *     completed.
- */
-function copyEntryToClipboard(path, opt_callback) {
-  var appId;
-  StepsRunner.run([
-    // Set up Files App.
-    function() {
-      setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, BASIC_LOCAL_ENTRY_SET,
-          COMPLEX_DRIVE_ENTRY_SET);
-    },
-    // Select the file.
-    function(results) {
-      appId = results.windowId;
-      remoteCall.callRemoteTestUtil('selectFile', appId, [path], this.next);
-    },
-    // Wait for the file to be selected.
-    function(result) {
-      chrome.test.assertTrue(result);
-      remoteCall.waitForElement(appId, '.table-row[selected]').then(this.next);
-    },
-    // Right-click on the file.
-    function() {
-      remoteCall.callRemoteTestUtil(
-          'fakeMouseRightClick', appId, ['.table-row[selected]'], this.next);
-    },
-    // Wait for the context menu to appear.
-    function(result) {
-      chrome.test.assertTrue(result);
-      remoteCall.waitForElement(appId, '#file-context-menu:not([hidden])')
-          .then(this.next);
-    },
-    // Wait for the 'copy' command to appear.
-    function() {
-      remoteCall
-          .waitForElement(
-              appId, '[command="#copy"]:not([hidden]):not([disabled])')
-          .then(this.next);
-    },
-    // Select 'copy'.
-    function() {
-      remoteCall.callRemoteTestUtil(
-          'fakeMouseClick', appId,
-          ['[command="#copy"]:not([hidden]):not([disabled])'], this.next);
-    },
-    // Wait for the context menu to disappear.
-    function(result) {
-      chrome.test.assertTrue(result);
-      remoteCall.waitForElement(appId, '#file-context-menu[hidden]')
-          .then(this.next);
-    },
-    // Check for Javascript errors.
-    function() {
-      checkIfNoErrorsOccured(this.next);
-      if (opt_callback)
-        opt_callback();
-    }
-  ]);
-}
-
-/**
  * Tests that the Delete menu item is enabled if a read-write entry is selected.
  */
 testcase.checkDeleteEnabledForReadWriteFile = function() {
@@ -307,23 +262,17 @@
 /**
  * Tests that the Paste into Folder menu item is enabled if a read-write folder
  * is selected.
- * TODO(sashab): Make this test only open one window, instead of two.
  */
 testcase.checkPasteIntoFolderEnabledForReadWriteFolder = function() {
-  copyEntryToClipboard('hello.txt', () => {
-    checkContextMenu('paste-into-folder', 'photos', true);
-  });
+  checkContextMenu('paste-into-folder', 'photos', true);
 };
 
 /**
  * Tests that the Paste into Folder menu item is disabled if a read-only folder
  * is selected.
- * TODO(sashab): Make this test only open one window, instead of two.
  */
 testcase.checkPasteIntoFolderDisabledForReadOnlyFolder = function() {
-  copyEntryToClipboard('hello.txt', () => {
-    checkContextMenu('paste-into-folder', 'Read-Only Folder', false);
-  });
+  checkContextMenu('paste-into-folder', 'Read-Only Folder', false);
 };
 
 /**
@@ -348,7 +297,7 @@
 testcase.checkContextMenusForInputElements = function() {
   let appId;
   StepsRunner.run([
-    // Start FilesApp.
+    // Open FilesApp on Downloads.
     function() {
       setupAndWaitUntilReady(null, RootPath.DOWNLOADS).then(this.next);
     },
@@ -430,15 +379,41 @@
     commandId, folderName, expectedEnabledState) {
   let appId;
   StepsRunner.run([
-    // Set up Files App.
+    // Open Files App on Drive.
     function() {
       setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, BASIC_LOCAL_ENTRY_SET,
-          COMPLEX_DRIVE_ENTRY_SET);
+          null, RootPath.DRIVE, this.next, [], COMPLEX_DRIVE_ENTRY_SET);
     },
-    // Select 'My Drive'.
+    // Optionally copy hello.txt into the clipboard if needed.
     function(results) {
       appId = results.windowId;
+
+      const needsClipboardCopy = /^paste/.test(commandId);
+      if (!needsClipboardCopy) {
+        this.next();
+        return;
+      }
+
+      const file = ['hello.txt'];
+      remoteCall.callRemoteTestUtil('selectFile', appId, file)
+          .then(result => {
+            chrome.test.assertTrue(!!result, 'selectFile failed');
+            return remoteCall.callRemoteTestUtil(
+                'execCommand', appId, ['copy']);
+          })
+          .then((result) => {
+            chrome.test.assertTrue(!!result, 'execCommand failed');
+            this.next();
+          });
+    },
+    // Focus the file list.
+    function() {
+      remoteCall.callRemoteTestUtil(
+          'focus', appId, ['#file-list:not([hidden])'], this.next);
+    },
+    // Select 'My Drive'.
+    function(result) {
+      chrome.test.assertTrue(!!result);
       remoteCall.callRemoteTestUtil(
           'selectFolderInTree', appId, ['My Drive'], this.next);
     },
@@ -467,11 +442,11 @@
     },
     // Wait for the command option to appear.
     function() {
-      let query;
+      let query = '#file-context-menu:not([hidden])';
       if (expectedEnabledState) {
-        query = `[command="#${commandId}"]:not([hidden]):not([disabled])`;
+        query += ` [command="#${commandId}"]:not([hidden]):not([disabled])`;
       } else {
-        query = `[command="#${commandId}"][disabled]:not([hidden])`;
+        query += ` [command="#${commandId}"][disabled]:not([hidden])`;
       }
       remoteCall.waitForElement(appId, query).then(this.next);
     },
@@ -501,26 +476,19 @@
 /**
  * Tests that the Paste menu item is enabled inside a folder that has read-write
  * permissions.
- * TODO(sashab): Make this test only open one window, instead of two.
  */
 testcase.checkPasteEnabledInsideReadWriteFolder = function() {
-  copyEntryToClipboard('hello.txt', () => {
-    checkContextMenuInDriveFolder('paste', 'photos', true);
-  });
+  checkContextMenuInDriveFolder('paste', 'photos', true);
 };
 
 /**
  * Tests that the Paste menu item is disabled inside a folder that has read-only
  * permissions.
- * TODO(sashab): Make this test only open one window, instead of two.
  */
 testcase.checkPasteDisabledInsideReadOnlyFolder = function() {
-  copyEntryToClipboard('hello.txt', () => {
-    checkContextMenuInDriveFolder('paste', 'Read-Only Folder', false);
-  });
+  checkContextMenuInDriveFolder('paste', 'Read-Only Folder', false);
 };
 
-
 /**
  * Tests that the specified menu item is in |expectedEnabledState| when the
  * context menu is opened from the directory tree. The tree item must be
@@ -536,15 +504,35 @@
     commandId, folderSelector, expectedEnabledState) {
   let appId;
   StepsRunner.run([
-    // Set up Files App.
+    // Open Files App on Drive.
     function() {
       setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, BASIC_LOCAL_ENTRY_SET,
-          COMPLEX_DRIVE_ENTRY_SET);
+          null, RootPath.DRIVE, this.next, [], COMPLEX_DRIVE_ENTRY_SET);
     },
-    // Set focus on the file list.
+    // Optionally copy hello.txt into the clipboard if needed.
     function(results) {
       appId = results.windowId;
+
+      const needsClipboardCopy = /^paste/.test(commandId);
+      if (!needsClipboardCopy) {
+        this.next();
+        return;
+      }
+
+      const file = ['hello.txt'];
+      remoteCall.callRemoteTestUtil('selectFile', appId, file)
+          .then(result => {
+            chrome.test.assertTrue(!!result, 'selectFile failed');
+            return remoteCall.callRemoteTestUtil(
+                'execCommand', appId, ['copy']);
+          })
+          .then((result) => {
+            chrome.test.assertTrue(!!result, 'execCommand failed');
+            this.next();
+          });
+    },
+    // Focus the file list.
+    function() {
       remoteCall.callRemoteTestUtil(
           'focus', appId, ['#file-list:not([hidden])'], this.next);
     },
@@ -572,7 +560,8 @@
           'focus', appId, ['#directory-tree'], this.next);
     },
     // Right-click the selected folder.
-    function() {
+    function(result) {
+      chrome.test.assertTrue(!!result);
       remoteCall.callRemoteTestUtil(
           'fakeMouseRightClick', appId,
           [`${folderSelector}:not([hidden]) .label`], this.next);
@@ -586,11 +575,11 @@
     },
     // Wait for the command option to appear.
     function() {
-      let query;
+      let query = '#directory-tree-context-menu:not([hidden])';
       if (expectedEnabledState) {
-        query = `[command="#${commandId}"]:not([hidden]):not([disabled])`;
+        query += ` [command="#${commandId}"]:not([hidden]):not([disabled])`;
       } else {
-        query = `[command="#${commandId}"][disabled]:not([hidden])`;
+        query += ` [command="#${commandId}"][disabled]:not([hidden])`;
       }
       remoteCall.waitForElement(appId, query).then(this.next);
     },
@@ -650,30 +639,24 @@
 /**
  * Tests that the Paste menu item is enabled in the directory
  * tree for a folder that has read-write permissions.
- * TODO(sashab): Make this test only open one window, instead of two.
  */
 testcase.checkPasteEnabledForReadWriteFolderInTree = function() {
-  copyEntryToClipboard('hello.txt', () => {
-    checkContextMenuForDriveFolderInTree(
-        'paste-into-folder',
-        '#directory-tree [full-path-for-testing="/root/photos"]:not([hidden])',
-        true);
-  });
+  checkContextMenuForDriveFolderInTree(
+      'paste-into-folder',
+      '#directory-tree [full-path-for-testing="/root/photos"]:not([hidden])',
+      true);
 };
 
 /**
  * Tests that the Paste menu item is disabled in the directory tree for a folder
  * that has read-only permissions.
- * TODO(sashab): Make this test only open one window, instead of two.
  */
 testcase.checkPasteDisabledForReadOnlyFolderInTree = function() {
-  copyEntryToClipboard('hello.txt', () => {
-    checkContextMenuForDriveFolderInTree(
-        'paste-into-folder',
-        '#directory-tree [full-path-for-testing="/root/Read-Only Folder"]' +
-            ':not([hidden])',
-        false);
-  });
+  checkContextMenuForDriveFolderInTree(
+      'paste-into-folder',
+      '#directory-tree [full-path-for-testing="/root/Read-Only Folder"]' +
+          ':not([hidden])',
+      false);
 };
 
 /**
@@ -695,13 +678,12 @@
       `.tree-item[full-path-for-testing="/team_drives/${teamDriveName}"]`;
   let appId;
   StepsRunner.run([
-    // Set up Files App.
+    // Open Files App on Drive.
     function() {
       setupAndWaitUntilReady(
-          null, RootPath.DRIVE, this.next, BASIC_LOCAL_ENTRY_SET,
-          TEAM_DRIVE_ENTRY_SET);
+          null, RootPath.DRIVE, this.next, [], TEAM_DRIVE_ENTRY_SET);
     },
-    // Set focus on the file list.
+    // Focus the file list.
     function(results) {
       appId = results.windowId;
       remoteCall.callRemoteTestUtil(
@@ -731,7 +713,8 @@
           'focus', appId, ['#directory-tree'], this.next);
     },
     // Right-click the selected team drive.
-    function() {
+    function(result) {
+      chrome.test.assertTrue(result);
       remoteCall.callRemoteTestUtil(
           'fakeMouseRightClick', appId,
           [`${navItemSelector}:not([hidden]) .label`], this.next);
@@ -745,16 +728,17 @@
     },
     // Wait for the command options to appear.
     function() {
-      let query;
       let promises = [];
       for (let commandId in expectedContextMenuState) {
+        let query = '#directory-tree-context-menu:not([hidden])';
         if (expectedContextMenuState[commandId] == true) {
-          query = `[command="#${commandId}"]:not([hidden]):not([disabled])`;
+          query += ` [command="#${commandId}"]:not([hidden]):not([disabled])`;
         } else {
-          query = `[command="#${commandId}"][disabled]:not([hidden])`;
+          query += ` [command="#${commandId}"][disabled]:not([hidden])`;
         }
         promises.push(remoteCall.waitForElement(appId, query));
       }
+
       Promise.all(promises).then(this.next);
     },
     // Check for Javascript errors.
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 8d5ba172..859a270 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -37,6 +37,7 @@
   ]
   deps = [
     "//base",
+    "//gpu/vulkan:buildflags",
     "//skia",
     "//ui/gfx/geometry",
   ]
diff --git a/ui/gfx/DEPS b/ui/gfx/DEPS
index 1fa6347..3a287d9 100644
--- a/ui/gfx/DEPS
+++ b/ui/gfx/DEPS
@@ -3,9 +3,11 @@
   "+cc/base",
   "+cc/paint",
   "+device/vr/buildflags/buildflags.h",
+  "+gpu/vulkan/buildflags.h",
   "+skia/ext",
   "+third_party/harfbuzz-ng",
   "+third_party/skia",
+  "+third_party/vulkan",
   "+ui/ios",
 
   "-testing/gmock",
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc
index 0a7116a..3c7f114 100644
--- a/ui/gfx/color_utils.cc
+++ b/ui/gfx/color_utils.cc
@@ -319,36 +319,60 @@
 
 SkColor GetColorWithMinimumContrast(SkColor default_foreground,
                                     SkColor background) {
-  DCHECK_EQ(SkColorGetA(default_foreground), SK_AlphaOPAQUE);
-
-  const float background_luminance = GetRelativeLuminance(background);
-  if (GetContrastRatio(GetRelativeLuminance(default_foreground),
-                       background_luminance) >= kMinimumReadableContrastRatio) {
-    return default_foreground;
-  }
-
   const SkColor blend_direction =
       IsDark(background) ? SK_ColorWHITE : g_color_utils_darkest;
-  // Binary search to find the smallest blend that gives us acceptable contrast.
-  SkAlpha lower_bound_alpha = SK_AlphaTRANSPARENT;
-  SkAlpha upper_bound_alpha = SK_AlphaOPAQUE;
-  SkColor best_color = blend_direction;
+  const SkAlpha alpha = GetBlendValueWithMinimumContrast(
+      default_foreground, blend_direction, background,
+      kMinimumReadableContrastRatio);
+  return AlphaBlend(blend_direction, default_foreground, alpha);
+}
+
+SkAlpha GetBlendValueWithMinimumContrast(SkColor source,
+                                         SkColor target,
+                                         SkColor base,
+                                         float contrast_ratio) {
+  DCHECK_EQ(SkColorGetA(base), SK_AlphaOPAQUE);
+
+  source = GetResultingPaintColor(source, base);
+  if (GetContrastRatio(source, base) >= contrast_ratio)
+    return 0;
+  target = GetResultingPaintColor(target, base);
+
   constexpr int kCloseEnoughAlphaDelta = 0x04;
-  while (lower_bound_alpha + kCloseEnoughAlphaDelta < upper_bound_alpha) {
-    const SkAlpha next_alpha =
-        gfx::ToCeiledInt((lower_bound_alpha + upper_bound_alpha) / 2.f);
-    const SkColor next_foreground =
-        AlphaBlend(blend_direction, default_foreground, next_alpha);
-    if (GetContrastRatio(GetRelativeLuminance(next_foreground),
-                         background_luminance) <
-        kMinimumReadableContrastRatio) {
-      lower_bound_alpha = next_alpha;
+  return FindBlendValueForContrastRatio(source, target, base, contrast_ratio,
+                                        kCloseEnoughAlphaDelta);
+}
+
+SkAlpha FindBlendValueForContrastRatio(SkColor source,
+                                       SkColor target,
+                                       SkColor base,
+                                       float contrast_ratio,
+                                       int alpha_error_tolerance) {
+  DCHECK_EQ(SkColorGetA(source), SK_AlphaOPAQUE);
+  DCHECK_EQ(SkColorGetA(target), SK_AlphaOPAQUE);
+  DCHECK_EQ(SkColorGetA(base), SK_AlphaOPAQUE);
+  DCHECK_GE(alpha_error_tolerance, 0);
+
+  const float base_luminance = GetRelativeLuminance(base);
+
+  // Use int for inclusive lower bound and exclusive upper bound, reserving
+  // conversion to SkAlpha for the end (reduces casts).
+  int low = SK_AlphaTRANSPARENT;
+  int high = SK_AlphaOPAQUE + 1;
+  int best = SK_AlphaOPAQUE;
+  while (low + alpha_error_tolerance < high) {
+    const int alpha = (low + high) / 2;
+    const SkColor blended = AlphaBlend(target, source, alpha);
+    const float luminance = GetRelativeLuminance(blended);
+    const float contrast = GetContrastRatio(luminance, base_luminance);
+    if (contrast >= contrast_ratio) {
+      best = alpha;
+      high = alpha;
     } else {
-      upper_bound_alpha = next_alpha;
-      best_color = next_foreground;
+      low = alpha + 1;
     }
   }
-  return best_color;
+  return best;
 }
 
 SkColor InvertColor(SkColor color) {
diff --git a/ui/gfx/color_utils.h b/ui/gfx/color_utils.h
index b7e524b..35d27484 100644
--- a/ui/gfx/color_utils.h
+++ b/ui/gfx/color_utils.h
@@ -130,10 +130,33 @@
 // |background|. If |default_foreground| already meets the minimum contrast
 // ratio, this function will simply return it. Otherwise it will blend the color
 // darker/lighter until either the contrast ratio is acceptable or the color
-// cannot become any more extreme. Only use with opaque colors.
+// cannot become any more extreme. Only use with opaque background.
 GFX_EXPORT SkColor GetColorWithMinimumContrast(SkColor default_foreground,
                                                SkColor background);
 
+// Attempts to select an alpha value such that blending |target| onto |source|
+// with that alpha produces a color of at least |contrast_ratio| against |base|.
+// If |source| already meets the minimum contrast ratio, this function will
+// simply return 0. Otherwise it will blend the |target| onto |source| until
+// either the contrast ratio is acceptable or the color cannot become any more
+// extreme. |base| must be opaque.
+GFX_EXPORT SkAlpha GetBlendValueWithMinimumContrast(SkColor source,
+                                                    SkColor target,
+                                                    SkColor base,
+                                                    float contrast_ratio);
+
+// Returns the minimum alpha value such that blending |target| onto |source|
+// produces a color that contrasts against |base| with at least |contrast_ratio|
+// unless this is impossible, in which case SK_AlphaOPAQUE is returned.
+// Use only with opaque colors. |alpha_error_tolerance| should normally be 0 for
+// best accuracy, but if performance is critical then it can be a positive value
+// (4 is recommended) to save a few cycles and give "close enough" alpha.
+GFX_EXPORT SkAlpha FindBlendValueForContrastRatio(SkColor source,
+                                                  SkColor target,
+                                                  SkColor base,
+                                                  float contrast_ratio,
+                                                  int alpha_error_tolerance);
+
 // Invert a color.
 GFX_EXPORT SkColor InvertColor(SkColor color);
 
diff --git a/ui/gfx/color_utils_unittest.cc b/ui/gfx/color_utils_unittest.cc
index 9d4b8d2..966205a 100644
--- a/ui/gfx/color_utils_unittest.cc
+++ b/ui/gfx/color_utils_unittest.cc
@@ -221,4 +221,37 @@
   SetDarkestColor(old_black_color);
 }
 
+TEST(ColorUtils, GetBlendValueWithMinimumContrast_ComputesExpectedOpacities) {
+  const SkColor source = SkColorSetRGB(0xDE, 0xE1, 0xE6);
+  const SkColor target = SkColorSetRGB(0xFF, 0xFF, 0xFF);
+  const SkColor base = source;
+  SkAlpha alpha = GetBlendValueWithMinimumContrast(source, target, base, 1.11f);
+  EXPECT_NEAR(alpha / 255.0f, 0.4f, 0.03f);
+  alpha = GetBlendValueWithMinimumContrast(source, target, base, 1.19f);
+  EXPECT_NEAR(alpha / 255.0f, 0.65f, 0.03f);
+  alpha = GetBlendValueWithMinimumContrast(source, target, base, 1.13728f);
+  EXPECT_NEAR(alpha / 255.0f, 0.45f, 0.03f);
+}
+
+TEST(ColorUtils, FindBlendValueForContrastRatio_MatchesNaiveImplementation) {
+  const SkColor source = SkColorSetRGB(0xDE, 0xE1, 0xE6);
+  const SkColor target = SkColorSetRGB(0xFF, 0xFF, 0xFF);
+  const SkColor base = source;
+  const float contrast_ratio = 1.11f;
+  const SkAlpha alpha =
+      FindBlendValueForContrastRatio(source, target, base, contrast_ratio, 0);
+
+  // Naive implementation is direct translation of function description.
+  SkAlpha check = SK_AlphaTRANSPARENT;
+  for (SkAlpha alpha = SK_AlphaTRANSPARENT; alpha <= SK_AlphaOPAQUE; ++alpha) {
+    const SkColor blended = AlphaBlend(target, source, alpha);
+    const float contrast = GetContrastRatio(blended, base);
+    check = alpha;
+    if (contrast >= contrast_ratio)
+      break;
+  }
+
+  EXPECT_EQ(check, alpha);
+}
+
 }  // namespace color_utils
diff --git a/ui/gfx/skia_util.cc b/ui/gfx/skia_util.cc
index 4379e76c..bcb5dde7 100644
--- a/ui/gfx/skia_util.cc
+++ b/ui/gfx/skia_util.cc
@@ -157,4 +157,37 @@
   return kFloatToHbRatio * value;
 }
 
+#if BUILDFLAG(ENABLE_VULKAN)
+VkFormat SkColorTypeToVkFormat(SkColorType color_type) {
+  switch (color_type) {
+    case kUnknown_SkColorType:
+      break;
+    case kAlpha_8_SkColorType:
+      return VK_FORMAT_R8_UNORM;
+    case kRGB_565_SkColorType:
+      return VK_FORMAT_R5G6B5_UNORM_PACK16;
+    case kARGB_4444_SkColorType:
+      return VK_FORMAT_B4G4R4A4_UNORM_PACK16;
+    case kRGBA_8888_SkColorType:
+      return VK_FORMAT_R8G8B8A8_UNORM;  // or VK_FORMAT_R8G8B8A8_SRGB
+    case kRGB_888x_SkColorType:  // Skia doesn't support it yet.
+      break;
+    case kBGRA_8888_SkColorType:
+      return VK_FORMAT_B8G8R8A8_UNORM;  // or VK_FORMAT_B8G8R8A8_SRGB
+    case kRGBA_1010102_SkColorType:
+      return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
+    case kGray_8_SkColorType:
+      return VK_FORMAT_R8_UNORM;
+    case kRGBA_F16_SkColorType:
+      return VK_FORMAT_R16G16B16A16_SFLOAT;
+    case kRGBA_F32_SkColorType:
+      return VK_FORMAT_R32G32B32A32_SFLOAT;
+    case kRGB_101010x_SkColorType:  // Skia doesn't support it yet.
+      break;
+  }
+  NOTREACHED();
+  return VK_FORMAT_UNDEFINED;
+}
+#endif
+
 }  // namespace gfx
diff --git a/ui/gfx/skia_util.h b/ui/gfx/skia_util.h
index d0efa6b..de6ed6d 100644
--- a/ui/gfx/skia_util.h
+++ b/ui/gfx/skia_util.h
@@ -8,12 +8,18 @@
 #include <string>
 #include <vector>
 
+#include "gpu/vulkan/buildflags.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkRect.h"
 #include "ui/gfx/geometry/quad_f.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gfx_export.h"
 
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/vulkan/include/vulkan/vulkan.h"
+#endif
+
 class SkBitmap;
 class SkMatrix;
 
@@ -62,6 +68,11 @@
 // Converts an hb_position_t to a float.
 GFX_EXPORT float HarfBuzzUnitsToFloat(int value);
 
+#if BUILDFLAG(ENABLE_VULKAN)
+// Converts a Skia color type to a compitable VkFormat
+GFX_EXPORT VkFormat SkColorTypeToVkFormat(SkColorType color_type);
+#endif
+
 }  // namespace gfx
 
 #endif  // UI_GFX_SKIA_UTIL_H_
diff --git a/ui/message_center/views/message_popup_view.cc b/ui/message_center/views/message_popup_view.cc
index 774e063..f71e43a 100644
--- a/ui/message_center/views/message_popup_view.cc
+++ b/ui/message_center/views/message_popup_view.cc
@@ -65,11 +65,17 @@
 MessagePopupView::~MessagePopupView() = default;
 
 void MessagePopupView::UpdateContents(const Notification& notification) {
+  ui::AXNodeData old_data;
+  message_view_->GetAccessibleNodeData(&old_data);
   message_view_->UpdateWithNotification(notification);
   popup_collection_->NotifyPopupResized();
   if (notification.rich_notification_data()
           .should_make_spoken_feedback_for_popup_updates) {
-    NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
+    ui::AXNodeData new_data;
+    message_view_->GetAccessibleNodeData(&new_data);
+    if (old_data.GetStringAttribute(ax::mojom::StringAttribute::kName) !=
+        new_data.GetStringAttribute(ax::mojom::StringAttribute::kName))
+      NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
   }
 }
 
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index 82d8ea92..c298ac455 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -299,17 +299,8 @@
 void MessageView::OnSlideChanged() {}
 
 void MessageView::OnSlideOut() {
-  // As a workaround for a MessagePopupCollection bug https://crbug.com/805208,
-  // pass false to by_user although it is triggered by user.
-  // TODO(tetsui): Rewrite MessagePopupCollection and remove this hack.
-  if (pinned_) {
-    // Also a workaround to not break notification pinning.
-    MessageCenter::Get()->MarkSinglePopupAsShown(
-        notification_id_, true /* mark_notification_as_read */);
-  } else {
-    MessageCenter::Get()->RemoveNotification(notification_id_,
-                                             true /* by_user */);
-  }
+  MessageCenter::Get()->RemoveNotification(notification_id_,
+                                           true /* by_user */);
 }
 
 SlideOutController::SlideMode MessageView::CalculateSlideMode() const {
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index 3c2d50c..192df8e 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -60,10 +60,10 @@
     "gpu/drm_window.h",
     "gpu/drm_window_proxy.cc",
     "gpu/drm_window_proxy.h",
-    "gpu/gbm_pixmap.cc",
-    "gpu/gbm_pixmap.h",
     "gpu/gbm_overlay_surface.cc",
     "gpu/gbm_overlay_surface.h",
+    "gpu/gbm_pixmap.cc",
+    "gpu/gbm_pixmap.h",
     "gpu/gbm_surface.cc",
     "gpu/gbm_surface.h",
     "gpu/gbm_surface_factory.cc",
@@ -90,8 +90,6 @@
     "gpu/page_flip_request.h",
     "gpu/proxy_helpers.cc",
     "gpu/proxy_helpers.h",
-    "gpu/drm_framebuffer.h",
-    "gpu/drm_framebuffer_generator.h",
     "gpu/screen_manager.cc",
     "gpu/screen_manager.h",
     "host/drm_cursor.cc",
@@ -184,10 +182,8 @@
     "gpu/hardware_display_plane_manager_unittest.cc",
     "gpu/mock_drm_device.cc",
     "gpu/mock_drm_device.h",
-    "gpu/mock_dumb_buffer_generator.cc",
-    "gpu/mock_dumb_buffer_generator.h",
-    "gpu/mock_drm_framebuffer_generator.cc",
-    "gpu/mock_drm_framebuffer_generator.h",
+    "gpu/mock_gbm_device.cc",
+    "gpu/mock_gbm_device.h",
     "gpu/proxy_helpers_unittest.cc",
     "gpu/screen_manager_unittest.cc",
   ]
diff --git a/ui/ozone/platform/drm/gpu/drm_framebuffer.cc b/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
index ab2737f..4ae423e 100644
--- a/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
+++ b/ui/ozone/platform/drm/gpu/drm_framebuffer.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
 
 #include "ui/ozone/common/linux/drm_util_linux.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
 #include "ui/ozone/platform/drm/gpu/drm_device.h"
 
@@ -48,6 +49,35 @@
       gfx::Size(params.width, params.height));
 }
 
+// static
+scoped_refptr<DrmFramebuffer> DrmFramebuffer::AddFramebuffer(
+    scoped_refptr<DrmDevice> drm,
+    const GbmBuffer* buffer) {
+  gfx::Size size = buffer->GetSize();
+  AddFramebufferParams params;
+  params.format = buffer->GetFormat();
+  params.modifier = buffer->GetFormatModifier();
+  params.width = size.width();
+  params.height = size.height();
+  params.num_planes = buffer->GetNumPlanes();
+  for (size_t i = 0; i < params.num_planes; ++i) {
+    params.handles[i] = buffer->GetPlaneHandle(i);
+    params.strides[i] = buffer->GetPlaneStride(i);
+    params.offsets[i] = buffer->GetPlaneOffset(i);
+  }
+
+  // AddFramebuffer2 only considers the modifiers if addfb_flags has
+  // DRM_MODE_FB_MODIFIERS set. We only set that when we've created
+  // a bo with modifiers, otherwise, we rely on the "no modifiers"
+  // behavior doing the right thing.
+  params.flags = 0;
+  if (drm->allow_addfb2_modifiers() &&
+      params.modifier != DRM_FORMAT_MOD_INVALID)
+    params.flags |= DRM_MODE_FB_MODIFIERS;
+
+  return AddFramebuffer(std::move(drm), params);
+}
+
 DrmFramebuffer::DrmFramebuffer(scoped_refptr<DrmDevice> drm_device,
                                uint32_t framebuffer_id,
                                uint32_t framebuffer_pixel_format,
diff --git a/ui/ozone/platform/drm/gpu/drm_framebuffer.h b/ui/ozone/platform/drm/gpu/drm_framebuffer.h
index c089cb3..bb5e6e3 100644
--- a/ui/ozone/platform/drm/gpu/drm_framebuffer.h
+++ b/ui/ozone/platform/drm/gpu/drm_framebuffer.h
@@ -15,6 +15,7 @@
 namespace ui {
 
 class DrmDevice;
+class GbmBuffer;
 
 // Abstraction for a DRM buffer that can be scanned-out of.
 class DrmFramebuffer : public base::RefCountedThreadSafe<DrmFramebuffer> {
@@ -35,6 +36,10 @@
       scoped_refptr<DrmDevice> drm_device,
       AddFramebufferParams params);
 
+  static scoped_refptr<DrmFramebuffer> AddFramebuffer(
+      scoped_refptr<DrmDevice> drm_device,
+      const GbmBuffer* buffer);
+
   DrmFramebuffer(scoped_refptr<DrmDevice> drm_device,
                  uint32_t framebuffer_id,
                  uint32_t framebuffer_pixel_format,
diff --git a/ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h b/ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h
deleted file mode 100644
index 04d8847..0000000
--- a/ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h
+++ /dev/null
@@ -1,31 +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 UI_OZONE_PLATFORM_DRM_GPU_SCANOUT_BUFFER_GENERATOR_H_
-#define UI_OZONE_PLATFORM_DRM_GPU_SCANOUT_BUFFER_GENERATOR_H_
-
-#include <vector>
-
-#include "base/memory/scoped_refptr.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace ui {
-
-class DrmDevice;
-class DrmFramebuffer;
-
-class DrmFramebufferGenerator {
- public:
-  virtual ~DrmFramebufferGenerator() {}
-
-  virtual scoped_refptr<DrmFramebuffer> Create(
-      const scoped_refptr<DrmDevice>& drm,
-      uint32_t format,
-      const std::vector<uint64_t>& modifiers,
-      const gfx::Size& size) = 0;
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRM_GPU_SCANOUT_BUFFER_GENERATOR_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
index 300aabe..ea0947a 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -10,10 +10,10 @@
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/ozone/common/linux/drm_util_linux.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
 #include "ui/ozone/platform/drm/gpu/drm_device.h"
 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 
@@ -25,7 +25,6 @@
     const scoped_refptr<DrmDevice>& drm_device,
     const gfx::Size& size,
     uint32_t format,
-    DrmFramebufferGenerator* buffer_generator,
     std::vector<scoped_refptr<DrmFramebuffer>>* reusable_buffers) {
   // Check if we can re-use existing buffers.
   for (const auto& buffer : *reusable_buffers) {
@@ -35,22 +34,24 @@
     }
   }
 
-  const std::vector<uint64_t>
-      modifiers;  // TODO(dcastagna): use the right modifiers.
-  scoped_refptr<DrmFramebuffer> drm_framebuffer =
-      buffer_generator->Create(drm_device, format, modifiers, size);
-  if (drm_framebuffer)
-    reusable_buffers->push_back(drm_framebuffer);
+  // TODO(dcastagna): use the right modifiers.
+  std::unique_ptr<GbmBuffer> buffer =
+      drm_device->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT);
+  if (!buffer)
+    return nullptr;
 
+  scoped_refptr<DrmFramebuffer> drm_framebuffer =
+      DrmFramebuffer::AddFramebuffer(drm_device, buffer.get());
+  if (!drm_framebuffer)
+    return nullptr;
+
+  reusable_buffers->push_back(drm_framebuffer);
   return drm_framebuffer;
 }
 
 }  // namespace
 
-DrmOverlayValidator::DrmOverlayValidator(
-    DrmWindow* window,
-    DrmFramebufferGenerator* buffer_generator)
-    : window_(window), buffer_generator_(buffer_generator) {}
+DrmOverlayValidator::DrmOverlayValidator(DrmWindow* window) : window_(window) {}
 
 DrmOverlayValidator::~DrmOverlayValidator() {}
 
@@ -82,8 +83,7 @@
 
     scoped_refptr<DrmFramebuffer> buffer = GetBufferForPageFlipTest(
         drm, params[i].buffer_size,
-        GetFourCCFormatFromBufferFormat(params[i].format), buffer_generator_,
-        &reusable_buffers);
+        GetFourCCFormatFromBufferFormat(params[i].format), &reusable_buffers);
 
     DrmOverlayPlane plane(buffer, params[i].plane_z_order, params[i].transform,
                           params[i].display_rect, params[i].crop_rect,
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator.h b/ui/ozone/platform/drm/gpu/drm_overlay_validator.h
index 1304559..5030650 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator.h
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator.h
@@ -11,14 +11,12 @@
 namespace ui {
 
 class DrmWindow;
-class DrmFramebufferGenerator;
 struct OverlayCheck_Params;
 struct OverlayCheckReturn_Params;
 
 class DrmOverlayValidator {
  public:
-  DrmOverlayValidator(DrmWindow* window,
-                      DrmFramebufferGenerator* buffer_generator);
+  DrmOverlayValidator(DrmWindow* window);
   ~DrmOverlayValidator();
 
   // Tests if configurations |params| are compatible with |window_| and finds
@@ -30,7 +28,6 @@
 
  private:
   DrmWindow* window_;  // Not owned.
-  DrmFramebufferGenerator* buffer_generator_;  // Not owned.
 
   DISALLOW_COPY_AND_ASSIGN(DrmOverlayValidator);
 };
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index 977207d..c2a99d7 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -15,14 +15,16 @@
 #include "ui/gfx/gpu_fence.h"
 #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
 #include "ui/ozone/common/linux/drm_util_linux.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h"
+#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 
 namespace {
@@ -62,8 +64,16 @@
   void AddPlane(const ui::OverlayCheck_Params& params);
 
   scoped_refptr<ui::DrmFramebuffer> CreateBuffer() {
-    return buffer_generator_->CreateWithModifier(
-        drm_, DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_NONE, primary_rect_.size());
+    auto gbm_buffer = drm_->gbm_device()->CreateBuffer(
+        DRM_FORMAT_XRGB8888, primary_rect_.size(), GBM_BO_USE_SCANOUT);
+    return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get());
+  }
+
+  scoped_refptr<ui::DrmFramebuffer> CreateOverlayBuffer(uint32_t format,
+                                                        const gfx::Size& size) {
+    auto gbm_buffer =
+        drm_->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT);
+    return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get());
   }
 
  protected:
@@ -79,7 +89,7 @@
 
   std::unique_ptr<base::MessageLoop> message_loop_;
   scoped_refptr<ui::MockDrmDevice> drm_;
-  std::unique_ptr<ui::MockDrmFramebufferGenerator> buffer_generator_;
+  ui::MockGbmDevice* gbm_ = nullptr;
   std::unique_ptr<ui::ScreenManager> screen_manager_;
   std::unique_ptr<ui::DrmDeviceManager> drm_device_manager_;
   ui::DrmWindow* window_;
@@ -101,15 +111,16 @@
   last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED;
 
   message_loop_.reset(new base::MessageLoopForUI);
-  drm_ = new ui::MockDrmDevice;
+  auto gbm = std::make_unique<ui::MockGbmDevice>();
+  gbm_ = gbm.get();
+  drm_ = new ui::MockDrmDevice(std::move(gbm));
 
   CrtcState crtc_state = {.planes = {
                               {.formats = {DRM_FORMAT_XRGB8888}},
                           }};
   InitializeDrmState({crtc_state});
 
-  buffer_generator_.reset(new ui::MockDrmFramebufferGenerator());
-  screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
+  screen_manager_.reset(new ui::ScreenManager());
   screen_manager_->AddDisplayController(drm_, kCrtcIdBase, kConnectorIdBase);
   screen_manager_->ConfigureDisplayController(
       drm_, kCrtcIdBase, kConnectorIdBase, gfx::Point(), kDefaultMode);
@@ -118,13 +129,12 @@
 
   std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
       kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(
       gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
   screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window));
   window_ = screen_manager_->GetWindow(kDefaultWidgetHandle);
-  overlay_validator_.reset(
-      new ui::DrmOverlayValidator(window_, buffer_generator_.get()));
+  overlay_validator_.reset(new ui::DrmOverlayValidator(window_));
 
   overlay_rect_ =
       gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2);
@@ -210,9 +220,9 @@
 
 void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) {
   scoped_refptr<ui::DrmDevice> drm = window_->GetController()->GetDrmDevice();
-  scoped_refptr<ui::DrmFramebuffer> drm_framebuffer = buffer_generator_->Create(
-      drm, ui::GetFourCCFormatFromBufferFormat(params.format), {},
-      params.buffer_size);
+
+  scoped_refptr<ui::DrmFramebuffer> drm_framebuffer = CreateOverlayBuffer(
+      ui::GetFourCCFormatFromBufferFormat(params.format), params.buffer_size);
   plane_list_.push_back(ui::DrmOverlayPlane(
       std::move(drm_framebuffer), params.plane_z_order, params.transform,
       params.display_rect, params.crop_rect, true, nullptr));
@@ -469,7 +479,7 @@
 TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) {
   // Buffer allocation for scanout might fail.
   // In that case we should reject the overlay candidate.
-  buffer_generator_->set_allocation_failure(true);
+  gbm_->set_allocation_failure(true);
 
   std::vector<ui::OverlayCheckReturn_Params> returns =
       overlay_validator_->TestPageFlip(overlay_params_,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index 4291a31c9..5e466191 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -22,7 +22,6 @@
 #include "ui/ozone/platform/drm/gpu/drm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
 #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
@@ -36,34 +35,6 @@
 
 namespace {
 
-scoped_refptr<DrmFramebuffer> AddFramebuffersForBuffer(
-    const scoped_refptr<DrmDevice>& drm,
-    GbmBuffer* buffer) {
-  gfx::Size size = buffer->GetSize();
-  DrmFramebuffer::AddFramebufferParams params;
-  params.format = buffer->GetFormat();
-  params.modifier = buffer->GetFormatModifier();
-  params.width = size.width();
-  params.height = size.height();
-  params.num_planes = buffer->GetNumPlanes();
-  for (size_t i = 0; i < params.num_planes; ++i) {
-    params.handles[i] = buffer->GetPlaneHandle(i);
-    params.strides[i] = buffer->GetPlaneStride(i);
-    params.offsets[i] = buffer->GetPlaneOffset(i);
-  }
-
-  // AddFramebuffer2 only considers the modifiers if addfb_flags has
-  // DRM_MODE_FB_MODIFIERS set. We only set that when we've created
-  // a bo with modifiers, otherwise, we rely on the "no modifiers"
-  // behavior doing the right thing.
-  params.flags = 0;
-  if (drm->allow_addfb2_modifiers() &&
-      params.modifier != DRM_FORMAT_MOD_INVALID)
-    params.flags |= DRM_MODE_FB_MODIFIERS;
-
-  return DrmFramebuffer::AddFramebuffer(drm, params);
-}
-
 uint32_t BufferUsageToGbmFlags(gfx::BufferUsage usage) {
   switch (usage) {
     case gfx::BufferUsage::GPU_READ:
@@ -106,7 +77,7 @@
 
   scoped_refptr<DrmFramebuffer> framebuffer;
   if (flags & GBM_BO_USE_SCANOUT) {
-    framebuffer = AddFramebuffersForBuffer(drm, buffer.get());
+    framebuffer = DrmFramebuffer::AddFramebuffer(drm, buffer.get());
     if (!framebuffer)
       return;
   }
@@ -115,36 +86,6 @@
   *out_framebuffer = std::move(framebuffer);
 }
 
-class GbmBufferGenerator : public DrmFramebufferGenerator {
- public:
-  GbmBufferGenerator() {}
-  ~GbmBufferGenerator() override {}
-
-  // DrmFramebufferGenerator:
-  scoped_refptr<DrmFramebuffer> Create(const scoped_refptr<DrmDevice>& drm,
-                                       uint32_t format,
-                                       const std::vector<uint64_t>& modifiers,
-                                       const gfx::Size& size) override {
-    std::unique_ptr<GbmBuffer> buffer;
-
-    if (modifiers.size() > 0) {
-      buffer = drm->gbm_device()->CreateBufferWithModifiers(
-          format, size, GBM_BO_USE_SCANOUT, modifiers);
-    } else {
-      buffer =
-          drm->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT);
-    }
-
-    if (!buffer)
-      return nullptr;
-
-    return AddFramebuffersForBuffer(drm, buffer.get());
-  }
-
- protected:
-  DISALLOW_COPY_AND_ASSIGN(GbmBufferGenerator);
-};
-
 class GbmDeviceGenerator : public DrmDeviceGenerator {
  public:
   GbmDeviceGenerator() {}
@@ -193,8 +134,7 @@
 void DrmThread::Init() {
   device_manager_.reset(
       new DrmDeviceManager(std::make_unique<GbmDeviceGenerator>()));
-  buffer_generator_.reset(new GbmBufferGenerator());
-  screen_manager_.reset(new ScreenManager(buffer_generator_.get()));
+  screen_manager_.reset(new ScreenManager());
 
   display_manager_.reset(
       new DrmGpuDisplayManager(screen_manager_.get(), device_manager_.get()));
@@ -262,7 +202,7 @@
 
   scoped_refptr<DrmFramebuffer> framebuffer;
   if (buffer->GetFlags() & GBM_BO_USE_SCANOUT) {
-    framebuffer = AddFramebuffersForBuffer(drm, buffer.get());
+    framebuffer = DrmFramebuffer::AddFramebuffer(drm, buffer.get());
     if (!framebuffer)
       return;
   }
@@ -328,7 +268,7 @@
 void DrmThread::CreateWindow(gfx::AcceleratedWidget widget) {
   std::unique_ptr<DrmWindow> window(
       new DrmWindow(widget, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   screen_manager_->AddWindow(widget, std::move(window));
 }
 
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index b1c954eb..79685b1 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -44,7 +44,6 @@
 class DrmFramebuffer;
 class DrmGpuDisplayManager;
 class GbmBuffer;
-class DrmFramebufferGenerator;
 class ScreenManager;
 
 struct DrmOverlayPlane;
@@ -155,7 +154,6 @@
                                 std::vector<DrmOverlayPlane> planes);
 
   std::unique_ptr<DrmDeviceManager> device_manager_;
-  std::unique_ptr<DrmFramebufferGenerator> buffer_generator_;
   std::unique_ptr<ScreenManager> screen_manager_;
   std::unique_ptr<DrmGpuDisplayManager> display_manager_;
 
diff --git a/ui/ozone/platform/drm/gpu/drm_window.cc b/ui/ozone/platform/drm/gpu/drm_window.cc
index 1c0dc3dc..04f31690 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -37,12 +37,11 @@
 DrmWindow::~DrmWindow() {
 }
 
-void DrmWindow::Initialize(DrmFramebufferGenerator* buffer_generator) {
+void DrmWindow::Initialize() {
   TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_);
 
   device_manager_->UpdateDrmDevice(widget_, nullptr);
-  overlay_validator_ =
-      std::make_unique<DrmOverlayValidator>(this, buffer_generator);
+  overlay_validator_ = std::make_unique<DrmOverlayValidator>(this);
 }
 
 void DrmWindow::Shutdown() {
diff --git a/ui/ozone/platform/drm/gpu/drm_window.h b/ui/ozone/platform/drm/gpu/drm_window.h
index 236eefa0..b44d416 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/ui/ozone/platform/drm/gpu/drm_window.h
@@ -33,7 +33,6 @@
 class HardwareDisplayController;
 struct OverlayCheck_Params;
 struct OverlayCheckReturn_Params;
-class DrmFramebufferGenerator;
 class ScreenManager;
 
 // The GPU object representing a window.
@@ -55,7 +54,7 @@
 
   gfx::Rect bounds() const { return bounds_; }
 
-  void Initialize(DrmFramebufferGenerator* buffer_generator);
+  void Initialize();
 
   void Shutdown();
 
diff --git a/ui/ozone/platform/drm/gpu/drm_window_unittest.cc b/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
index fd5d379c..fdd4af7 100644
--- a/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window_unittest.cc
@@ -21,12 +21,13 @@
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gfx/presentation_feedback.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.h"
+#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
@@ -85,7 +86,6 @@
  protected:
   std::unique_ptr<base::MessageLoop> message_loop_;
   scoped_refptr<ui::MockDrmDevice> drm_;
-  std::unique_ptr<ui::MockDumbBufferGenerator> buffer_generator_;
   std::unique_ptr<ui::ScreenManager> screen_manager_;
   std::unique_ptr<ui::DrmDeviceManager> drm_device_manager_;
 
@@ -102,9 +102,9 @@
   last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED;
 
   message_loop_.reset(new base::MessageLoopForUI);
-  drm_ = new ui::MockDrmDevice;
-  buffer_generator_.reset(new ui::MockDumbBufferGenerator());
-  screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
+  auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+  drm_ = new ui::MockDrmDevice(std::move(gbm_device));
+  screen_manager_.reset(new ui::ScreenManager());
   screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector);
   screen_manager_->ConfigureDisplayController(
       drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
@@ -113,7 +113,7 @@
 
   std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
       kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(
       gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
   screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window));
@@ -159,7 +159,9 @@
                   gfx::Point(4, 2), 0);
 
   // Add another device.
-  scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice;
+  auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+  scoped_refptr<ui::MockDrmDevice> drm =
+      new ui::MockDrmDevice(std::move(gbm_device));
   screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector);
   screen_manager_->ConfigureDisplayController(
       drm, kDefaultCrtc, kDefaultConnector,
@@ -177,11 +179,13 @@
 
 TEST_F(DrmWindowTest, CheckDeathOnFailedSwap) {
   const gfx::Size window_size(6, 4);
-  ui::MockDumbBufferGenerator buffer_generator;
   ui::DrmWindow* window = screen_manager_->GetWindow(kDefaultWidgetHandle);
-  ui::DrmOverlayPlane plane(
-      buffer_generator.Create(drm_, DRM_FORMAT_XRGB8888, {}, window_size),
-      nullptr);
+
+  std::unique_ptr<ui::GbmBuffer> buffer = drm_->gbm_device()->CreateBuffer(
+      DRM_FORMAT_XRGB8888, window_size, GBM_BO_USE_SCANOUT);
+  scoped_refptr<ui::DrmFramebuffer> framebuffer =
+      ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get());
+  ui::DrmOverlayPlane plane(framebuffer, nullptr);
 
   drm_->set_page_flip_expectation(false);
 
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
index 0a4c75cb..662d7232 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller_unittest.cc
@@ -13,12 +13,14 @@
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gfx/presentation_feedback.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h"
+#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h"
 
 namespace {
 
@@ -57,17 +59,18 @@
                                  const std::string& property_name);
 
   scoped_refptr<ui::DrmFramebuffer> CreateBuffer() {
-    return buffer_generator_->CreateWithModifier(
-        drm_, DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_NONE, kDefaultModeSize);
+    std::unique_ptr<ui::GbmBuffer> buffer = drm_->gbm_device()->CreateBuffer(
+        DRM_FORMAT_XRGB8888, kDefaultModeSize, GBM_BO_USE_SCANOUT);
+    return ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get());
   }
 
   scoped_refptr<ui::DrmFramebuffer> CreateOverlayBuffer() {
-    return buffer_generator_->CreateWithModifier(
-        drm_, DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_NONE, kOverlaySize);
+    std::unique_ptr<ui::GbmBuffer> buffer = drm_->gbm_device()->CreateBuffer(
+        DRM_FORMAT_XRGB8888, kOverlaySize, GBM_BO_USE_SCANOUT);
+    return ui::DrmFramebuffer::AddFramebuffer(drm_, buffer.get());
   }
 
  protected:
-  std::unique_ptr<ui::MockDrmFramebufferGenerator> buffer_generator_;
   std::unique_ptr<ui::HardwareDisplayController> controller_;
   scoped_refptr<ui::MockDrmDevice> drm_;
 
@@ -83,10 +86,10 @@
   page_flips_ = 0;
   last_swap_result_ = gfx::SwapResult::SWAP_FAILED;
 
-  drm_ = new ui::MockDrmDevice;
+  auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+  drm_ = new ui::MockDrmDevice(std::move(gbm_device));
   InitializeDrmDevice(/* use_atomic= */ true);
 
-  buffer_generator_.reset(new ui::MockDrmFramebufferGenerator());
   controller_.reset(new ui::HardwareDisplayController(
       std::unique_ptr<ui::CrtcController>(
           new ui::CrtcController(drm_.get(), kPrimaryCrtc, kPrimaryConnector)),
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index 7944c60..177a262 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -17,13 +17,15 @@
 #include "ui/display/types/gamma_ramp_rgb_entry.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gfx/gpu_fence_handle.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_atomic.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h"
+#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h"
 
 namespace {
 
@@ -62,21 +64,20 @@
   void SetUp() override;
 
   scoped_refptr<ui::DrmFramebuffer> CreateBuffer(const gfx::Size& size) {
-    return buffer_generator_->CreateWithModifier(fake_drm_, DRM_FORMAT_XRGB8888,
-                                                 DRM_FORMAT_MOD_NONE, size);
+    return CreateBufferWithFormat(size, DRM_FORMAT_XRGB8888);
   }
 
   scoped_refptr<ui::DrmFramebuffer> CreateBufferWithFormat(
       const gfx::Size& size,
       uint32_t format) {
-    return buffer_generator_->CreateWithModifier(fake_drm_, format,
-                                                 DRM_FORMAT_MOD_NONE, size);
+    std::unique_ptr<ui::GbmBuffer> buffer =
+        fake_drm_->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT);
+    return ui::DrmFramebuffer::AddFramebuffer(fake_drm_, buffer.get());
   }
 
  protected:
   ui::HardwareDisplayPlaneList state_;
   scoped_refptr<ui::DrmFramebuffer> fake_buffer_;
-  std::unique_ptr<ui::MockDrmFramebufferGenerator> buffer_generator_;
   scoped_refptr<ui::MockDrmDevice> fake_drm_;
 
   std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties_;
@@ -91,9 +92,9 @@
 
 void HardwareDisplayPlaneManagerTest::SetUp() {
   use_atomic_ = GetParam();
-  buffer_generator_.reset(new ui::MockDrmFramebufferGenerator());
 
-  fake_drm_ = new ui::MockDrmDevice;
+  auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+  fake_drm_ = new ui::MockDrmDevice(std::move(gbm_device));
   fake_drm_->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
       kInFormatsBlobPropId, {DRM_FORMAT_XRGB8888}, {}));
 
@@ -298,7 +299,7 @@
 TEST_P(HardwareDisplayPlaneManagerLegacyTest, CheckFramebufferFormatMatch) {
   ui::DrmOverlayPlaneList assigns;
   scoped_refptr<ui::DrmFramebuffer> buffer =
-      CreateBufferWithFormat(kDefaultBufferSize, DRM_FORMAT_NV12);
+      CreateBufferWithFormat(kDefaultBufferSize, DRM_FORMAT_UYVY);
   assigns.push_back(ui::DrmOverlayPlane(buffer, nullptr));
 
   InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
@@ -782,8 +783,8 @@
   HardwareDisplayPlaneManagerPlanesReadyTest() {}
 
   void SetUp() override {
-    fake_drm_ = new ui::MockDrmDevice;
-    buffer_generator_.reset(new ui::MockDrmFramebufferGenerator());
+    auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+    fake_drm_ = new ui::MockDrmDevice(std::move(gbm_device));
     drm_framebuffer_ = CreateBuffer(kDefaultBufferSize);
     planes_without_fences_ = CreatePlanesWithoutFences();
     planes_with_fences_ = CreatePlanesWithFences();
@@ -794,8 +795,10 @@
   void RequestPlanesReady(ui::DrmOverlayPlaneList planes);
 
   scoped_refptr<ui::DrmFramebuffer> CreateBuffer(const gfx::Size& size) {
-    return buffer_generator_->CreateWithModifier(fake_drm_, DRM_FORMAT_XRGB8888,
-                                                 DRM_FORMAT_MOD_NONE, size);
+    std::unique_ptr<ui::GbmBuffer> buffer =
+        fake_drm_->gbm_device()->CreateBuffer(DRM_FORMAT_XRGB8888, size,
+                                              GBM_BO_USE_SCANOUT);
+    return ui::DrmFramebuffer::AddFramebuffer(fake_drm_, buffer.get());
   }
 
   ui::DrmOverlayPlaneList CreatePlanesWithoutFences() {
@@ -817,7 +820,6 @@
   }
 
   scoped_refptr<ui::MockDrmDevice> fake_drm_;
-  std::unique_ptr<ui::MockDrmFramebufferGenerator> buffer_generator_;
   std::unique_ptr<ui::HardwareDisplayPlaneManager> plane_manager_;
   bool callback_called = false;
   base::test::ScopedTaskEnvironment task_env_{
@@ -926,24 +928,26 @@
 TEST(HardwareDisplayPlaneManagerAtomic, EnableBlend) {
   auto plane_manager =
       std::make_unique<ui::HardwareDisplayPlaneManagerAtomic>();
-  auto drm_device = base::MakeRefCounted<ui::MockDrmDevice>();
-  auto buffer_generator = std::make_unique<ui::MockDrmFramebufferGenerator>();
+  auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+  auto drm_device =
+      base::MakeRefCounted<ui::MockDrmDevice>(std::move(gbm_device));
   ui::HardwareDisplayPlaneList plane_list;
   HardwareDisplayPlaneAtomicMock hw_plane;
-  scoped_refptr<ui::DrmFramebuffer> buffer =
-      buffer_generator->CreateWithModifier(
-          drm_device.get(), DRM_FORMAT_XRGB8888, DRM_FORMAT_MOD_NONE,
-          kDefaultBufferSize);
-  ui::DrmOverlayPlane overlay(buffer, nullptr);
+  std::unique_ptr<ui::GbmBuffer> buffer =
+      drm_device->gbm_device()->CreateBuffer(
+          DRM_FORMAT_XRGB8888, kDefaultBufferSize, GBM_BO_USE_SCANOUT);
+  scoped_refptr<ui::DrmFramebuffer> framebuffer =
+      ui::DrmFramebuffer::AddFramebuffer(drm_device, buffer.get());
+  ui::DrmOverlayPlane overlay(framebuffer, nullptr);
   overlay.enable_blend = true;
   plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect(),
                               nullptr);
-  EXPECT_EQ(hw_plane.framebuffer(), buffer->framebuffer_id());
+  EXPECT_EQ(hw_plane.framebuffer(), framebuffer->framebuffer_id());
 
   overlay.enable_blend = false;
   plane_manager->SetPlaneData(&plane_list, &hw_plane, overlay, 1, gfx::Rect(),
                               nullptr);
-  EXPECT_EQ(hw_plane.framebuffer(), buffer->opaque_framebuffer_id());
+  EXPECT_EQ(hw_plane.framebuffer(), framebuffer->opaque_framebuffer_id());
 }
 
 }  // namespace
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
index abdc7adc..4b7f5a46 100644
--- a/ui/ozone/platform/drm/gpu/mock_drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -73,11 +73,11 @@
     default;
 MockDrmDevice::PlaneProperties::~PlaneProperties() = default;
 
-MockDrmDevice::MockDrmDevice()
+MockDrmDevice::MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device)
     : DrmDevice(base::FilePath(),
                 base::File(),
                 true /* is_primary_device */,
-                nullptr),
+                std::move(gbm_device)),
       get_crtc_call_count_(0),
       set_crtc_call_count_(0),
       restore_crtc_call_count_(0),
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.h b/ui/ozone/platform/drm/gpu/mock_drm_device.h
index 95ad0398..2e705d0 100644
--- a/ui/ozone/platform/drm/gpu/mock_drm_device.h
+++ b/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -44,7 +44,7 @@
     std::vector<DrmDevice::Property> properties;
   };
 
-  MockDrmDevice();
+  MockDrmDevice(std::unique_ptr<GbmDevice> gbm_device);
 
   static ScopedDrmPropertyBlobPtr AllocateInFormatsBlob(
       uint32_t id,
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.cc b/ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.cc
deleted file mode 100644
index 41fb7ba..0000000
--- a/ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h"
-
-#include <drm_fourcc.h>
-
-#include "ui/ozone/platform/drm/common/drm_util.h"
-#include "ui/ozone/platform/drm/gpu/drm_device.h"
-
-namespace ui {
-
-namespace {
-
-uint32_t g_current_mock_buffer_handle = 0x1111;
-
-}  // namespace
-
-MockDrmFramebufferGenerator::MockDrmFramebufferGenerator() {}
-
-MockDrmFramebufferGenerator::~MockDrmFramebufferGenerator() {}
-
-scoped_refptr<DrmFramebuffer> MockDrmFramebufferGenerator::Create(
-    const scoped_refptr<DrmDevice>& drm,
-    uint32_t format,
-    const std::vector<uint64_t>& modifiers,
-    const gfx::Size& size) {
-  return CreateWithModifier(
-      drm, format, modifiers.empty() ? DRM_FORMAT_MOD_NONE : modifiers.front(),
-      size);
-}
-
-scoped_refptr<DrmFramebuffer> MockDrmFramebufferGenerator::CreateWithModifier(
-    const scoped_refptr<DrmDevice>& drm,
-    uint32_t format,
-    uint64_t modifier,
-    const gfx::Size& size) {
-  if (allocation_failure_)
-    return nullptr;
-
-  DrmFramebuffer::AddFramebufferParams params;
-  params.format = format;
-  params.modifier = modifier;
-  params.width = size.width();
-  params.height = size.height();
-  params.num_planes = 1;
-  params.handles[0] = g_current_mock_buffer_handle++;
-
-  return DrmFramebuffer::AddFramebuffer(drm, params);
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h b/ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h
deleted file mode 100644
index 4b3e8cb..0000000
--- a/ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_DRM_GPU_MOCK_SCANOUT_BUFFER_GENERATOR_H_
-#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_SCANOUT_BUFFER_GENERATOR_H_
-
-#include "base/macros.h"
-
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h"
-
-namespace ui {
-
-class MockDrmFramebufferGenerator : public DrmFramebufferGenerator {
- public:
-  MockDrmFramebufferGenerator();
-  ~MockDrmFramebufferGenerator() override;
-
-  // DrmFramebufferGenerator:
-  scoped_refptr<DrmFramebuffer> Create(const scoped_refptr<DrmDevice>& drm,
-                                       uint32_t format,
-                                       const std::vector<uint64_t>& modifiers,
-                                       const gfx::Size& size) override;
-
-  scoped_refptr<DrmFramebuffer> CreateWithModifier(
-      const scoped_refptr<DrmDevice>& drm,
-      uint32_t format,
-      uint64_t modifier,
-      const gfx::Size& size);
-
-  void set_allocation_failure(bool allocation_failure) {
-    allocation_failure_ = allocation_failure;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockDrmFramebufferGenerator);
-
-  bool allocation_failure_ = false;
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRM_GPU_MOCK_SCANOUT_BUFFER_GENERATOR_H_
diff --git a/ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.cc b/ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.cc
deleted file mode 100644
index 2934559..0000000
--- a/ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.h"
-
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
-#include "ui/ozone/platform/drm/gpu/drm_device.h"
-
-namespace ui {
-
-namespace {
-
-uint32_t GetFourCCCodeForSkColorType(SkColorType type) {
-  switch (type) {
-    case kUnknown_SkColorType:
-    case kAlpha_8_SkColorType:
-      return 0;
-    case kRGB_565_SkColorType:
-      return DRM_FORMAT_RGB565;
-    case kARGB_4444_SkColorType:
-      return DRM_FORMAT_ARGB4444;
-    case kN32_SkColorType:
-      return DRM_FORMAT_ARGB8888;
-    default:
-      NOTREACHED();
-      return 0;
-  }
-}
-
-scoped_refptr<DrmFramebuffer> AddFramebufferForDumbBuffer(
-    const scoped_refptr<DrmDevice>& drm,
-    uint32_t handle,
-    uint32_t stride,
-    const SkImageInfo& info) {
-  DrmFramebuffer::AddFramebufferParams params;
-  params.flags = 0;
-  params.format = GetFourCCCodeForSkColorType(info.colorType());
-  params.modifier = DRM_FORMAT_MOD_INVALID;
-  params.width = info.width();
-  params.height = info.height();
-  params.num_planes = 1;
-  params.handles[0] = handle;
-  params.strides[0] = stride;
-  return DrmFramebuffer::AddFramebuffer(drm, params);
-}
-
-}  // namespace
-
-MockDumbBufferGenerator::MockDumbBufferGenerator() {}
-
-MockDumbBufferGenerator::~MockDumbBufferGenerator() {}
-
-scoped_refptr<DrmFramebuffer> MockDumbBufferGenerator::Create(
-    const scoped_refptr<DrmDevice>& drm,
-    uint32_t format,
-    const std::vector<uint64_t>& modifiers,
-    const gfx::Size& size) {
-  std::unique_ptr<DrmBuffer> buffer(new DrmBuffer(drm));
-  SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
-  if (!buffer->Initialize(info))
-    return NULL;
-
-  return AddFramebufferForDumbBuffer(drm, buffer->GetHandle(), buffer->stride(),
-                                     info);
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.h b/ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.h
deleted file mode 100644
index 9fe8f4d..0000000
--- a/ui/ozone/platform/drm/gpu/mock_dumb_buffer_generator.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_DRM_GPU_MOCK_DUMB_BUFFER_GENERATOR_H_
-#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_DUMB_BUFFER_GENERATOR_H_
-
-#include "base/macros.h"
-
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h"
-
-namespace ui {
-
-class DrmFramebuffer;
-
-class MockDumbBufferGenerator : public DrmFramebufferGenerator {
- public:
-  MockDumbBufferGenerator();
-  ~MockDumbBufferGenerator() override;
-
-  // DrmFramebufferGenerator:
-  scoped_refptr<DrmFramebuffer> Create(const scoped_refptr<DrmDevice>& drm,
-                                       uint32_t format,
-                                       const std::vector<uint64_t>& modifiers,
-                                       const gfx::Size& size) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockDumbBufferGenerator);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRM_GPU_MOCK_DUMB_BUFFER_GENERATOR_H_
diff --git a/ui/ozone/platform/drm/gpu/mock_gbm_device.cc b/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
new file mode 100644
index 0000000..d7b298f
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/mock_gbm_device.cc
@@ -0,0 +1,161 @@
+// 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 "ui/ozone/platform/drm/gpu/mock_gbm_device.h"
+
+#include <drm_fourcc.h>
+#include <xf86drm.h>
+
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/ozone/common/linux/drm_util_linux.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
+
+namespace ui {
+namespace {
+
+class MockGbmBuffer final : public ui::GbmBuffer {
+ public:
+  MockGbmBuffer(uint32_t format,
+                uint32_t flags,
+                uint64_t modifier,
+                const gfx::Size& size,
+                std::vector<gfx::NativePixmapPlane> planes,
+                std::vector<uint32_t> handles)
+      : format_(format),
+        format_modifier_(modifier),
+        flags_(flags),
+        size_(size),
+        planes_(std::move(planes)),
+        handles_(std::move(handles)) {}
+
+  ~MockGbmBuffer() override {}
+
+  uint32_t GetFormat() const override { return format_; }
+  uint64_t GetFormatModifier() const override { return format_modifier_; }
+  uint32_t GetFlags() const override { return flags_; }
+  size_t GetFdCount() const override { return 0; }
+  gfx::Size GetSize() const override { return size_; }
+  gfx::BufferFormat GetBufferFormat() const override {
+    return ui::GetBufferFormatFromFourCCFormat(format_);
+  }
+  bool AreFdsValid() const override { return false; }
+  size_t GetNumPlanes() const override { return planes_.size(); }
+  int GetPlaneFd(size_t plane) const override {
+    NOTREACHED();
+    return -1;
+  }
+  int GetPlaneStride(size_t plane) const override {
+    DCHECK_LT(plane, planes_.size());
+    return planes_[plane].stride;
+  }
+  int GetPlaneOffset(size_t plane) const override {
+    DCHECK_LT(plane, planes_.size());
+    return planes_[plane].offset;
+  }
+  size_t GetPlaneSize(size_t plane) const override {
+    DCHECK_LT(plane, planes_.size());
+    return planes_[plane].size;
+  }
+  uint32_t GetPlaneHandle(size_t plane) const override {
+    DCHECK_LT(plane, planes_.size());
+    return handles_[plane];
+  }
+  uint32_t GetHandle() const override { return GetPlaneHandle(0); }
+  gfx::NativePixmapHandle ExportHandle() const override {
+    NOTIMPLEMENTED();
+    return gfx::NativePixmapHandle();
+  }
+
+ private:
+  uint32_t format_ = 0;
+  uint64_t format_modifier_ = 0;
+  uint32_t flags_ = 0;
+  std::vector<base::ScopedFD> fds_;
+  gfx::Size size_;
+  std::vector<gfx::NativePixmapPlane> planes_;
+  std::vector<uint32_t> handles_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockGbmBuffer);
+};
+
+}  // namespace
+
+MockGbmDevice::MockGbmDevice() {}
+
+MockGbmDevice::~MockGbmDevice() {}
+
+void MockGbmDevice::set_allocation_failure(bool should_fail_allocations) {
+  should_fail_allocations_ = should_fail_allocations;
+}
+
+std::unique_ptr<GbmBuffer> MockGbmDevice::CreateBuffer(uint32_t format,
+                                                       const gfx::Size& size,
+                                                       uint32_t flags) {
+  if (should_fail_allocations_)
+    return nullptr;
+
+  return CreateBufferWithModifiers(format, size, flags, {});
+}
+
+std::unique_ptr<GbmBuffer> MockGbmDevice::CreateBufferWithModifiers(
+    uint32_t format,
+    const gfx::Size& size,
+    uint32_t flags,
+    const std::vector<uint64_t>& modifiers) {
+  uint32_t bytes_per_pixel;
+  switch (format) {
+    case DRM_FORMAT_XRGB8888:
+    case DRM_FORMAT_ARGB8888:
+      bytes_per_pixel = 4;
+      break;
+    case DRM_FORMAT_UYVY:
+      bytes_per_pixel = 2;
+      break;
+    default:
+      NOTREACHED() << "Unsupported format: " << format;
+      return nullptr;
+  }
+
+  if (modifiers.size() > 1)
+    return nullptr;
+
+  uint64_t format_modifier =
+      modifiers.size() ? modifiers[0] : DRM_FORMAT_MOD_NONE;
+  switch (format_modifier) {
+    case DRM_FORMAT_MOD_NONE:
+    case I915_FORMAT_MOD_X_TILED:
+      break;
+    default:
+      NOTREACHED() << "Unsupported format modifier: " << format_modifier;
+      return nullptr;
+  }
+
+  uint32_t width = base::checked_cast<uint32_t>(size.width());
+  uint32_t height = base::checked_cast<uint32_t>(size.height());
+  uint32_t plane_stride = base::CheckMul(bytes_per_pixel, width).ValueOrDie();
+  uint32_t plane_size = base::CheckMul(plane_stride, height).ValueOrDie();
+  uint32_t plane_offset = 0;
+
+  std::vector<gfx::NativePixmapPlane> planes;
+  planes.push_back(gfx::NativePixmapPlane(plane_stride, plane_offset,
+                                          plane_size, format_modifier));
+  std::vector<uint32_t> handles;
+  handles.push_back(next_handle_++);
+
+  return std::make_unique<MockGbmBuffer>(format, flags, format_modifier, size,
+                                         std::move(planes), std::move(handles));
+}
+
+std::unique_ptr<GbmBuffer> MockGbmDevice::CreateBufferFromFds(
+    uint32_t format,
+    const gfx::Size& size,
+    std::vector<base::ScopedFD> fds,
+    const std::vector<gfx::NativePixmapPlane>& planes) {
+  NOTREACHED();
+  return nullptr;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/mock_gbm_device.h b/ui/ozone/platform/drm/gpu/mock_gbm_device.h
new file mode 100644
index 0000000..b07c63e51
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/mock_gbm_device.h
@@ -0,0 +1,44 @@
+// 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 UI_OZONE_PLATFORM_DRM_GPU_MOCK_GBM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_GBM_DEVICE_H_
+
+#include "ui/ozone/common/linux/gbm_device.h"
+
+namespace ui {
+
+// The real DrmDevice makes actual DRM calls which we can't use in unit tests.
+class MockGbmDevice : public GbmDevice {
+ public:
+  MockGbmDevice();
+  ~MockGbmDevice() override;
+
+  void set_allocation_failure(bool should_fail_allocations);
+
+  // GbmDevice:
+  std::unique_ptr<GbmBuffer> CreateBuffer(uint32_t format,
+                                          const gfx::Size& size,
+                                          uint32_t flags) override;
+  std::unique_ptr<GbmBuffer> CreateBufferWithModifiers(
+      uint32_t format,
+      const gfx::Size& size,
+      uint32_t flags,
+      const std::vector<uint64_t>& modifiers) override;
+  std::unique_ptr<GbmBuffer> CreateBufferFromFds(
+      uint32_t format,
+      const gfx::Size& size,
+      std::vector<base::ScopedFD> fds,
+      const std::vector<gfx::NativePixmapPlane>& planes) override;
+
+ private:
+  uint32_t next_handle_ = 0;
+  bool should_fail_allocations_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(MockGbmDevice);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_GPU_MOCK_GBM_DEVICE_H_
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc
index 3cd0ad0..a228fda 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -15,12 +15,12 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_fence.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
 #include "ui/ozone/platform/drm/gpu/drm_console_buffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_device.h"
 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
-#include "ui/ozone/platform/drm/gpu/drm_framebuffer_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 
@@ -96,8 +96,7 @@
 
 }  // namespace
 
-ScreenManager::ScreenManager(DrmFramebufferGenerator* buffer_generator)
-    : buffer_generator_(buffer_generator) {}
+ScreenManager::ScreenManager() {}
 
 ScreenManager::~ScreenManager() {
   DCHECK(window_map_.empty());
@@ -387,8 +386,11 @@
   }
 
   scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
-  scoped_refptr<DrmFramebuffer> buffer =
-      buffer_generator_->Create(drm, fourcc_format, modifiers, bounds.size());
+  std::unique_ptr<GbmBuffer> buffer =
+      drm->gbm_device()->CreateBufferWithModifiers(
+          fourcc_format, bounds.size(), GBM_BO_USE_SCANOUT, modifiers);
+  scoped_refptr<DrmFramebuffer> framebuffer =
+      DrmFramebuffer::AddFramebuffer(drm, buffer.get());
   if (!buffer) {
     LOG(ERROR) << "Failed to create scanout buffer";
     return DrmOverlayPlane(nullptr, 0, gfx::OVERLAY_TRANSFORM_INVALID,
@@ -396,8 +398,8 @@
                            /* gpu_fence */ nullptr);
   }
 
-  FillModesetBuffer(drm, controller, buffer.get());
-  return DrmOverlayPlane(buffer, nullptr);
+  FillModesetBuffer(drm, controller, framebuffer.get());
+  return DrmOverlayPlane(framebuffer, nullptr);
 }
 
 bool ScreenManager::EnableController(HardwareDisplayController* controller) {
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h
index c21dbde..e5c2760d 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.h
+++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -25,12 +25,11 @@
 
 class DrmDevice;
 class DrmWindow;
-class DrmFramebufferGenerator;
 
 // Responsible for keeping track of active displays and configuring them.
 class ScreenManager {
  public:
-  ScreenManager(DrmFramebufferGenerator* surface_generator);
+  ScreenManager();
   virtual ~ScreenManager();
 
   // Register a display controller. This must be called before trying to
@@ -131,7 +130,6 @@
 
   DrmWindow* FindWindowAt(const gfx::Rect& bounds) const;
 
-  DrmFramebufferGenerator* buffer_generator_;  // Not owned.
   // List of display controllers (active and disabled).
   HardwareDisplayControllers controllers_;
 
diff --git a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index d88806e..1d05b1d9 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/gpu_fence.h"
+#include "ui/ozone/common/linux/gbm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
@@ -19,7 +20,7 @@
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
-#include "ui/ozone/platform/drm/gpu/mock_drm_framebuffer_generator.h"
+#include "ui/ozone/platform/drm/gpu/mock_gbm_device.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 
 namespace ui {
@@ -56,20 +57,36 @@
   }
 
   void SetUp() override {
-    drm_ = new ui::MockDrmDevice;
+    auto gbm = std::make_unique<ui::MockGbmDevice>();
+    drm_ = new ui::MockDrmDevice(std::move(gbm));
     device_manager_.reset(new ui::DrmDeviceManager(nullptr));
-    buffer_generator_.reset(new ui::MockDrmFramebufferGenerator());
-    screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
+    screen_manager_.reset(new ui::ScreenManager());
   }
   void TearDown() override {
     screen_manager_.reset();
     drm_ = nullptr;
   }
 
+  scoped_refptr<DrmFramebuffer> CreateBuffer(uint32_t format,
+                                             const gfx::Size& size) {
+    return CreateBufferWithModifier(format, DRM_FORMAT_MOD_NONE, size);
+  }
+
+  scoped_refptr<DrmFramebuffer> CreateBufferWithModifier(
+      uint32_t format,
+      uint64_t format_modifier,
+      const gfx::Size& size) {
+    std::vector<uint64_t> modifiers;
+    if (format_modifier != DRM_FORMAT_MOD_NONE)
+      modifiers.push_back(format_modifier);
+    auto buffer = drm_->gbm_device()->CreateBufferWithModifiers(
+        format, size, GBM_BO_USE_SCANOUT, modifiers);
+    return DrmFramebuffer::AddFramebuffer(drm_, buffer.get());
+  }
+
  protected:
   scoped_refptr<ui::MockDrmDevice> drm_;
   std::unique_ptr<ui::DrmDeviceManager> device_manager_;
-  std::unique_ptr<ui::MockDrmFramebufferGenerator> buffer_generator_;
   std::unique_ptr<ui::ScreenManager> screen_manager_;
 
  private:
@@ -360,7 +377,9 @@
 
 TEST_F(ScreenManagerTest,
        CheckProperConfigurationWithDifferentDeviceAndSameCrtc) {
-  scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice;
+  auto gbm_device = std::make_unique<ui::MockGbmDevice>();
+  scoped_refptr<ui::MockDrmDevice> drm2 =
+      new ui::MockDrmDevice(std::move(gbm_device));
 
   screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
@@ -385,7 +404,7 @@
 TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
   std::unique_ptr<ui::DrmWindow> window(
       new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(GetPrimaryBounds());
   screen_manager_->AddWindow(1, std::move(window));
 
@@ -403,7 +422,7 @@
 TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
   std::unique_ptr<ui::DrmWindow> window(
       new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   gfx::Rect new_bounds = GetPrimaryBounds();
   new_bounds.Inset(0, 0, 1, 1);
   window->SetBounds(new_bounds);
@@ -426,7 +445,7 @@
   for (size_t i = 1; i < kWindowCount + 1; ++i) {
     std::unique_ptr<ui::DrmWindow> window(
         new ui::DrmWindow(i, device_manager_.get(), screen_manager_.get()));
-    window->Initialize(buffer_generator_.get());
+    window->Initialize();
     window->SetBounds(GetPrimaryBounds());
     screen_manager_->AddWindow(i, std::move(window));
   }
@@ -451,7 +470,7 @@
   gfx::AcceleratedWidget window_id = 1;
   std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
       window_id, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(GetPrimaryBounds());
   screen_manager_->AddWindow(window_id, std::move(window));
 
@@ -473,7 +492,7 @@
 TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasNoBuffer) {
   std::unique_ptr<ui::DrmWindow> window(
       new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(GetPrimaryBounds());
   screen_manager_->AddWindow(1, std::move(window));
 
@@ -502,11 +521,10 @@
 TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
   std::unique_ptr<ui::DrmWindow> window(
       new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(GetPrimaryBounds());
-
-  scoped_refptr<ui::DrmFramebuffer> buffer = buffer_generator_->Create(
-      drm_, DRM_FORMAT_XRGB8888, {}, GetPrimaryBounds().size());
+  scoped_refptr<DrmFramebuffer> buffer =
+      CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
   ui::DrmOverlayPlaneList planes;
   planes.push_back(ui::DrmOverlayPlane(buffer, nullptr));
   window->SchedulePageFlip(std::move(planes), base::DoNothing(),
@@ -528,13 +546,10 @@
 TEST_F(ScreenManagerTest, DISABLED_RejectBufferWithIncompatibleModifiers) {
   std::unique_ptr<ui::DrmWindow> window(
       new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get()));
-  window->Initialize(buffer_generator_.get());
+  window->Initialize();
   window->SetBounds(GetPrimaryBounds());
-  scoped_refptr<ui::DrmFramebuffer> buffer =
-      buffer_generator_->CreateWithModifier(drm_, DRM_FORMAT_XRGB8888,
-                                            I915_FORMAT_MOD_X_TILED,
-                                            GetPrimaryBounds().size());
-
+  auto buffer = CreateBufferWithModifier(
+      DRM_FORMAT_XRGB8888, I915_FORMAT_MOD_X_TILED, GetPrimaryBounds().size());
   ui::DrmOverlayPlaneList planes;
   planes.push_back(ui::DrmOverlayPlane(buffer, nullptr));
   window->SchedulePageFlip(std::move(planes), base::DoNothing(),
@@ -558,11 +573,14 @@
 }
 
 TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
-  auto drm_device1 = base::MakeRefCounted<MockDrmDevice>();
-  auto drm_device2 = base::MakeRefCounted<MockDrmDevice>();
+  auto gbm_device1 = std::make_unique<MockGbmDevice>();
+  auto drm_device1 =
+      base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device1));
+  auto gbm_device2 = std::make_unique<MockGbmDevice>();
+  auto drm_device2 =
+      base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device2));
   DrmDeviceManager drm_device_manager(nullptr);
-  MockDrmFramebufferGenerator buffer_generator;
-  ScreenManager screen_manager(&buffer_generator);
+  ScreenManager screen_manager;
 
   constexpr uint32_t kCrtc19 = 19;
   constexpr uint32_t kConnector28 = 28;
@@ -581,7 +599,7 @@
   {
     auto window1 =
         std::make_unique<DrmWindow>(1, &drm_device_manager, &screen_manager);
-    window1->Initialize(&buffer_generator);
+    window1->Initialize();
     screen_manager.AddWindow(1, std::move(window1));
     screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
     screen_manager.AddDisplayController(drm_device1, kCrtc19, kConnector28);
@@ -593,7 +611,7 @@
                                               Mode(1920, 1080));
     auto window2 =
         std::make_unique<DrmWindow>(2, &drm_device_manager, &screen_manager);
-    window2->Initialize(&buffer_generator);
+    window2->Initialize();
     screen_manager.AddWindow(2, std::move(window2));
     screen_manager.GetWindow(2)->SetBounds(gfx::Rect(0, 1140, 1920, 1080));
   }
@@ -639,7 +657,7 @@
                                               Mode(1920, 1080));
     auto window3 =
         std::make_unique<DrmWindow>(3, &drm_device_manager, &screen_manager);
-    window3->Initialize(&buffer_generator);
+    window3->Initialize();
     screen_manager.AddWindow(3, std::move(window3));
     screen_manager.GetWindow(3)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
     screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 1140, 1920, 1080));
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 8a702690..09711e4 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -111,6 +111,10 @@
 }
 
 TEST_F(ViewAXPlatformNodeDelegateTest, LabelIsChildOfButton) {
+  // Disable focus rings for this test: they introduce extra children that can
+  // be either before or after the label, which complicates correctness testing.
+  button_->SetInstallFocusRingOnFocus(false);
+
   // |button_| is focusable, so |label_| (as its child) should be ignored.
   EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, button_->focus_behavior());
   EXPECT_EQ(1, button_accessibility()->GetChildCount());
diff --git a/ui/views/controls/button/button.cc b/ui/views/controls/button/button.cc
index f73a3102..9656e5dc 100644
--- a/ui/views/controls/button/button.cc
+++ b/ui/views/controls/button/button.cc
@@ -476,6 +476,7 @@
   SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
   SetProperty(kIsButtonProperty, true);
   hover_animation_.SetSlideDuration(kHoverFadeDurationMs);
+  SetInstallFocusRingOnFocus(PlatformStyle::kPreferFocusRings);
 }
 
 Button::KeyClickAction Button::GetKeyClickActionForEvent(